From 73e1a7a80301d341864ea75de4124bf98d52a3ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Ron=C4=8Devi=C4=87?= Date: Wed, 6 Nov 2024 10:03:21 +0100 Subject: [PATCH 01/52] Rewrite `TypeEngine` for performance, robustness, and simplicity (#6613) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This PR implements a major rewrite of the `TypeEngine`. The rewrite: - significantly improves overall compilation performance. The compilation time of the real-world [Spark Orderbook workspace](https://github.com/compolabs/orderbook-contract) got **reduced from 8.99 to 5.94 seconds**, and the memory consumption from **3.32 to 1.78 GB**. - provides robust API for inserting types, related to the usage of the `source_id` (see: #5991). The new API forbids not providing `source_id`s or providing semantically questionable or non-optimal ones. - introduces simpler, much less verbose, API for inserting types. The PR also removes the obsolete and unused `TypeInfo::Storage`. The PR **does not address** the following: - The `TypeEngine`'s "garbage-collection-(un)friendlines" (see: #6603). - The handling of the `TypeInfo::Custom` and `TypeInfo::TraitType` types within the `TypeEngine` (see: #6601). - The number of interactions with the `TypeEngine`. E.g., removing unnecessary insertions after `resolve()`ing or `monomorphyze()`ing types will be done as a part of `DeclEngine` optimization. Closes #5991. ## Shareable types The PR formalizes the notion of a _shareable type_ within the `TypeEngine` (strictly speaking, a shareable `TypeInfo`). A shareable type is a type that is both: - _unchangeable_: it, or any of its parts, cannot be replaced during the unification or monomorphization. - and _undistinguishable by annotations_: it doesn't carry any additional information (annotations) that could differ it from another instance of `TypeInfo` that would, purely from the type perspective, be a same type. E.g., `u64` or `MyStruct` are unchangeable while `Numeric`, `Unknown` or `MyStruct` are changeable. E.g., in this example, `a` and `b` have the same type, `[u64; 2]` but those two types differ in spans assigned to the "u64"s and the "2"s, and are treated as different within the `TypeEngine`, and thus as non-shareable. ``` let a: [u64; 2] = [1, 1]; let b: [u64; 2] = [2, 2]; ``` Shareability of a type is crucial for reusing the `TypeSourceInfo` instances within the type engine. Shareable types can be given different `TypeId`s without the need to newly allocate a `TypeSourceInfo`. ## Performance improvements The cummulative effect of the performance improvements on the compilataion of the real-world [Spark Orderbook workspace](https://github.com/compolabs/orderbook-contract) is given below. The compilation means the frontend compilation, up to the IR generation (`forc check`). **Compilation time** ``` Before: Time (mean ± σ): 8.995 s ± 0.297 s [User: 7.126 s, System: 1.289 s] Range (min … max): 8.675 s … 9.262 s 3 runs After: Time (mean ± σ): 5.945 s ± 0.517 s [User: 4.749 s, System: 0.768 s] Range (min … max): 5.349 s … 6.280 s 3 runs ``` **Memory consumption** ``` --------------------------------------------------------- total(B) useful-heap(B) extra-heap(B) --------------------------------------------------------- Before: 3,316,786,808 3,237,317,383 79,469,425 After: 1,784,467,376 1,743,772,406 40,694,970 ``` ### Applied optimizations: - **Replacement of expensive `insert` calls with compile time constants for built-in types.** Built-in types like `!`, `bool`, `()`, `u8`, etc. are inserted into the engine at its creation at predefined slots within the `slab`. The `id_of_` methods just return those predefined `TypeId`s, effectively being compiled down to constants. The calls like `type_engine.insert(engines, TypeInfo::Boolean, None)` are replaced with maximally optimized and non-verbose `type_engine.id_of_bool()`. - **Elimination of extensive creation of `TypeSourceInfo`s for `TypeInfo::Unknown/Numeric`s.** `Unknown` and `Numeric` are inserted into the engine ~50.000 times. Each insert used to create a new instance of `TypeSourceInfo` with the `source_id` set to `None`. The optimization replaces those ~50.000 instances with two predefined singleton instances, one for `Unknown` + `None` and one for `Numeric` + `None`. (Note that when implementing #6603, we will want to bind also `Unknown`s and `Numeric`s to `source_id`s different then `None`, but we will still want to reuse the `TypeInfo` instances.) - **Elimination of extensive temporary heap-allocations during hash calculation.** The custom hasher obtained by `make_hasher` required a `TypeSourceInfo` to calculate the hash and it was called every time the `insert` was called, ~530.000 times. Getting the `TypeSourceInfo` originally required cloning the `TypeInfo`, which depending on the concrete `TypeInfo` instance could cause heap allocations, and also heap-allocating that copy within an `Arc`. Hash was calculated regardless of the possibility for the type to be stored in the hash map of reusable types. The optimization removed the hashing step if the type is not shareable, removed the cloning of the `TypeInfo` and introduced a custom `compute_hash_without_heap_allocation` method that produced the same hash as the `make_hasher` but without unnecessary temporary heap-allocations of `TypeSourceInfo`s. - **Replacement of `TypeSourceInfo`s within the hash map with `Arc`s.** The hash map unnecessarily required making copies of reused `TypeSourceInfo`s. - **Introducing the concept of a _shareable type_ and rolling it out for all types.** Previously, the engine checked only for changeability of types by using the `TypeInfo::is_changeable` method. The implementation of that method was extremely simplified, e.g. treating all structs and enums with generic arguments as changeable even if they were fully monomorphized. This resulted in over-bloating the engine with type instances that were actually unchangeable, but considered to be changeable. Also, strictly seen, the unchangeability (during unification and monomorphization) is not the only necessary criteria for reuse (or sharing) a type within the engine. Another important aspect is, as explained above, the _differentiability by annotations_. The PR introduces the notion of a _shareable type_ which is both unchangeable and not differentiable by annotations. The optimization takes advantage of such types by storing them only once per `source_id`. - **Elimination of extensive unnecessary inserts of new types during `replace()` calls.** When `replace()`ing types during unifications, a new `TypeSourceInfo` instance was created for every replacement, ~46.000 times. This meant a heap-allocation of the `TypeSourceInfo` (16 bytes) and the `Arc`-contained `TypeInfo` (232 bytes), even if the replaced type was shareable and already available in the type engine. The optimization now reuses an already existing shareable type if available. ## Robustness related to `source_id`s The issues we had with properly providing the `source_id` in the `insert` method are explained in #5991. This PR removes the `source_id` from the new public API and calculates it internally within the engine, based on the type being inserted. This makes inserting of types both more robust and less verbose and eliminates the possibility of providing a semantically wrong `source_id`. Note that the calculation of an optimal `source_id` done within the engine fully corresponds to the "calculations" we currently have at call sites. E.g., when inserting enums, previously we always had to write `type_engine.insert(engines, TypeInfo::Enum(decl_id), enum_decl.span.source_id())`. Fetching the `source_id` from the enum declaration is now done within the `insert_enum` method: `type_engine.insert_enum(engines, decl_id)`. Note that for certain types we will want to change the current behavior and either provide a `source_id` or pick a more suitable one. E.g, even when inserting `Unknown`s, we will want to have `source_id`s, if possible. This will be done in #6603, but again, together with providing a robust API that will be difficult to misuse. ## Simplicity As already mentioned in some of the examples above, the new `id_of_()` and `insert_` methods provide much simpler and less verbose API to use. Introducing those methods remove a lot of boilerplate code from the callers. Also, the individual `insert_` methods are additionally optimized for inserting the particular type. The common `insert` method is intended to be used only in cases where the inserted `TypeInfo` is not known at the call site. Here are some examples of the new API versus the existing one: |Before|After| |------|-----| | `type_engine.insert(engines, TypeInfo::Tuple(vec![]), None)` | `type_engine.id_of_unit()` | | `type_engine.insert(engines, TypeInfo::Unknown, None)` | `type_engine.new_unknown()` | | `type_engine.insert(engines, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), None)` | `type_engine.id_of_u64()` | For more complex types, like, e.g., `TypeInfo::Tuple`, the difference in inserting is even more prominent, as can be seen from the diffs of numerous code lines deleted in this PR. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] 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. --------- Co-authored-by: Joshua Batty Co-authored-by: João Matos --- Cargo.lock | 1 + Cargo.toml | 2 +- sway-core/Cargo.toml | 1 + sway-core/src/abi_generation/abi_str.rs | 1 - sway-core/src/abi_generation/evm_abi.rs | 1 - sway-core/src/concurrent_slab.rs | 7 + sway-core/src/engine_threading.rs | 11 +- sway-core/src/ir_generation/const_eval.rs | 2 +- sway-core/src/ir_generation/convert.rs | 1 - .../language/parsed/declaration/impl_trait.rs | 2 +- sway-core/src/language/ty/declaration/abi.rs | 9 +- .../language/ty/declaration/declaration.rs | 26 +- .../src/language/ty/declaration/storage.rs | 23 +- .../src/language/ty/declaration/type_alias.rs | 12 +- .../src/language/ty/expression/expression.rs | 2 +- .../semantic_analysis/ast_node/code_block.rs | 16 +- .../ast_node/declaration/abi.rs | 2 + .../ast_node/declaration/auto_impl.rs | 11 +- .../ast_node/declaration/configurable.rs | 23 +- .../ast_node/declaration/constant.rs | 4 +- .../ast_node/declaration/declaration.rs | 14 +- .../ast_node/declaration/enum.rs | 3 +- .../ast_node/declaration/function.rs | 27 +- .../function/function_parameter.rs | 6 +- .../ast_node/declaration/impl_trait.rs | 63 +- .../ast_node/declaration/struct.rs | 4 +- .../ast_node/declaration/trait.rs | 4 +- .../ast_node/declaration/trait_fn.rs | 5 +- .../ast_node/declaration/trait_type.rs | 13 +- .../ast_node/declaration/variable.rs | 2 +- .../ast_node/expression/intrinsic_function.rs | 345 +-- .../match_expression/typed/instantiate.rs | 18 +- .../match_expression/typed/matcher.rs | 16 +- .../typed/typed_match_branch.rs | 18 +- .../typed/typed_match_expression.rs | 46 +- .../match_expression/typed/typed_scrutinee.rs | 65 +- .../ast_node/expression/typed_expression.rs | 220 +- .../typed_expression/enum_instantiation.rs | 12 +- .../typed_expression/if_expression.rs | 9 +- .../typed_expression/method_application.rs | 68 +- .../typed_expression/struct_instantiation.rs | 26 +- .../src/semantic_analysis/ast_node/mod.rs | 6 +- .../semantic_analysis/namespace/trait_map.rs | 35 +- .../semantic_analysis/node_dependencies.rs | 1 - .../semantic_analysis/type_check_context.rs | 10 +- .../src/semantic_analysis/type_resolve.rs | 51 +- .../to_parsed_lang/convert_parse_tree.rs | 135 +- .../src/type_system/ast_elements/binding.rs | 20 +- .../src/type_system/ast_elements/length.rs | 34 +- .../ast_elements/trait_constraint.rs | 6 +- .../type_system/ast_elements/type_argument.rs | 47 +- .../ast_elements/type_parameter.rs | 176 +- sway-core/src/type_system/engine.rs | 1916 ++++++++++++++++- sway-core/src/type_system/id.rs | 33 +- sway-core/src/type_system/info.rs | 149 +- sway-core/src/type_system/mod.rs | 72 +- sway-core/src/type_system/monomorphization.rs | 35 +- sway-core/src/type_system/priv_prelude.rs | 2 +- .../src/type_system/substitute/subst_map.rs | 126 +- sway-core/src/type_system/unify/unifier.rs | 20 +- .../src/type_system/unify/unify_check.rs | 1 - sway-lsp/README.md | 10 + .../code_actions/common/generate_impl.rs | 2 +- sway-lsp/src/server_state.rs | 17 +- sway-lsp/src/traverse/parsed_tree.rs | 2 +- sway-lsp/src/traverse/typed_tree.rs | 27 +- sway-lsp/tests/lib.rs | 239 +- sway-lsp/tests/utils/src/lib.rs | 12 + sway-types/src/lib.rs | 31 +- sway-types/src/source_engine.rs | 2 +- .../abi_cast_nested_method/src/main.sw | 4 +- .../language/match_expressions_or/test.toml | 2 +- 72 files changed, 2768 insertions(+), 1596 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 95a6bab5a68..07c201f8f60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7611,6 +7611,7 @@ dependencies = [ "lazy_static", "object", "parking_lot 0.12.3", + "paste", "pest", "pest_derive", "petgraph", diff --git a/Cargo.toml b/Cargo.toml index 340bc9d0581..cc4f22bd5c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -165,7 +165,7 @@ libtest-mimic = "0.7" lsp-types = "0.94" mdbook = { version = "0.4", default-features = false } minifier = "0.3" -normalize-path = "0.2.1" +normalize-path = "0.2" notify = "6.1" notify-debouncer-mini = "0.4" num-bigint = "0.4" diff --git a/sway-core/Cargo.toml b/sway-core/Cargo.toml index 3a351390cbb..5e2e5d54536 100644 --- a/sway-core/Cargo.toml +++ b/sway-core/Cargo.toml @@ -28,6 +28,7 @@ itertools.workspace = true lazy_static.workspace = true object = { workspace = true, features = ["write"] } parking_lot.workspace = true +paste.workspace = true pest.workspace = true pest_derive.workspace = true petgraph.workspace = true diff --git a/sway-core/src/abi_generation/abi_str.rs b/sway-core/src/abi_generation/abi_str.rs index 254b8a805ad..5794906d7c9 100644 --- a/sway-core/src/abi_generation/abi_str.rs +++ b/sway-core/src/abi_generation/abi_str.rs @@ -179,7 +179,6 @@ impl TypeInfo { length.val() ) } - Storage { .. } => "contract storage".into(), RawUntypedPtr => "raw untyped ptr".into(), RawUntypedSlice => "raw untyped slice".into(), Ptr(ty) => { diff --git a/sway-core/src/abi_generation/evm_abi.rs b/sway-core/src/abi_generation/evm_abi.rs index f723f36d14a..147fa387a6f 100644 --- a/sway-core/src/abi_generation/evm_abi.rs +++ b/sway-core/src/abi_generation/evm_abi.rs @@ -115,7 +115,6 @@ pub fn abi_str(type_info: &TypeInfo, engines: &Engines) -> String { Array(elem_ty, length) => { format!("{}[{}]", abi_str_type_arg(elem_ty, engines), length.val()) } - Storage { .. } => "contract storage".into(), RawUntypedPtr => "raw untyped ptr".into(), RawUntypedSlice => "raw untyped slice".into(), Ptr(ty) => { diff --git a/sway-core/src/concurrent_slab.rs b/sway-core/src/concurrent_slab.rs index 77aef759e9d..8c3d1eacf2c 100644 --- a/sway-core/src/concurrent_slab.rs +++ b/sway-core/src/concurrent_slab.rs @@ -100,6 +100,13 @@ where Arc::into_inner(old) } + pub fn replace_arc(&self, index: usize, new_value: Arc) -> Option { + let mut inner = self.inner.write(); + let item = inner.items.get_mut(index)?; + let old = item.replace(new_value)?; + Arc::into_inner(old) + } + pub fn get(&self, index: usize) -> Arc { let inner = self.inner.read(); inner.items[index] diff --git a/sway-core/src/engine_threading.rs b/sway-core/src/engine_threading.rs index 2af209c807f..c5e48557e72 100644 --- a/sway-core/src/engine_threading.rs +++ b/sway-core/src/engine_threading.rs @@ -7,6 +7,7 @@ use std::{ cmp::Ordering, fmt, hash::{BuildHasher, Hash, Hasher}, + sync::Arc, }; use sway_types::{SourceEngine, Span}; @@ -40,7 +41,7 @@ impl Engines { &self.source_engine } - /// Removes all data associated with `program_id` from the declaration and type engines. + /// Removes all data associated with `program_id` from the engines. /// It is intended to be used during garbage collection to remove any data that is no longer needed. pub fn clear_program(&mut self, program_id: &sway_types::ProgramId) { self.type_engine.clear_program(program_id); @@ -49,7 +50,7 @@ impl Engines { self.query_engine.clear_program(program_id); } - /// Removes all data associated with `source_id` from the declaration and type engines. + /// Removes all data associated with `source_id` from the engines. /// It is intended to be used during garbage collection to remove any data that is no longer needed. pub fn clear_module(&mut self, source_id: &sway_types::SourceId) { self.type_engine.clear_module(source_id); @@ -258,6 +259,12 @@ impl HashWithEngines for Box { } } +impl HashWithEngines for Arc { + fn hash(&self, state: &mut H, engines: &Engines) { + (**self).hash(state, engines) + } +} + pub trait EqWithEngines: PartialEqWithEngines {} pub struct PartialEqWithEnginesContext<'a> { diff --git a/sway-core/src/ir_generation/const_eval.rs b/sway-core/src/ir_generation/const_eval.rs index ad2d5a307ff..258d63cb6d2 100644 --- a/sway-core/src/ir_generation/const_eval.rs +++ b/sway-core/src/ir_generation/const_eval.rs @@ -221,7 +221,7 @@ pub(crate) fn compile_constant_expression_to_constant( // definition, rather than the actual call site. ty::TyExpressionVariant::FunctionApplication { call_path, .. } => { let span = call_path.span(); - let span = if span == Span::dummy() { + let span = if span.is_dummy() { const_expr.span.clone() } else { span diff --git a/sway-core/src/ir_generation/convert.rs b/sway-core/src/ir_generation/convert.rs index 4d0ee1d20c7..f95217fb2b4 100644 --- a/sway-core/src/ir_generation/convert.rs +++ b/sway-core/src/ir_generation/convert.rs @@ -184,7 +184,6 @@ fn convert_resolved_type_info( TypeInfo::Placeholder(_) => reject_type!("Placeholder"), TypeInfo::TypeParam(_) => reject_type!("TypeParam"), TypeInfo::ErrorRecovery(_) => reject_type!("Error recovery"), - TypeInfo::Storage { .. } => reject_type!("Storage"), TypeInfo::TraitType { .. } => reject_type!("TraitType"), }) } diff --git a/sway-core/src/language/parsed/declaration/impl_trait.rs b/sway-core/src/language/parsed/declaration/impl_trait.rs index 48ba779155e..ed0ee15bf35 100644 --- a/sway-core/src/language/parsed/declaration/impl_trait.rs +++ b/sway-core/src/language/parsed/declaration/impl_trait.rs @@ -72,7 +72,7 @@ pub struct ImplSelfOrTrait { pub trait_decl_ref: Option, pub implementing_for: TypeArgument, pub items: Vec, - // the span of the whole impl trait and block + /// The [Span] of the whole impl trait and block. pub(crate) block_span: Span, } diff --git a/sway-core/src/language/ty/declaration/abi.rs b/sway-core/src/language/ty/declaration/abi.rs index 5ad5ea2c3dc..7dae1ef3271 100644 --- a/sway-core/src/language/ty/declaration/abi.rs +++ b/sway-core/src/language/ty/declaration/abi.rs @@ -76,12 +76,9 @@ impl HashWithEngines for TyAbiDecl { impl CreateTypeId for TyAbiDecl { fn create_type_id(&self, engines: &Engines) -> TypeId { - let type_engine = engines.te(); - let ty = TypeInfo::ContractCaller { - abi_name: AbiName::Known(self.name.clone().into()), - address: None, - }; - type_engine.insert(engines, ty, self.name.span().source_id()) + engines + .te() + .new_contract_caller(engines, AbiName::Known(self.name.clone().into()), None) } } diff --git a/sway-core/src/language/ty/declaration/declaration.rs b/sway-core/src/language/ty/declaration/declaration.rs index 9bd68ec0046..3c5b6481d09 100644 --- a/sway-core/src/language/ty/declaration/declaration.rs +++ b/sway-core/src/language/ty/declaration/declaration.rs @@ -740,31 +740,9 @@ impl TyDecl { decl.return_type.type_id } TyDecl::StructDecl(StructDecl { decl_id }) => { - let decl = decl_engine.get_struct(decl_id); - type_engine.insert( - engines, - TypeInfo::Struct(*decl_id), - decl.name().span().source_id(), - ) - } - TyDecl::EnumDecl(EnumDecl { decl_id }) => { - let decl = decl_engine.get_enum(decl_id); - type_engine.insert( - engines, - TypeInfo::Enum(*decl_id), - decl.name().span().source_id(), - ) - } - TyDecl::StorageDecl(StorageDecl { decl_id, .. }) => { - let storage_decl = decl_engine.get_storage(decl_id); - type_engine.insert( - engines, - TypeInfo::Storage { - fields: storage_decl.fields_as_typed_struct_fields(), - }, - storage_decl.span().source_id(), - ) + type_engine.insert_struct(engines, *decl_id) } + TyDecl::EnumDecl(EnumDecl { decl_id }) => type_engine.insert_enum(engines, *decl_id), TyDecl::TypeAliasDecl(TypeAliasDecl { decl_id, .. }) => { let decl = decl_engine.get_type_alias(decl_id); decl.create_type_id(engines) diff --git a/sway-core/src/language/ty/declaration/storage.rs b/sway-core/src/language/ty/declaration/storage.rs index 767d5728ee7..23e4b7a09ba 100644 --- a/sway-core/src/language/ty/declaration/storage.rs +++ b/sway-core/src/language/ty/declaration/storage.rs @@ -8,7 +8,7 @@ use sway_types::{Ident, Named, Span, Spanned}; use crate::{ engine_threading::*, - language::{parsed::StorageDeclaration, ty::*, Visibility}, + language::{parsed::StorageDeclaration, ty::*}, transform::{self}, type_system::*, Namespace, @@ -233,27 +233,6 @@ impl TyStorageDecl { return_type, )) } - - pub(crate) fn fields_as_typed_struct_fields(&self) -> Vec { - self.fields - .iter() - .map( - |TyStorageField { - ref name, - ref type_argument, - ref span, - ref attributes, - .. - }| TyStructField { - visibility: Visibility::Public, - name: name.clone(), - span: span.clone(), - type_argument: type_argument.clone(), - attributes: attributes.clone(), - }, - ) - .collect() - } } impl Spanned for TyStorageField { diff --git a/sway-core/src/language/ty/declaration/type_alias.rs b/sway-core/src/language/ty/declaration/type_alias.rs index e2e5844de3f..cb33c0d27bd 100644 --- a/sway-core/src/language/ty/declaration/type_alias.rs +++ b/sway-core/src/language/ty/declaration/type_alias.rs @@ -64,15 +64,9 @@ impl SubstTypes for TyTypeAliasDecl { impl CreateTypeId for TyTypeAliasDecl { fn create_type_id(&self, engines: &Engines) -> TypeId { - let type_engine = engines.te(); - type_engine.insert( - engines, - TypeInfo::Alias { - name: self.name.clone(), - ty: self.ty.clone(), - }, - self.name.span().source_id(), - ) + engines + .te() + .new_alias(engines, self.name.clone(), self.ty.clone()) } } diff --git a/sway-core/src/language/ty/expression/expression.rs b/sway-core/src/language/ty/expression/expression.rs index 15f57369007..a0c70559b1d 100644 --- a/sway-core/src/language/ty/expression/expression.rs +++ b/sway-core/src/language/ty/expression/expression.rs @@ -369,7 +369,7 @@ impl TyExpression { let type_engine = engines.te(); TyExpression { expression: TyExpressionVariant::Tuple { fields: vec![] }, - return_type: type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None), + return_type: type_engine.id_of_error_recovery(err), span, } } diff --git a/sway-core/src/semantic_analysis/ast_node/code_block.rs b/sway-core/src/semantic_analysis/ast_node/code_block.rs index 330b8e4e4e9..c82523f9395 100644 --- a/sway-core/src/semantic_analysis/ast_node/code_block.rs +++ b/sway-core/src/semantic_analysis/ast_node/code_block.rs @@ -91,8 +91,6 @@ impl ty::TyCodeBlock { ctx: &TypeCheckContext, code_block: &TyCodeBlock, ) -> (TypeId, Span) { - let engines = ctx.engines(); - let implicit_return_span = code_block .contents .iter() @@ -122,12 +120,8 @@ impl ty::TyCodeBlock { .. }), .. - } => Some( - ctx.engines - .te() - .insert(engines, TypeInfo::Never, span.source_id()), - ), - // find the implicit return, if any, and use it as the code block's return type. + } => Some(ctx.engines.te().id_of_never()), + // Find the implicit return, if any, and use it as the code block's return type. // The fact that there is at most one implicit return is an invariant held by the parser. ty::TyAstNode { content: @@ -153,11 +147,7 @@ impl ty::TyCodeBlock { _ => None, } }) - .unwrap_or_else(|| { - ctx.engines - .te() - .insert(engines, TypeInfo::Tuple(Vec::new()), span.source_id()) - }); + .unwrap_or_else(|| ctx.engines.te().id_of_unit()); (block_type, span) } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs index bb0bc9e2fb8..0274195845b 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs @@ -79,6 +79,8 @@ impl ty::TyAbiDecl { // so we don't support the case of calling a contract's own interface // from itself. This is by design. + // The span of the `abi_decl` `name` points to the file (use site) in which + // the ABI is getting declared, so we can use it as the `use_site_span`. let self_type_param = TypeParameter::new_self_type(ctx.engines, name.span()); let self_type_id = self_type_param.type_id; diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs index 55ef6a25e79..98def2c187f 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs @@ -75,11 +75,8 @@ where } else { format!( "<{}>", - itertools::intersperse( - type_parameters.iter().map(|x| { x.name_ident.as_str() }), - ", " - ) - .collect::() + itertools::intersperse(type_parameters.iter().map(|x| { x.name.as_str() }), ", ") + .collect::() ) } } @@ -94,7 +91,7 @@ where for t in type_parameters.iter() { code.push_str(&format!( "{}: {},\n", - t.name_ident.as_str(), + t.name.as_str(), itertools::intersperse( [extra_constraint].into_iter().chain( t.trait_constraints @@ -502,7 +499,7 @@ where fn generate_type(engines: &Engines, type_id: TypeId) -> Option { let name = match &*engines.te().get(type_id) { TypeInfo::UnknownGeneric { name, .. } => name.to_string(), - TypeInfo::Placeholder(type_param) => type_param.name_ident.to_string(), + TypeInfo::Placeholder(type_param) => type_param.name.to_string(), TypeInfo::StringSlice => "str".into(), TypeInfo::StringArray(x) => format!("str[{}]", x.val()), TypeInfo::UnsignedInteger(x) => match x { 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 6c9f5e7f404..7fefd0c1636 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs @@ -19,7 +19,6 @@ use crate::{ }, semantic_analysis::*, EnforceTypeArguments, Engines, SubstTypes, TypeArgument, TypeBinding, TypeCheckTypeBinding, - TypeInfo, }; impl ty::TyConfigurableDecl { @@ -68,7 +67,7 @@ impl ty::TyConfigurableDecl { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // this subst is required to replace associated types, namely TypeInfo::TraitType. type_ascription.type_id.subst(&ctx.subst_ctx()); @@ -84,7 +83,7 @@ impl ty::TyConfigurableDecl { let (value, decode_fn) = if ctx.experimental.new_encoding { let mut ctx = ctx .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::RawUntypedSlice, None)) + .with_type_annotation(type_engine.id_of_raw_slice()) .with_help_text("Configurables must evaluate to slices."); let value = value.map(|value| { @@ -93,21 +92,9 @@ impl ty::TyConfigurableDecl { }); let mut arguments = VecDeque::default(); - arguments.push_back( - engines - .te() - .insert(engines, TypeInfo::RawUntypedSlice, None), - ); - arguments.push_back(engines.te().insert( - engines, - TypeInfo::UnsignedInteger(sway_types::integer_bits::IntegerBits::SixtyFour), - None, - )); - arguments.push_back( - engines - .te() - .insert(engines, TypeInfo::RawUntypedSlice, None), - ); + arguments.push_back(engines.te().id_of_raw_slice()); + arguments.push_back(engines.te().id_of_u64()); + arguments.push_back(engines.te().id_of_raw_slice()); let value_span = value .as_ref() diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs b/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs index e5cca67ecde..6a0c788d2a8 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs @@ -61,7 +61,7 @@ impl ty::TyConstantDecl { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // this subst is required to replace associated types, namely TypeInfo::TraitType. type_ascription.type_id.subst(&ctx.subst_ctx()); @@ -129,7 +129,7 @@ impl ty::TyConstantDecl { call_path, span, attributes: Default::default(), - return_type: type_engine.insert(engines, TypeInfo::Unknown, None), + return_type: type_engine.new_unknown(), type_ascription, value: None, visibility, 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 663891261bd..0f965bd0d4e 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -157,8 +157,7 @@ impl TyDecl { let fn_decl = engines.pe().get_function(&decl_id); let span = fn_decl.span.clone(); - let mut ctx = - ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let mut ctx = ctx.with_type_annotation(type_engine.new_unknown()); let fn_decl = match ty::TyFunctionDecl::type_check( handler, ctx.by_ref(), @@ -444,11 +443,8 @@ impl TyDecl { let mut key_ty_expression = None; if let Some(key_expression) = key_expression { - let mut key_ctx = ctx.with_type_annotation(engines.te().insert( - engines, - TypeInfo::B256, - None, - )); + let mut key_ctx = + ctx.with_type_annotation(engines.te().id_of_b256()); key_ty_expression = Some(ty::TyExpression::type_check( handler, @@ -522,9 +518,7 @@ impl TyDecl { // Resolve the type that the type alias replaces let new_ty = ctx .resolve_type(handler, ty.type_id, &span, EnforceTypeArguments::Yes, None) - .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // create the type alias decl using the resolved type above let decl = ty::TyTypeAliasDecl { diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs index 0434857f18f..5e4839c0172 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -87,7 +87,6 @@ impl ty::TyEnumVariant { variant: EnumVariant, ) -> Result { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let mut type_argument = variant.type_argument; type_argument.type_id = ctx .resolve_type( @@ -97,7 +96,7 @@ impl ty::TyEnumVariant { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); Ok(ty::TyEnumVariant { name: variant.name.clone(), type_argument, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs index 4b5b306cb98..69603909545 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -85,7 +85,6 @@ impl ty::TyFunctionDecl { let mut return_type = fn_decl.return_type.clone(); let type_engine = ctx.engines.te(); - let engines = ctx.engines(); // If functions aren't allowed in this location, return an error. if ctx.functions_disallowed() { @@ -146,9 +145,7 @@ impl ty::TyFunctionDecl { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let (visibility, is_contract_call) = if is_method { if is_in_impl_self { @@ -329,7 +326,7 @@ impl TypeCheckFinalization for ty::TyFunctionDecl { fn test_function_selector_behavior() { use crate::language::Visibility; use crate::Engines; - use sway_types::{integer_bits::IntegerBits, Ident, Span}; + use sway_types::{Ident, Span}; let engines = Engines::default(); let handler = Handler::default(); @@ -373,11 +370,7 @@ fn test_function_selector_behavior() { mutability_span: Span::dummy(), type_argument: engines .te() - .insert( - &engines, - TypeInfo::StringArray(Length::new(5, Span::dummy())), - None, - ) + .insert_string_array_without_annotations(&engines, 5) .into(), }, ty::TyFunctionParameter { @@ -386,16 +379,10 @@ fn test_function_selector_behavior() { is_mutable: false, mutability_span: Span::dummy(), type_argument: TypeArgument { - type_id: engines.te().insert( - &engines, - TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo), - None, - ), - initial_type_id: engines.te().insert( - &engines, - TypeInfo::StringArray(Length::new(5, Span::dummy())), - None, - ), + type_id: engines.te().id_of_u32(), + initial_type_id: engines + .te() + .insert_string_array_without_annotations(&engines, 5), span: Span::dummy(), call_path_tree: None, }, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs index 324a2d14404..be929464af6 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs @@ -17,7 +17,6 @@ impl ty::TyFunctionParameter { parameter: FunctionParameter, ) -> Result { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let FunctionParameter { name, @@ -35,7 +34,7 @@ impl ty::TyFunctionParameter { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); type_argument.type_id.check_type_parameter_bounds( handler, @@ -71,7 +70,6 @@ impl ty::TyFunctionParameter { parameter: &FunctionParameter, ) -> Result { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let FunctionParameter { name, @@ -90,7 +88,7 @@ impl ty::TyFunctionParameter { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let typed_parameter = ty::TyFunctionParameter { name: name.clone(), diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index 8d88a8989d8..72320202ba2 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -83,8 +83,13 @@ impl TyImplSelfOrTrait { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); - // Create a new type parameter for the Self type - let self_type_param = TypeParameter::new_self_type(engines, implementing_for.span()); + // Create a new type parameter for the Self type. + // For the `use_site_span` of the self type parameter we take the `block_span`. + // This is the span of the whole impl trait and block and thus, points to + // the code in the source file in which the self type is used in the implementation. + let self_type_use_site_span = block_span.clone(); + let self_type_param = + TypeParameter::new_self_type(engines, self_type_use_site_span.clone()); let self_type_id = self_type_param.type_id; // create a namespace for the impl @@ -157,7 +162,7 @@ impl TyImplSelfOrTrait { // Update the context let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) + .with_type_annotation(type_engine.new_unknown()) .with_self_type(Some(implementing_for.type_id)); let impl_trait = match ctx @@ -248,7 +253,7 @@ impl TyImplSelfOrTrait { } let self_type_param = - TypeParameter::new_self_type(engines, abi.span.clone()); + TypeParameter::new_self_type(engines, self_type_use_site_span); // Unify the "self" type param from the abi declaration with // the type that we are implementing for. handler.scope(|h| { @@ -340,9 +345,11 @@ impl TyImplSelfOrTrait { ctx.with_const_shadowing_mode(ConstShadowingMode::ItemStyle) .allow_functions() .scoped(handler, Some(block_span.clone()), |mut ctx| { - // Create a new type parameter for the "self type". + // Create a new type parameter for the self type. let self_type_param = - TypeParameter::new_self_type(engines, implementing_for.span()); + // Same as with impl trait or ABI, we take the `block_span` as the `use_site_span` + // of the self type. + TypeParameter::new_self_type(engines, block_span.clone()); let self_type_id = self_type_param.type_id; // create the trait name @@ -413,7 +420,7 @@ impl TyImplSelfOrTrait { let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); // type check the items inside of the impl block let mut new_items = vec![]; @@ -854,41 +861,29 @@ fn type_check_trait_implementation( let decl_ref = decl_engine.insert(type_decl.clone(), Some(decl_id)); impld_item_refs.insert((name, implementing_for), TyTraitItem::Type(decl_ref)); - let old_type_decl_info1 = TypeInfo::TraitType { - name: type_decl.name.clone(), - trait_type_id: implementing_for, - }; - let old_type_decl_info2 = TypeInfo::TraitType { - name: type_decl.name.clone(), - trait_type_id: type_engine.insert( - engines, - TypeInfo::UnknownGeneric { - // Using Span::dummy just to match the type substitution, type is not used anywhere else. - name: Ident::new_with_override("Self".into(), Span::dummy()), - trait_constraints: VecSet(vec![]), - parent: None, - is_from_type_parameter: false, - }, - None, - ), - }; + // We want the `Self` type to have the span that points to an arbitrary location within + // the source file in which the trait is implemented for a type. The `trait_name` points + // to the name in the `impl for ...` and is thus a good candidate. + let self_type_id = type_engine + .new_unknown_generic_self(trait_name.span(), false) + .0; if let Some(type_arg) = type_decl.ty.clone() { trait_type_mapping.extend( &TypeSubstMap::from_type_parameters_and_type_arguments( - vec![type_engine.insert( + vec![type_engine.insert_trait_type( engines, - old_type_decl_info1, - type_decl.name.span().source_id(), + type_decl.name.clone(), + implementing_for, )], vec![type_arg.type_id], ), ); trait_type_mapping.extend( &TypeSubstMap::from_type_parameters_and_type_arguments( - vec![type_engine.insert( + vec![type_engine.insert_trait_type( engines, - old_type_decl_info2, - type_decl.name.span().source_id(), + type_decl.name.clone(), + self_type_id, )], vec![type_arg.type_id], ), @@ -1106,7 +1101,7 @@ fn type_check_impl_method( let mut ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let interface_name = || -> InterfaceName { if is_contract { @@ -1335,7 +1330,7 @@ fn type_check_const_decl( let mut ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let interface_name = || -> InterfaceName { if is_contract { @@ -1416,7 +1411,7 @@ fn type_check_type_decl( let mut ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let interface_name = || -> InterfaceName { if is_contract { diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs index 0d3a7a25d34..4ad0a268284 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -93,9 +93,7 @@ impl ty::TyStructField { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| { - type_engine.insert(ctx.engines(), TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let field = ty::TyStructField { visibility: field.visibility, name: field.name, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs index 9a0ed2942eb..2f4504c1b90 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -100,7 +100,9 @@ impl TyTraitDecl { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); - // Create a new type parameter for the "self type". + // Create a new type parameter for the self type. + // The span of the `trait_decl` `name` points to the file (use site) in which + // the trait is getting declared, so we can use it as the `use_site_span`. let self_type_param = TypeParameter::new_self_type(engines, name.span()); let self_type = self_type_param.type_id; diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs index 07bd2feee81..fc2b0fc6c3f 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs @@ -49,7 +49,6 @@ impl ty::TyTraitFn { } = trait_fn; let type_engine = ctx.engines.te(); - let engines = ctx.engines(); // Create a namespace for the trait function. ctx.by_ref().scoped(handler, Some(span.clone()), |mut ctx| { @@ -80,9 +79,7 @@ impl ty::TyTraitFn { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let trait_fn = ty::TyTraitFn { name: name.clone(), diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs index 262c2a5ef36..27338cede56 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs @@ -14,8 +14,7 @@ use crate::{ symbol_collection_context::SymbolCollectionContext, TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, }, - type_system::*, - Engines, + EnforceTypeArguments, Engines, }; impl ty::TyTraitType { @@ -58,9 +57,7 @@ impl ty::TyTraitType { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); Some(ty) } else { None @@ -92,11 +89,7 @@ impl ty::TyTraitType { name, attributes, ty: ty_opt, - implementing_type: engines.te().insert( - engines, - TypeInfo::new_self_type(Span::dummy()), - None, - ), + implementing_type: engines.te().new_self_type(engines, Span::dummy()), span, } } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs b/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs index cd9bff70750..ea66d6e6194 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs @@ -48,7 +48,7 @@ impl ty::TyVariableDecl { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let mut ctx = ctx .with_type_annotation(type_ascription.type_id) .with_help_text( diff --git a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs index 0219bec7d15..3ed6c9de234 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs @@ -132,7 +132,7 @@ fn type_check_elem_at( // check first argument let first_argument_span = arguments[0].span.clone(); - let first_argument_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let first_argument_type = type_engine.new_unknown(); let first_argument_typed_expr = { let ctx = ctx .by_ref() @@ -163,32 +163,16 @@ fn type_check_elem_at( }; // index argument - let index_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); let index_typed_expr = { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(index_type); + .with_type_annotation(type_engine.id_of_u64()); ty::TyExpression::type_check(handler, ctx, &arguments[1])? }; - let return_type = type_engine.insert( - engines, - TypeInfo::Ref { - to_mutable_value, - referenced_type: TypeArgument { - type_id: elem_type_type_id, - initial_type_id: elem_type_type_id, - span: Span::dummy(), - call_path_tree: None, - }, - }, - None, - ); + let return_type = + type_engine.insert_ref_without_annotations(engines, to_mutable_value, elem_type_type_id); Ok(( TyIntrinsicFunctionKind { @@ -221,36 +205,26 @@ fn type_check_slice( let engines = ctx.engines(); // start index argument - let start_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); let start_ty_expr = { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(start_type); + .with_type_annotation(type_engine.id_of_u64()); ty::TyExpression::type_check(handler, ctx, &arguments[1])? }; // end index argument - let end_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); let end_ty_expr = { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(end_type); + .with_type_annotation(type_engine.id_of_u64()); ty::TyExpression::type_check(handler, ctx, &arguments[2])? }; // check first argument let first_argument_span = arguments[0].span.clone(); - let first_argument_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let first_argument_type = type_engine.new_unknown(); let first_argument_ty_expr = { let ctx = ctx .by_ref() @@ -288,18 +262,8 @@ fn type_check_slice( elem_type_arg: TypeArgument, ) -> TypeId { let type_engine = engines.te(); - let slice_type_id = - type_engine.insert(engines, TypeInfo::Slice(elem_type_arg.clone()), None); - let ref_to_slice_type = TypeInfo::Ref { - to_mutable_value, - referenced_type: TypeArgument { - type_id: slice_type_id, - initial_type_id: slice_type_id, - span: Span::dummy(), - call_path_tree: None, - }, - }; - type_engine.insert(engines, ref_to_slice_type, None) + let slice_type_id = type_engine.insert_slice(engines, elem_type_arg); + type_engine.insert_ref_without_annotations(engines, to_mutable_value, slice_type_id) } // first argument can be ref to array or ref to slice @@ -375,45 +339,22 @@ fn type_check_encode_as_raw_slice( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let buffer_expr = { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); ty::TyExpression::type_check(handler, ctx, &arguments[0].clone())? }; - let return_type = type_engine.insert(engines, TypeInfo::RawUntypedSlice, None); - let kind = ty::TyIntrinsicFunctionKind { kind, arguments: vec![buffer_expr], type_arguments: vec![], span, }; - Ok((kind, return_type)) -} - -// TODO: Rename to `new_tuple` and move to `TypeInfo` once https://github.com/FuelLabs/sway/issues/5991 is implemented. -fn new_encoding_buffer_tuple( - engines: &Engines, - items: impl IntoIterator, - span: Span, -) -> TypeInfo { - let te = engines.te(); - let items = items - .into_iter() - .map(|x| te.insert(engines, x, None)) - .map(|type_id| TypeArgument { - initial_type_id: type_id, - type_id, - span: span.clone(), - call_path_tree: None, - }) - .collect(); - TypeInfo::Tuple(items) + Ok((kind, type_engine.id_of_raw_slice())) } fn type_check_encode_buffer_empty( @@ -432,56 +373,29 @@ fn type_check_encode_buffer_empty( })); } - let type_engine = ctx.engines.te(); - let engines = ctx.engines(); - - let return_type = new_encoding_buffer_tuple( - engines, - [ - TypeInfo::RawUntypedPtr, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - ], - span.clone(), - ); - let return_type = type_engine.insert(engines, return_type, None); - let kind = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], type_arguments: vec![], span, }; - Ok((kind, return_type)) + + Ok((kind, get_encoding_buffer_type(ctx.engines()))) } -fn encode_buffer_type(engines: &Engines) -> TypeInfo { - let raw_ptr = engines.te().insert(engines, TypeInfo::RawUntypedPtr, None); - let uint64 = engines.te().insert( +/// Returns the [TypeId] of the buffer type used in encoding: `(raw_ptr, u64, u64)`. +/// The buffer type is a shareable [TypeInfo::Tuple], so it will be inserted into +/// the [TypeEngine] only once, when this method is called for the first time. +fn get_encoding_buffer_type(engines: &Engines) -> TypeId { + let type_engine = engines.te(); + type_engine.insert_tuple_without_annotations( engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); - TypeInfo::Tuple(vec![ - TypeArgument { - type_id: raw_ptr, - initial_type_id: raw_ptr, - span: Span::dummy(), - call_path_tree: None, - }, - TypeArgument { - type_id: uint64, - initial_type_id: uint64, - span: Span::dummy(), - call_path_tree: None, - }, - TypeArgument { - type_id: uint64, - initial_type_id: uint64, - span: Span::dummy(), - call_path_tree: None, - }, - ]) + vec![ + type_engine.id_of_raw_ptr(), + type_engine.id_of_u64(), + type_engine.id_of_u64(), + ], + ) } fn type_check_encode_append( @@ -503,7 +417,7 @@ fn type_check_encode_append( let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let buffer_type = type_engine.insert(engines, encode_buffer_type(engines), None); + let buffer_type = get_encoding_buffer_type(engines); let buffer_expr = { let ctx = ctx .by_ref() @@ -513,7 +427,7 @@ fn type_check_encode_append( }; let item_span = arguments[1].span.clone(); - let item_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let item_type = type_engine.new_unknown(); let item_expr = { let ctx = ctx .by_ref() @@ -574,7 +488,7 @@ fn type_check_not( })); } - let return_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let return_type = type_engine.new_unknown(); let mut ctx = ctx.with_help_text("").with_type_annotation(return_type); @@ -616,7 +530,6 @@ fn type_check_size_of_val( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 1 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -627,7 +540,7 @@ fn type_check_size_of_val( } let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let exp = ty::TyExpression::type_check(handler, ctx, &arguments[0])?; let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, @@ -635,12 +548,7 @@ fn type_check_size_of_val( type_arguments: vec![], span: span.clone(), }; - let return_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - span.source_id(), - ); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_u64())) } /// Signature: `__size_of() -> u64` @@ -685,7 +593,7 @@ fn type_check_size_of_type( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], @@ -697,12 +605,7 @@ fn type_check_size_of_type( }], span, }; - let return_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_u64())) } /// Signature: `__is_reference_type() -> bool` @@ -740,7 +643,7 @@ fn type_check_is_reference_type( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], @@ -752,10 +655,7 @@ fn type_check_is_reference_type( }], span, }; - Ok(( - intrinsic_function, - type_engine.insert(engines, TypeInfo::Boolean, None), - )) + Ok((intrinsic_function, type_engine.id_of_bool())) } /// Signature: `__assert_is_str_array()` @@ -793,7 +693,7 @@ fn type_check_assert_is_str_array( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], @@ -805,10 +705,7 @@ fn type_check_assert_is_str_array( }], span, }; - Ok(( - intrinsic_function, - type_engine.insert(engines, TypeInfo::Tuple(vec![]), None), - )) + Ok((intrinsic_function, type_engine.id_of_unit())) } fn type_check_to_str_array( @@ -832,17 +729,9 @@ fn type_check_to_str_array( match &arg.kind { ExpressionKind::Literal(Literal::String(s)) => { - let literal_length = s.as_str().len(); - let l = Length::new(literal_length, s.clone()); - let t = TypeInfo::StringArray(l); - let span = arg.span.clone(); - let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( - engines, - TypeInfo::Unknown, - None, - )); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.new_unknown()); let new_type = ty::TyExpression::type_check(handler, ctx.by_ref(), arg)?; Ok(( @@ -852,7 +741,7 @@ fn type_check_to_str_array( type_arguments: vec![], span, }, - type_engine.insert(engines, t, None), + type_engine.insert_string_array_without_annotations(engines, s.as_str().len()), )) } _ => Err(handler.emit_err(CompileError::ExpectedStringLiteral { @@ -880,7 +769,6 @@ fn type_check_cmp( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 2 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -889,9 +777,7 @@ fn type_check_cmp( span, })); } - let mut ctx = - ctx.by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.new_unknown()); let lhs = &arguments[0]; let lhs = ty::TyExpression::type_check(handler, ctx.by_ref(), lhs)?; @@ -926,7 +812,7 @@ fn type_check_cmp( type_arguments: vec![], span, }, - type_engine.insert(engines, TypeInfo::Boolean, None), + type_engine.id_of_bool(), )) } @@ -964,19 +850,11 @@ fn type_check_gtf( } // Type check the first argument which is the index - let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.id_of_u64()); let index = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[0])?; // Type check the second argument which is the tx field ID - let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.id_of_u64()); let tx_field_id = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[1])?; let targ = type_arguments[0].clone(); @@ -993,7 +871,7 @@ fn type_check_gtf( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); Ok(( ty::TyIntrinsicFunctionKind { @@ -1022,7 +900,6 @@ fn type_check_addr_of( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 1 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1033,7 +910,7 @@ fn type_check_addr_of( } let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let exp = ty::TyExpression::type_check(handler, ctx, &arguments[0])?; let copy_type_info = type_engine .to_typeinfo(exp.return_type, &span) @@ -1053,8 +930,7 @@ fn type_check_addr_of( type_arguments: vec![], span, }; - let return_type = type_engine.insert(engines, TypeInfo::RawUntypedPtr, None); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_raw_ptr())) } /// Signature: `__state_load_clear(key: b256, slots: u64) -> bool` @@ -1069,7 +945,6 @@ fn type_check_state_clear( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 2 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1082,7 +957,7 @@ fn type_check_state_clear( // `key` argument let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let key_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[0])?; let key_ty = type_engine .to_typeinfo(key_exp.return_type, &span) @@ -1100,11 +975,7 @@ fn type_check_state_clear( } // `slots` argument - let mut ctx = ctx.with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let mut ctx = ctx.with_type_annotation(type_engine.id_of_u64()); let number_of_slots_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[1])?; // Typed intrinsic @@ -1114,8 +985,7 @@ fn type_check_state_clear( type_arguments: vec![], span, }; - let return_type = type_engine.insert(engines, TypeInfo::Boolean, None); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_bool())) } /// Signature: `__state_load_word(key: b256) -> u64` @@ -1140,7 +1010,7 @@ fn type_check_state_load_word( } let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let exp = ty::TyExpression::type_check(handler, ctx, &arguments[0])?; let key_ty = type_engine .to_typeinfo(exp.return_type, &span) @@ -1159,12 +1029,7 @@ fn type_check_state_load_word( type_arguments: vec![], span, }; - let return_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_u64())) } /// Signature: `__state_store_word(key: b256, val: u64) -> bool` @@ -1198,7 +1063,7 @@ fn type_check_state_store_word( } let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let key_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[0])?; let key_ty = type_engine .to_typeinfo(key_exp.return_type, &span) @@ -1214,15 +1079,11 @@ fn type_check_state_store_word( hint: "Argument type must be B256, a key into the state storage".to_string(), })); } - let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let mut ctx = ctx.with_type_annotation(type_engine.new_unknown()); let val_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[1])?; - let ctx = ctx.with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let ctx = ctx.with_type_annotation(type_engine.id_of_u64()); let type_argument = type_arguments.first().map(|targ| { - let ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let ctx = ctx.with_type_annotation(type_engine.new_unknown()); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) @@ -1236,7 +1097,7 @@ fn type_check_state_store_word( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); TypeArgument { type_id, initial_type_id, @@ -1250,8 +1111,7 @@ fn type_check_state_store_word( type_arguments: type_argument.map_or(vec![], |ta| vec![ta]), span, }; - let return_type = type_engine.insert(engines, TypeInfo::Boolean, None); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_bool())) } /// Signature: `__state_load_quad(key: b256, ptr: raw_ptr, slots: u64)` @@ -1292,7 +1152,7 @@ fn type_check_state_quad( } let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let key_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[0])?; let key_ty = type_engine .to_typeinfo(key_exp.return_type, &span) @@ -1308,16 +1168,12 @@ fn type_check_state_quad( hint: "Argument type must be B256, a key into the state storage".to_string(), })); } - let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let mut ctx = ctx.with_type_annotation(type_engine.new_unknown()); let val_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[1])?; - let mut ctx = ctx.with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let mut ctx = ctx.with_type_annotation(type_engine.id_of_u64()); let number_of_slots_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[2])?; let type_argument = type_arguments.first().map(|targ| { - let ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let ctx = ctx.with_type_annotation(type_engine.new_unknown()); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) @@ -1331,7 +1187,7 @@ fn type_check_state_quad( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); TypeArgument { type_id, initial_type_id, @@ -1345,8 +1201,7 @@ fn type_check_state_quad( type_arguments: type_argument.map_or(vec![], |ta| vec![ta]), span, }; - let return_type = type_engine.insert(engines, TypeInfo::Boolean, None); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_bool())) } /// Signature: `__log(val: T)` @@ -1360,7 +1215,6 @@ fn type_check_log( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 1 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1372,7 +1226,7 @@ fn type_check_log( let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let exp = ty::TyExpression::type_check(handler, ctx, &arguments[0])?; let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, @@ -1380,8 +1234,7 @@ fn type_check_log( type_arguments: vec![], span, }; - let return_type = type_engine.insert(engines, TypeInfo::Tuple(vec![]), None); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_unit())) } /// Signature: `__add(lhs: T, rhs: T) -> T` @@ -1420,7 +1273,6 @@ fn type_check_arith_binary_op( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 2 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1437,7 +1289,7 @@ fn type_check_arith_binary_op( })); } - let return_type = type_engine.insert(engines, TypeInfo::Numeric, None); + let return_type = type_engine.new_numeric(); let mut ctx = ctx .by_ref() .with_type_annotation(return_type) @@ -1485,7 +1337,7 @@ fn type_check_bitwise_binary_op( })); } - let return_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let return_type = type_engine.new_unknown(); let mut ctx = ctx .by_ref() .with_type_annotation(return_type) @@ -1551,7 +1403,7 @@ fn type_check_shift_binary_op( })); } - let return_type = engines.te().insert(engines, TypeInfo::Unknown, None); + let return_type = engines.te().new_unknown(); let lhs = &arguments[0]; let lhs = ty::TyExpression::type_check( handler, @@ -1566,7 +1418,7 @@ fn type_check_shift_binary_op( handler, ctx.by_ref() .with_help_text("Incorrect argument type") - .with_type_annotation(engines.te().insert(engines, TypeInfo::Numeric, None)), + .with_type_annotation(engines.te().new_numeric()), rhs, )?; @@ -1605,7 +1457,6 @@ fn type_check_revert( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 1 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1624,11 +1475,7 @@ fn type_check_revert( } // Type check the argument which is the revert code - let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.id_of_u64()); let revert_code = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[0])?; Ok(( @@ -1638,7 +1485,7 @@ fn type_check_revert( type_arguments: vec![], span, }, - type_engine.insert(engines, TypeInfo::Never, None), + type_engine.id_of_never(), )) } @@ -1653,7 +1500,6 @@ fn type_check_jmp_mem( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if !arguments.is_empty() { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1678,7 +1524,7 @@ fn type_check_jmp_mem( type_arguments: vec![], span, }, - type_engine.insert(engines, TypeInfo::Never, None), + type_engine.id_of_never(), )) } @@ -1728,11 +1574,9 @@ fn type_check_ptr_ops( EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); - let mut ctx = - ctx.by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.new_unknown()); let lhs = &arguments[0]; let lhs = ty::TyExpression::type_check(handler, ctx.by_ref(), lhs)?; @@ -1754,11 +1598,7 @@ fn type_check_ptr_ops( let ctx = ctx .by_ref() .with_help_text("Incorrect argument type") - .with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + .with_type_annotation(type_engine.id_of_u64()); let rhs = ty::TyExpression::type_check(handler, ctx, rhs)?; Ok(( @@ -1813,7 +1653,7 @@ fn type_check_smo( let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) @@ -1827,7 +1667,7 @@ fn type_check_smo( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); TypeArgument { type_id, initial_type_id, @@ -1837,9 +1677,7 @@ fn type_check_smo( }); // Type check the first argument which is the recipient address, so it has to be a `b256`. - let mut ctx = - ctx.by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::B256, None)); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.id_of_b256()); let recipient = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[0])?; // Type check the second argument which is the data, which can be anything. If a type @@ -1847,18 +1685,12 @@ fn type_check_smo( let mut ctx = ctx.by_ref().with_type_annotation( type_argument .clone() - .map_or(type_engine.insert(engines, TypeInfo::Unknown, None), |ta| { - ta.type_id - }), + .map_or(type_engine.new_unknown(), |ta| ta.type_id), ); let data = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[1])?; // Type check the third argument which is the amount of coins to send, so it has to be a `u64`. - let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.id_of_u64()); let coins = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[2])?; Ok(( @@ -1868,7 +1700,7 @@ fn type_check_smo( type_arguments: type_argument.map_or(vec![], |ta| vec![ta]), span, }, - type_engine.insert(engines, TypeInfo::Tuple(vec![]), None), + type_engine.id_of_unit(), )) } @@ -1885,7 +1717,6 @@ fn type_check_contract_ret( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 2 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1909,13 +1740,11 @@ fn type_check_contract_ret( let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); ty::TyExpression::type_check(handler, ctx, x) }) .collect::, _>>()?; - let t = ctx.engines.te().insert(ctx.engines, TypeInfo::Never, None); - Ok(( ty::TyIntrinsicFunctionKind { kind: Intrinsic::ContractRet, @@ -1923,7 +1752,7 @@ fn type_check_contract_ret( type_arguments: vec![], span, }, - t, + ctx.engines.te().id_of_never(), )) } @@ -1939,17 +1768,11 @@ fn type_check_contract_call( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if !type_arguments.is_empty() { return Err(handler.emit_err(CompileError::TypeArgumentsNotAllowed { span })); } - let return_type_id = ctx - .engines - .te() - .insert(ctx.engines, TypeInfo::Tuple(vec![]), None); - // Arguments let arguments: Vec = arguments .iter() @@ -1957,7 +1780,7 @@ fn type_check_contract_call( let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); ty::TyExpression::type_check(handler, ctx, x) }) .collect::, _>>()?; @@ -1969,5 +1792,5 @@ fn type_check_contract_call( span, }; - Ok((intrinsic_function, return_type_id)) + Ok((intrinsic_function, type_engine.id_of_unit())) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/instantiate.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/instantiate.rs index 31306c2f247..792de9d779b 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/instantiate.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/instantiate.rs @@ -1,5 +1,5 @@ use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{integer_bits::IntegerBits, Ident, Span}; +use sway_types::{Ident, Span}; use crate::{ language::{ty, LazyOp, Literal}, @@ -7,7 +7,7 @@ use crate::{ typed_expression::{instantiate_lazy_operator, instantiate_tuple_index_access}, TypeCheckContext, }, - Engines, TypeId, TypeInfo, + Engines, TypeId, }; /// Simplifies instantiation of desugared code in the match expression and match arms. @@ -23,19 +23,11 @@ pub(super) struct Instantiate { impl Instantiate { pub(super) fn new(engines: &Engines, span: Span) -> Self { let type_engine = engines.te(); - let u64_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); - let boolean_type = type_engine.insert(engines, TypeInfo::Boolean, None); - let revert_type = type_engine.insert(engines, TypeInfo::Never, None); - Self { span, - u64_type, - boolean_type, - revert_type, + u64_type: type_engine.id_of_u64(), + boolean_type: type_engine.id_of_bool(), + revert_type: type_engine.id_of_never(), } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs index 39cd872146d..3f7856f4854 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs @@ -12,7 +12,7 @@ use crate::{ }, TypeCheckContext, }, - Ident, TypeId, TypeInfo, UnifyCheck, + Ident, TypeId, UnifyCheck, }; use sway_error::{ @@ -20,7 +20,7 @@ use sway_error::{ handler::{ErrorEmitted, Handler}, }; -use sway_types::{integer_bits::IntegerBits, span::Span, Named, Spanned}; +use sway_types::{span::Span, Named, Spanned}; /// A single requirement in the form ` == ` that has to be /// fulfilled for the match arm to match. @@ -492,20 +492,12 @@ fn match_enum( expression: ty::TyExpressionVariant::EnumTag { exp: Box::new(exp.clone()), }, - return_type: type_engine.insert( - ctx.engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ), + return_type: type_engine.id_of_u64(), span: exp.span.clone(), }, ty::TyExpression { expression: ty::TyExpressionVariant::Literal(Literal::U64(variant.tag as u64)), - return_type: type_engine.insert( - ctx.engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ), + return_type: type_engine.id_of_u64(), span: exp.span.clone(), }, ); diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs index 7e110b86e49..e00b968c4ce 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs @@ -17,7 +17,7 @@ use crate::{ ty::{self, MatchBranchCondition, MatchedOrVariantIndexVars, TyExpression}, }, semantic_analysis::*, - Engines, TypeArgument, TypeInfo, UnifyCheck, + Engines, TypeInfo, UnifyCheck, }; use super::{instantiate::Instantiate, matcher::matcher, ReqDeclTree}; @@ -619,7 +619,7 @@ fn instantiate_branch_condition_result_var_declarations_and_matched_or_variant_i ) -> Result<(VarDecl, Vec), ErrorEmitted> { let type_engine = ctx.engines.te(); // At this point we have the guarantee that we have: - // - exactly the same variables in each OR variant + // - exactly the same variables in each of the OR variants // - that variables of the same name are of the same type // - that we do not have duplicates in variable names inside of alternatives @@ -645,18 +645,10 @@ fn instantiate_branch_condition_result_var_declarations_and_matched_or_variant_i // All variants have same variable types and names, thus we pick them from the first alternative. let tuple_field_types = carry_over_vars[0] .iter() - .map(|(_, var_body)| TypeArgument { - type_id: var_body.return_type, - initial_type_id: var_body.return_type, - span: var_body.span.clone(), // Although not needed, this span can be mapped to var declaration. - call_path_tree: None, - }) + .map(|(_, var_body)| var_body.return_type) .collect(); - let tuple_type = type_engine.insert( - ctx.engines, - TypeInfo::Tuple(tuple_field_types), - instantiate.dummy_span().source_id(), - ); + let tuple_type = + type_engine.insert_tuple_without_annotations(ctx.engines, tuple_field_types); let variable_names = carry_over_vars[0] .iter() .map(|(ident, _)| ident.clone()) diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs index bd271a7f638..98168776ac2 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs @@ -12,7 +12,7 @@ use crate::{ ast_node::expression::typed_expression::instantiate_if_expression, expression::match_expression::typed::instantiate::Instantiate, TypeCheckContext, }, - CompileError, TypeId, TypeInfo, + CompileError, TypeEngine, TypeId, TypeInfo, }; use std::{collections::BTreeMap, ops::ControlFlow}; use sway_error::handler::{ErrorEmitted, Handler}; @@ -32,19 +32,19 @@ struct Trie { nodes: Vec, } -fn revert(never_type_id: TypeId, u64_type_id: TypeId) -> TyExpression { +fn revert(type_engine: &TypeEngine) -> TyExpression { TyExpression { expression: TyExpressionVariant::IntrinsicFunction(TyIntrinsicFunctionKind { kind: sway_ast::Intrinsic::Revert, arguments: vec![TyExpression { expression: TyExpressionVariant::Literal(crate::language::Literal::U64(17)), - return_type: u64_type_id, + return_type: type_engine.id_of_u64(), span: Span::dummy(), }], type_arguments: vec![], span: Span::dummy(), }), - return_type: never_type_id, + return_type: type_engine.id_of_never(), span: Span::dummy(), } } @@ -124,18 +124,7 @@ impl ty::TyMatchExpression { &self, mut ctx: TypeCheckContext<'_>, ) -> Result { - let never_type_id = ctx.engines.te().insert(ctx.engines, TypeInfo::Never, None); - - let u64_type_id = ctx.engines.te().insert( - ctx.engines, - TypeInfo::UnsignedInteger(sway_types::integer_bits::IntegerBits::SixtyFour), - None, - ); - - let bool_type_id = ctx - .engines - .te() - .insert(ctx.engines, TypeInfo::Boolean, None); + let type_engine = ctx.engines.te(); let branch_return_type_id = self .branches @@ -163,7 +152,7 @@ impl ty::TyMatchExpression { .filter(|x| x.condition.is_none()) .map(|x| x.result.clone()) .next() - .unwrap_or_else(|| revert(never_type_id, u64_type_id)); + .unwrap_or_else(|| revert(type_engine)); // All the match string slices, ignoring the wildcard let match_arms_string_slices = self @@ -246,7 +235,7 @@ impl ty::TyMatchExpression { expression: TyExpressionVariant::Literal( crate::language::Literal::U64(k as u64), ), - return_type: u64_type_id, + return_type: type_engine.id_of_u64(), span: Span::dummy(), }), }, @@ -285,7 +274,6 @@ impl ty::TyMatchExpression { .generate_radix_tree_checks( ctx.by_ref(), matched_value, - u64_type_id, branch_return_type_id, wildcard_return_expr.clone(), trie, @@ -297,7 +285,7 @@ impl ty::TyMatchExpression { expression: TyExpressionVariant::IfExp { condition: Box::new(TyExpression { expression, - return_type: bool_type_id, + return_type: type_engine.id_of_bool(), span: self.span.clone(), }), then: Box::new(then_node), @@ -373,28 +361,18 @@ impl ty::TyMatchExpression { &self, ctx: TypeCheckContext<'_>, matched_value: &TyExpression, - u64_type_id: TypeId, branch_return_type_id: TypeId, wildcard_return_expr: TyExpression, trie: Trie, packed_strings: &str, ) -> Result { - //generate code - let bool_type_id = ctx - .engines - .te() - .insert(ctx.engines, TypeInfo::Boolean, None); - - let string_slice_type_id = - ctx.engines - .te() - .insert(ctx.engines, TypeInfo::StringSlice, None); + let type_engine = ctx.engines.te(); let packed_strings_expr = TyExpression { expression: TyExpressionVariant::Literal(crate::language::Literal::String( Span::from_string(packed_strings.to_string()), )), - return_type: string_slice_type_id, + return_type: type_engine.id_of_string_slice(), span: Span::dummy(), }; @@ -405,8 +383,8 @@ impl ty::TyMatchExpression { &trie.nodes, 0, 0, - bool_type_id, - u64_type_id, + type_engine.id_of_bool(), + type_engine.id_of_u64(), branch_return_type_id, 1, wildcard_return_expr, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs index fddb0ee7b21..f81916fa337 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs @@ -3,7 +3,7 @@ use sway_error::{ error::{CompileError, StructFieldUsageContext}, handler::{ErrorEmitted, Handler}, }; -use sway_types::{BaseIdent, Ident, Span, Spanned}; +use sway_types::{Ident, Span, Spanned}; use crate::{ decl_engine::{DeclEngineGetParsedDeclId, DeclEngineInsert}, @@ -26,8 +26,6 @@ impl TyScrutinee { let engines = ctx.engines(); match scrutinee { Scrutinee::Or { elems, span } => { - let type_id = type_engine.insert(engines, TypeInfo::Unknown, None); - let mut typed_elems = Vec::with_capacity(elems.len()); for scrutinee in elems { typed_elems.push(ty::TyScrutinee::type_check( @@ -38,28 +36,22 @@ impl TyScrutinee { } let typed_scrutinee = ty::TyScrutinee { variant: ty::TyScrutineeVariant::Or(typed_elems), - type_id, + type_id: type_engine.new_unknown(), span, }; Ok(typed_scrutinee) } Scrutinee::CatchAll { span } => { - let type_id = type_engine.insert(engines, TypeInfo::Unknown, None); - let dummy_type_param = TypeParameter { - type_id, - initial_type_id: type_id, - name_ident: BaseIdent::new_with_override("_".into(), span.clone()), - trait_constraints: vec![], - trait_constraints_span: Span::dummy(), - is_from_parent: false, - }; let typed_scrutinee = ty::TyScrutinee { variant: ty::TyScrutineeVariant::CatchAll, - type_id: type_engine.insert( - engines, - TypeInfo::Placeholder(dummy_type_param), - span.source_id(), - ), + // The `span` will mostly point to a "_" in code. However, match expressions + // are heavily used in code generation, e.g., to generate code for contract + // function selection in the `__entry` and sometimes the span does not point + // to a "_". But it is always in the code in which the match expression is. + type_id: type_engine.new_placeholder(TypeParameter::new_placeholder( + type_engine.new_unknown(), + span.clone(), + )), span, }; Ok(typed_scrutinee) @@ -207,7 +199,7 @@ fn type_check_variable( // appropriate helpful errors, depending on the exact usage of that configurable. _ => ty::TyScrutinee { variant: ty::TyScrutineeVariant::Variable(name), - type_id: type_engine.insert(ctx.engines(), TypeInfo::Unknown, None), + type_id: type_engine.new_unknown(), span, }, }; @@ -425,11 +417,7 @@ fn type_check_struct( decl_engine.get_parsed_decl_id(&struct_id).as_ref(), ); let typed_scrutinee = ty::TyScrutinee { - type_id: type_engine.insert( - ctx.engines(), - TypeInfo::Struct(*struct_ref.id()), - struct_ref.span().source_id(), - ), + type_id: type_engine.insert_struct(engines, *struct_ref.id()), span, variant: ty::TyScrutineeVariant::StructScrutinee { struct_ref, @@ -552,11 +540,7 @@ fn type_check_enum( value: Box::new(typed_value), instantiation_call_path: call_path, }, - type_id: type_engine.insert( - engines, - TypeInfo::Enum(*enum_ref.id()), - enum_ref.span().source_id(), - ), + type_id: type_engine.insert_enum(engines, *enum_ref.id()), span, }; @@ -581,20 +565,17 @@ fn type_check_tuple( }, ); } - let type_id = type_engine.insert( + let type_id = type_engine.insert_tuple( engines, - TypeInfo::Tuple( - typed_elems - .iter() - .map(|x| TypeArgument { - type_id: x.type_id, - initial_type_id: x.type_id, - span: span.clone(), - call_path_tree: None, - }) - .collect(), - ), - span.source_id(), + typed_elems + .iter() + .map(|elem| TypeArgument { + type_id: elem.type_id, + initial_type_id: elem.type_id, + span: elem.span.clone(), + call_path_tree: None, + }) + .collect(), ); let typed_scrutinee = ty::TyScrutinee { variant: ty::TyScrutineeVariant::Tuple(typed_elems), diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 229f38dd9c2..3d6204c46ce 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -355,11 +355,7 @@ impl ty::TyExpression { ) } ExpressionKind::LazyOperator(LazyOperatorExpression { op, lhs, rhs }) => { - let ctx = ctx.by_ref().with_type_annotation(type_engine.insert( - engines, - TypeInfo::Boolean, - None, - )); + let ctx = ctx.by_ref().with_type_annotation(type_engine.id_of_bool()); Self::type_check_lazy_operator(handler, ctx, op.clone(), lhs, rhs, span) } ExpressionKind::CodeBlock(contents) => { @@ -477,7 +473,7 @@ impl ty::TyExpression { ExpressionKind::ArrayIndex(ArrayIndexExpression { prefix, index }) => { let ctx = ctx .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) + .with_type_annotation(type_engine.new_unknown()) .with_help_text(""); Self::type_check_array_index(handler, ctx, prefix, index, span) } @@ -488,7 +484,7 @@ impl ty::TyExpression { }) => { let ctx = ctx .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) + .with_type_annotation(type_engine.new_unknown()) .with_help_text(""); Self::type_check_storage_access( handler, @@ -519,7 +515,7 @@ impl ty::TyExpression { ExpressionKind::Break => { let expr = ty::TyExpression { expression: ty::TyExpressionVariant::Break, - return_type: type_engine.insert(engines, TypeInfo::Never, None), + return_type: type_engine.id_of_never(), span, }; Ok(expr) @@ -527,7 +523,7 @@ impl ty::TyExpression { ExpressionKind::Continue => { let expr = ty::TyExpression { expression: ty::TyExpressionVariant::Continue, - return_type: type_engine.insert(engines, TypeInfo::Never, None), + return_type: type_engine.id_of_never(), span, }; Ok(expr) @@ -563,7 +559,7 @@ impl ty::TyExpression { .unwrap_or_else(|err| ty::TyExpression::error(err, expr_span, engines)); let typed_expr = ty::TyExpression { expression: ty::TyExpressionVariant::Return(Box::new(expr)), - return_type: type_engine.insert(engines, TypeInfo::Never, None), + return_type: type_engine.id_of_never(), span, }; Ok(typed_expr) @@ -593,7 +589,7 @@ impl ty::TyExpression { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // Literals of type Numeric can now be resolved if typed_expression.return_type is // an UnsignedInteger or a Numeric @@ -620,20 +616,19 @@ impl ty::TyExpression { fn type_check_literal(engines: &Engines, lit: Literal, span: Span) -> ty::TyExpression { let type_engine = engines.te(); let return_type = match &lit { - Literal::String(_) => TypeInfo::StringSlice, - Literal::Numeric(_) => TypeInfo::Numeric, - Literal::U8(_) => TypeInfo::UnsignedInteger(IntegerBits::Eight), - Literal::U16(_) => TypeInfo::UnsignedInteger(IntegerBits::Sixteen), - Literal::U32(_) => TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo), - Literal::U64(_) => TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - Literal::U256(_) => TypeInfo::UnsignedInteger(IntegerBits::V256), - Literal::Boolean(_) => TypeInfo::Boolean, - Literal::B256(_) => TypeInfo::B256, + Literal::String(_) => type_engine.id_of_string_slice(), + Literal::Numeric(_) => type_engine.new_numeric(), + Literal::U8(_) => type_engine.id_of_u8(), + Literal::U16(_) => type_engine.id_of_u16(), + Literal::U32(_) => type_engine.id_of_u32(), + Literal::U64(_) => type_engine.id_of_u64(), + Literal::U256(_) => type_engine.id_of_u256(), + Literal::Boolean(_) => type_engine.id_of_bool(), + Literal::B256(_) => type_engine.id_of_b256(), }; - let id = type_engine.insert(engines, return_type, span.source_id()); ty::TyExpression { expression: ty::TyExpressionVariant::Literal(lit), - return_type: id, + return_type, span, } } @@ -782,7 +777,6 @@ impl ty::TyExpression { span: Span, ) -> Result { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let (typed_block, block_return_type) = match ty::TyCodeBlock::type_check(handler, ctx.by_ref(), contents, false) { @@ -790,10 +784,7 @@ impl ty::TyExpression { let (block_type, _span) = TyCodeBlock::compute_return_type_and_span(&ctx, &res); (res, block_type) } - Err(_err) => ( - ty::TyCodeBlock::default(), - type_engine.insert(engines, TypeInfo::Tuple(Vec::new()), None), - ), + Err(_err) => (ty::TyCodeBlock::default(), type_engine.id_of_unit()), }; let exp = ty::TyExpression { @@ -820,7 +811,7 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("The condition of an if expression must be a boolean expression.") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Boolean, None)); + .with_type_annotation(type_engine.id_of_bool()); ty::TyExpression::type_check(handler, ctx, &condition) .unwrap_or_else(|err| ty::TyExpression::error(err, condition.span(), engines)) }; @@ -883,7 +874,7 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); ty::TyExpression::type_check(handler, ctx, value) .unwrap_or_else(|err| ty::TyExpression::error(err, value.span().clone(), engines)) }; @@ -1071,20 +1062,27 @@ impl ty::TyExpression { // 2. Check that initialized registers are not reassigned in the `asm` block. check_asm_block_validity(handler, &asm, &ctx)?; - let asm_span = asm + // Take the span of the returns register, or as a fallback, the span of the + // whole ASM block. + let asm_returns_span = asm .returns .clone() .map(|x| x.1) .unwrap_or_else(|| asm.whole_block_span.clone()); + let return_type = ctx .resolve_type( handler, - type_engine.insert(engines, asm.return_type.clone(), asm_span.source_id()), - &asm_span, + type_engine.insert( + engines, + asm.return_type.clone(), + asm_returns_span.source_id(), + ), + &asm_returns_span, EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // type check the initializers let typed_registers = asm @@ -1095,9 +1093,10 @@ impl ty::TyExpression { |AsmRegisterDeclaration { name, initializer }| ty::TyAsmRegisterDeclaration { name, initializer: initializer.map(|initializer| { - let ctx = ctx.by_ref().with_help_text("").with_type_annotation( - type_engine.insert(engines, TypeInfo::Unknown, None), - ); + let ctx = ctx + .by_ref() + .with_help_text("") + .with_type_annotation(type_engine.new_unknown()); ty::TyExpression::type_check(handler, ctx, &initializer).unwrap_or_else( |err| ty::TyExpression::error(err, initializer.span(), engines), @@ -1132,7 +1131,7 @@ impl ty::TyExpression { let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let parent = ty::TyExpression::type_check(handler, ctx.by_ref(), prefix)?; let exp = instantiate_struct_field_access( handler, @@ -1168,7 +1167,7 @@ impl ty::TyExpression { .as_ref() .map(|field_type_ids| field_type_ids[i].clone()) .unwrap_or_else(|| { - let initial_type_id = type_engine.insert(engines, TypeInfo::Unknown, None); + let initial_type_id = type_engine.new_unknown(); TypeArgument { type_id: initial_type_id, initial_type_id, @@ -1195,11 +1194,7 @@ impl ty::TyExpression { expression: ty::TyExpressionVariant::Tuple { fields: typed_fields, }, - return_type: ctx.engines.te().insert( - engines, - TypeInfo::Tuple(typed_field_types), - span.source_id(), - ), + return_type: ctx.engines.te().insert_tuple(engines, typed_field_types), span, }; Ok(exp) @@ -1297,11 +1292,7 @@ impl ty::TyExpression { .get_parsed_decl_id(&storage_key_struct_decl_id) .as_ref(), ); - access_type = type_engine.insert( - engines, - TypeInfo::Struct(*storage_key_struct_decl_ref.id()), - storage_key_struct_decl_ref.span().source_id(), - ); + access_type = type_engine.insert_struct(engines, *storage_key_struct_decl_ref.id()); Ok(ty::TyExpression { expression: ty::TyExpressionVariant::StorageAccess(storage_access), @@ -1323,7 +1314,7 @@ impl ty::TyExpression { let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let parent = ty::TyExpression::type_check(handler, ctx, &prefix)?; let exp = instantiate_tuple_index_access(handler, engines, parent, index, index_span, span)?; @@ -1793,7 +1784,7 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("An address that is being ABI cast must be of type b256") - .with_type_annotation(type_engine.insert(engines, TypeInfo::B256, None)); + .with_type_annotation(type_engine.id_of_b256()); ty::TyExpression::type_check(handler, ctx, address) .unwrap_or_else(|err| ty::TyExpression::error(err, err_span, engines)) }; @@ -1835,13 +1826,10 @@ impl ty::TyExpression { } AbiName::Deferred => { return Ok(ty::TyExpression { - return_type: type_engine.insert( + return_type: type_engine.new_contract_caller( engines, - TypeInfo::ContractCaller { - abi_name: AbiName::Deferred, - address: None, - }, - span.source_id(), + AbiName::Deferred, + None, ), expression: ty::TyExpressionVariant::Tuple { fields: vec![] }, span, @@ -1865,13 +1853,10 @@ impl ty::TyExpression { .. } = &*abi_decl; - let return_type = type_engine.insert( + let return_type = type_engine.new_contract_caller( engines, - TypeInfo::ContractCaller { - abi_name: AbiName::Known(abi_name.clone()), - address: Some(Box::new(address_expr.clone())), - }, - abi_name.span().source_id(), + AbiName::Known(abi_name.clone()), + Some(Box::new(address_expr.clone())), ); // Retrieve the interface surface for this abi. @@ -1961,25 +1946,13 @@ impl ty::TyExpression { let engines = ctx.engines(); if contents.is_empty() { - let elem_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let elem_type = type_engine.new_unknown(); return Ok(ty::TyExpression { expression: ty::TyExpressionVariant::Array { elem_type, contents: Vec::new(), }, - return_type: type_engine.insert( - engines, - TypeInfo::Array( - TypeArgument { - type_id: elem_type, - span: Span::dummy(), - call_path_tree: None, - initial_type_id: elem_type, - }, - Length::new(0, Span::dummy()), - ), - None, - ), + return_type: type_engine.insert_array_without_annotations(engines, elem_type, 0), span, }); }; @@ -2036,25 +2009,13 @@ impl ty::TyExpression { }; let elem_type = type_engine.insert(engines, initial_type.clone(), None); - let array_count = typed_contents.len(); + let length = typed_contents.len(); let expr = ty::TyExpression { expression: ty::TyExpressionVariant::Array { elem_type, contents: typed_contents, }, - return_type: type_engine.insert( - engines, - TypeInfo::Array( - TypeArgument { - type_id: elem_type, - span: Span::dummy(), - call_path_tree: None, - initial_type_id: elem_type, - }, - Length::new(array_count, Span::dummy()), - ), - None, - ), + return_type: type_engine.insert_array_without_annotations(engines, elem_type, length), span, }; @@ -2079,7 +2040,7 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); ty::TyExpression::type_check(handler, ctx, prefix)? }); @@ -2126,10 +2087,9 @@ impl ty::TyExpression { }; let index_te = { - let type_info_u64 = TypeInfo::UnsignedInteger(IntegerBits::SixtyFour); let ctx = ctx .with_help_text("Array index must be of type \"u64\".") - .with_type_annotation(type_engine.insert(engines, type_info_u64, None)); + .with_type_annotation(type_engine.id_of_u64()); ty::TyExpression::type_check(handler, ctx, index)? }; @@ -2174,17 +2134,16 @@ impl ty::TyExpression { span: Span, ) -> Result { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let typed_condition = { let ctx = ctx .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Boolean, None)) + .with_type_annotation(type_engine.id_of_bool()) .with_help_text("A while loop's loop condition must be a boolean expression."); ty::TyExpression::type_check(handler, ctx, condition)? }; - let unit_ty = type_engine.insert(engines, TypeInfo::Tuple(Vec::new()), None); + let unit_ty = type_engine.id_of_unit(); let mut ctx = ctx.with_type_annotation(unit_ty).with_help_text( "A while loop's loop body cannot implicitly return a value. Try \ assigning it to a mutable variable declared outside of the loop \ @@ -2222,7 +2181,7 @@ impl ty::TyExpression { let engines = ctx.engines(); let mut ctx = ctx - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) + .with_type_annotation(type_engine.new_unknown()) .with_help_text(""); let (lhs, expected_rhs_type) = match lhs { @@ -2407,15 +2366,10 @@ impl ty::TyExpression { expr = prefix; } ExpressionKind::ArrayIndex(ArrayIndexExpression { prefix, index }) => { - let type_info_u64 = TypeInfo::UnsignedInteger(IntegerBits::SixtyFour); let ctx = ctx .by_ref() .with_help_text("Array index must be of type \"u64\".") - .with_type_annotation(type_engine.insert( - engines, - type_info_u64, - None, - )); + .with_type_annotation(type_engine.id_of_u64()); let typed_index = ty::TyExpression::type_check(handler, ctx, index.as_ref()) .unwrap_or_else(|err| { @@ -2470,7 +2424,7 @@ impl ty::TyExpression { lhs, rhs, })), - return_type: type_engine.insert(engines, TypeInfo::Tuple(Vec::new()), None), + return_type: type_engine.id_of_unit(), span, }) } @@ -2496,7 +2450,7 @@ impl ty::TyExpression { TypeInfo::Ref { referenced_type, .. } => referenced_type.type_id, - _ => type_engine.insert(engines, TypeInfo::Unknown, None), + _ => type_engine.new_unknown(), }; let ctx = ctx @@ -2518,16 +2472,13 @@ impl ty::TyExpression { } }; - let expr_type_argument: TypeArgument = expr.return_type.into(); + let expr_return_type = expr.return_type; let typed_expr = ty::TyExpression { expression: ty::TyExpressionVariant::Ref(Box::new(expr)), - return_type: type_engine.insert( + return_type: type_engine.insert_ref_without_annotations( engines, - TypeInfo::Ref { - to_mutable_value, - referenced_type: expr_type_argument, - }, - None, + to_mutable_value, + expr_return_type, ), span, }; @@ -2601,15 +2552,8 @@ impl ty::TyExpression { // Since `&mut T` coerces into `&T` we always go with a lesser expectation, `&T`. // Thus, `to_mutable_vale` is set to false. let type_annotation = match &*type_engine.get(ctx.type_annotation()) { - TypeInfo::Unknown => type_engine.insert(engines, TypeInfo::Unknown, None), - _ => type_engine.insert( - engines, - TypeInfo::Ref { - to_mutable_value: false, - referenced_type: ctx.type_annotation().into(), - }, - None, - ), + TypeInfo::Unknown => type_engine.new_unknown(), + _ => type_engine.insert_ref_without_annotations(engines, false, ctx.type_annotation()), }; let deref_ctx = ctx @@ -2710,7 +2654,7 @@ impl ty::TyExpression { num.to_string().parse().map(Literal::Numeric).map_err(|e| { Literal::handle_parse_int_error(engines, e, TypeInfo::Numeric, span.clone()) }), - type_engine.insert(engines, TypeInfo::Numeric, None), + type_engine.new_numeric(), ), _ => unreachable!("Unexpected type for integer literals"), }, @@ -2949,19 +2893,9 @@ mod tests { handler, &engines, expr, - engines.te().insert( - &engines, - TypeInfo::Array( - TypeArgument { - type_id: engines.te().insert(&engines, TypeInfo::Boolean, None), - span: Span::dummy(), - call_path_tree: None, - initial_type_id: engines.te().insert(&engines, TypeInfo::Boolean, None), - }, - Length::new(2, Span::dummy()), - ), - None, - ), + engines + .te() + .insert_array_without_annotations(&engines, engines.te().id_of_bool(), 2), ExperimentalFeatures::default(), )?; expr.type_check_analyze(handler, &mut TypeCheckAnalysisContext::new(&engines))?; @@ -3089,19 +3023,9 @@ mod tests { &handler, &engines, &expr, - engines.te().insert( - &engines, - TypeInfo::Array( - TypeArgument { - type_id: engines.te().insert(&engines, TypeInfo::Boolean, None), - span: Span::dummy(), - call_path_tree: None, - initial_type_id: engines.te().insert(&engines, TypeInfo::Boolean, None), - }, - Length::new(0, Span::dummy()), - ), - None, - ), + engines + .te() + .insert_array_without_annotations(&engines, engines.te().id_of_bool(), 0), ExperimentalFeatures::default(), ); let (errors, warnings) = handler.consume(); diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs index 35ddcb183ca..4da63001bb4 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs @@ -56,11 +56,7 @@ pub(crate) fn instantiate_enum( match (&args, &*type_engine.get(enum_variant.type_argument.type_id)) { ([], ty) if ty.is_unit() => Ok(ty::TyExpression { - return_type: type_engine.insert( - engines, - TypeInfo::Enum(*enum_ref.id()), - enum_ref.span().source_id(), - ), + return_type: type_engine.insert_enum(engines, *enum_ref.id()), expression: ty::TyExpressionVariant::EnumInstantiation { tag: enum_variant.tag, contents: None, @@ -149,11 +145,7 @@ pub(crate) fn instantiate_enum( // Create the resulting enum type based on the enum we have instantiated. // Note that we clone the `enum_ref` but the unification we do below will // affect the types behind that new enum decl reference. - let type_id = type_engine.insert( - engines, - TypeInfo::Enum(*enum_ref.id()), - enum_ref.span().source_id(), - ); + let type_id = type_engine.insert_enum(engines, *enum_ref.id()); // The above type check will unify the type behind the `enum_variant_type_id` // and the resulting expression type. diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs index bdd3679c869..9b1a5e4ebc8 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs @@ -22,7 +22,7 @@ pub(crate) fn instantiate_if_expression( let ty_to_check = if r#else.is_some() { ctx.type_annotation() } else { - type_engine.insert(engines, TypeInfo::Tuple(vec![]), then.span.source_id()) + type_engine.id_of_unit() }; // We check then_type_is_never and else_type_is_never before unifying to make sure we don't @@ -62,9 +62,10 @@ pub(crate) fn instantiate_if_expression( Box::new(r#else) }); - let r#else_ret_ty = r#else.as_ref().map(|x| x.return_type).unwrap_or_else(|| { - type_engine.insert(engines, TypeInfo::Tuple(Vec::new()), span.source_id()) - }); + let r#else_ret_ty = r#else + .as_ref() + .map(|x| x.return_type) + .unwrap_or_else(|| type_engine.id_of_unit()); // delay emitting the errors until we decide if this is a missing else branch or some other set of errors let h = Handler::default(); diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs index 3c118c43536..d7d724caea1 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs @@ -20,7 +20,7 @@ use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, }; -use sway_types::{constants, integer_bits::IntegerBits, BaseIdent, IdentUnique}; +use sway_types::{constants, BaseIdent, IdentUnique}; use sway_types::{constants::CONTRACT_CALL_COINS_PARAMETER_NAME, Spanned}; use sway_types::{Ident, Span}; @@ -45,7 +45,7 @@ pub(crate) fn type_check_method_application( let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); // Ignore errors in method parameters // On the second pass we will throw the errors if they persist. @@ -82,7 +82,7 @@ pub(crate) fn type_check_method_application( .iter() .map(|(arg, _has_errors)| match arg { Some(arg) => arg.return_type, - None => type_engine.insert(engines, TypeInfo::Unknown, None), + None => type_engine.new_unknown(), }) .collect(), )?; @@ -130,7 +130,7 @@ pub(crate) fn type_check_method_application( } else { ctx.by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) + .with_type_annotation(type_engine.new_unknown()) }; args_buf.push_back( @@ -183,17 +183,13 @@ pub(crate) fn type_check_method_application( | constants::CONTRACT_CALL_ASSET_ID_PARAMETER_NAME => { untyped_contract_call_params_map .insert(param.name.to_string(), param.value.clone()); - let type_annotation = type_engine.insert( - engines, - if param.name.span().as_str() - != constants::CONTRACT_CALL_ASSET_ID_PARAMETER_NAME - { - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour) - } else { - TypeInfo::B256 - }, - param.name.span().source_id(), - ); + let type_annotation = if param.name.span().as_str() + != constants::CONTRACT_CALL_ASSET_ID_PARAMETER_NAME + { + type_engine.id_of_u64() + } else { + type_engine.id_of_b256() + }; let ctx = ctx .by_ref() .with_help_text("") @@ -443,21 +439,10 @@ pub(crate) fn type_check_method_application( asset_id_expr: Expression, gas_expr: Expression, ) -> Expression { - let tuple_args_type_id = ctx.engines.te().insert( - ctx.engines, - TypeInfo::Tuple( - typed_arguments - .iter() - .map(|&type_id| TypeArgument { - type_id, - initial_type_id: type_id, - span: Span::dummy(), - call_path_tree: None, - }) - .collect(), - ), - None, - ); + let tuple_args_type_id = ctx + .engines + .te() + .insert_tuple_without_annotations(ctx.engines, typed_arguments); Expression { kind: ExpressionKind::FunctionApplication(Box::new( FunctionApplicationExpression { @@ -608,7 +593,7 @@ pub(crate) fn type_check_method_application( for p in method.type_parameters.clone() { if p.is_from_parent { if let Some(impl_type_param) = - names_index.get(&p.name_ident).and_then(|type_param_index| { + names_index.get(&p.name).and_then(|type_param_index| { implementing_type_parameters.get(*type_param_index) }) { @@ -672,7 +657,7 @@ pub(crate) fn type_check_method_application( // This handles the case of substituting the generic blanket type by call_path_typeid. for p in method.type_parameters.clone() { - if p.name_ident.as_str() == qualified_call_path.call_path.suffix.as_str() { + if p.name.as_str() == qualified_call_path.call_path.suffix.as_str() { subst_type_parameters.push(t.initial_type_id); subst_type_arguments.push(call_path_typeid); break; @@ -682,13 +667,10 @@ pub(crate) fn type_check_method_application( // This will subst inner method_application placeholders with the already resolved // current method application type parameter for p in method.type_parameters.clone() { - if names_type_ids.contains_key(&p.name_ident) { - subst_type_parameters.push(engines.te().insert( - engines, - TypeInfo::Placeholder(p.clone()), - p.span().source_id(), - )); - subst_type_arguments.push(p.type_id); + if names_type_ids.contains_key(&p.name) { + let type_parameter_type_id = p.type_id; + subst_type_parameters.push(engines.te().new_placeholder(p)); + subst_type_arguments.push(type_parameter_type_id); } } @@ -818,9 +800,7 @@ pub(crate) fn resolve_method_name( // type check the call path let type_id = call_path_binding .type_check_with_type_info(handler, &mut ctx) - .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // find the module that the symbol is in let type_info_prefix = ctx @@ -867,7 +847,7 @@ pub(crate) fn resolve_method_name( let type_id = arguments_types .front() .cloned() - .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Unknown, None)); + .unwrap_or_else(|| type_engine.new_unknown()); // find the method let decl_ref = ctx.find_method_for_type( @@ -891,7 +871,7 @@ pub(crate) fn resolve_method_name( let type_id = arguments_types .front() .cloned() - .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Unknown, None)); + .unwrap_or_else(|| type_engine.new_unknown()); // find the method let decl_ref = ctx.find_method_for_type( diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs index 1d84a623fbd..47c190a0c2b 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs @@ -59,21 +59,16 @@ pub(crate) fn struct_instantiation( let type_arguments = type_arguments.to_vec(); - let type_info = match (suffix.as_str(), type_arguments.is_empty()) { - ("Self", true) => TypeInfo::new_self_type(suffix.span()), + // We first create a custom type and then resolve it to the struct type. + let custom_type_id = match (suffix.as_str(), type_arguments.is_empty()) { + ("Self", true) => type_engine.new_self_type(engines, suffix.span()), ("Self", false) => { return Err(handler.emit_err(CompileError::TypeArgumentsNotAllowed { span: suffix.span(), })); } - (_, true) => TypeInfo::Custom { - qualified_call_path: suffix.clone().into(), - type_arguments: None, - }, - (_, false) => TypeInfo::Custom { - qualified_call_path: suffix.clone().into(), - type_arguments: Some(type_arguments), - }, + (_, true) => type_engine.new_custom_from_name(engines, suffix.clone()), + (_, false) => type_engine.new_custom(engines, suffix.clone().into(), Some(type_arguments)), }; // find the module that the struct decl is in @@ -85,12 +80,12 @@ pub(crate) fn struct_instantiation( let type_id = ctx .resolve_type( handler, - type_engine.insert(engines, type_info, suffix.span().source_id()), + custom_type_id, inner_span, EnforceTypeArguments::No, Some(&type_info_prefix), ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // extract the struct name and fields from the type info let type_info = type_engine.get(type_id); @@ -389,7 +384,6 @@ fn type_check_field_arguments( ) -> Result, ErrorEmitted> { handler.scope(|handler| { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let mut typed_fields = vec![]; let mut missing_fields = vec![]; @@ -434,11 +428,7 @@ fn type_check_field_arguments( name: struct_field.name.clone(), value: ty::TyExpression { expression: ty::TyExpressionVariant::Tuple { fields: vec![] }, - return_type: type_engine.insert( - engines, - TypeInfo::ErrorRecovery(err), - None, - ), + return_type: type_engine.id_of_error_recovery(err), span: span.clone(), }, }); diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index 3a6ea5f2153..5dee758e227 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -91,11 +91,7 @@ impl ty::TyAstNode { _ => { ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert( - engines, - TypeInfo::Unknown, - None, - )); + .with_type_annotation(type_engine.new_unknown()); } } let inner = ty::TyExpression::type_check(handler, ctx, &expr) diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index 15113704762..e37c30dfd61 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -177,7 +177,6 @@ enum TypeRootFilter { Struct(ParsedDeclId), ContractCaller(String), Array(usize), - Storage, RawUntypedPtr, RawUntypedSlice, Ptr, @@ -882,7 +881,8 @@ impl TraitMap { }, } in impls.iter() { - if !type_info.can_change(engines) && *type_id == *map_type_id { + if !type_engine.is_type_changeable(engines, &type_info) && *type_id == *map_type_id + { trait_map.insert_inner( map_trait_name.clone(), impl_span.clone(), @@ -1397,17 +1397,14 @@ impl TraitMap { let key = &e.key; let suffix = &key.name.suffix; if unify_check.check(type_id, key.type_id) { - let map_trait_type_id = type_engine.insert( + let map_trait_type_id = type_engine.new_custom( engines, - TypeInfo::Custom { - qualified_call_path: suffix.name.clone().into(), - type_arguments: if suffix.args.is_empty() { - None - } else { - Some(suffix.args.to_vec()) - }, + suffix.name.clone().into(), + if suffix.args.is_empty() { + None + } else { + Some(suffix.args.to_vec()) }, - suffix.name.span().source_id(), ); Some((suffix.name.clone(), map_trait_type_id)) } else { @@ -1423,17 +1420,14 @@ impl TraitMap { trait_name: constraint_trait_name, type_arguments: constraint_type_arguments, } = c; - let constraint_type_id = type_engine.insert( + let constraint_type_id = type_engine.new_custom( engines, - TypeInfo::Custom { - qualified_call_path: constraint_trait_name.suffix.clone().into(), - type_arguments: if constraint_type_arguments.is_empty() { - None - } else { - Some(constraint_type_arguments.clone()) - }, + constraint_trait_name.suffix.clone().into(), + if constraint_type_arguments.is_empty() { + None + } else { + Some(constraint_type_arguments.clone()) }, - constraint_trait_name.span().source_id(), ); (c.trait_name.suffix.clone(), constraint_type_id) }) @@ -1604,7 +1598,6 @@ impl TraitMap { } ContractCaller { abi_name, .. } => TypeRootFilter::ContractCaller(abi_name.to_string()), Array(_, length) => TypeRootFilter::Array(length.val()), - Storage { .. } => TypeRootFilter::Storage, RawUntypedPtr => TypeRootFilter::RawUntypedPtr, RawUntypedSlice => TypeRootFilter::RawUntypedSlice, Ptr(_) => TypeRootFilter::Ptr, diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index e0a5b5b3f0b..2ca2ee6ad38 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -1029,7 +1029,6 @@ fn type_info_name(type_info: &TypeInfo) -> String { TypeInfo::Struct { .. } => "struct", TypeInfo::Enum { .. } => "enum", TypeInfo::Array(..) => "array", - TypeInfo::Storage { .. } => "contract storage", TypeInfo::RawUntypedPtr => "raw untyped ptr", TypeInfo::RawUntypedSlice => "raw untyped slice", TypeInfo::Ptr(..) => "__ptr", diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index d6c3a7c45f1..2a6b71b5687 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -124,8 +124,8 @@ impl<'a> TypeCheckContext<'a> { namespace, engines, collection_ctx, - type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), - function_type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), + type_annotation: engines.te().new_unknown(), + function_type_annotation: engines.te().new_unknown(), unify_generic: false, self_type: None, type_subst: TypeSubstMap::new(), @@ -168,8 +168,8 @@ impl<'a> TypeCheckContext<'a> { collection_ctx, namespace, engines, - type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), - function_type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), + type_annotation: engines.te().new_unknown(), + function_type_annotation: engines.te().new_unknown(), unify_generic: false, self_type: None, type_subst: TypeSubstMap::new(), @@ -750,7 +750,7 @@ impl<'a> TypeCheckContext<'a> { self.self_type(), &self.subst_ctx(), ) - .unwrap_or_else(|err| type_engine.insert(self.engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // grab the module where the type itself is declared let type_module = self.namespace().lookup_submodule_from_absolute_path( diff --git a/sway-core/src/semantic_analysis/type_resolve.rs b/sway-core/src/semantic_analysis/type_resolve.rs index e4c676fda1e..387d3f48b2d 100644 --- a/sway-core/src/semantic_analysis/type_resolve.rs +++ b/sway-core/src/semantic_analysis/type_resolve.rs @@ -63,7 +63,7 @@ pub fn resolve_type( subst_ctx, )? } - TypeInfo::Array(mut elem_ty, n) => { + TypeInfo::Array(mut elem_ty, length) => { elem_ty.type_id = resolve_type( handler, engines, @@ -76,17 +76,9 @@ pub fn resolve_type( self_type, subst_ctx, ) - .unwrap_or_else(|err| { - engines - .te() - .insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); - engines.te().insert( - engines, - TypeInfo::Array(elem_ty.clone(), n.clone()), - elem_ty.span.source_id(), - ) + engines.te().insert_array(engines, elem_ty, length) } TypeInfo::Slice(mut elem_ty) => { elem_ty.type_id = resolve_type( @@ -101,17 +93,9 @@ pub fn resolve_type( self_type, subst_ctx, ) - .unwrap_or_else(|err| { - engines - .te() - .insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); - engines.te().insert( - engines, - TypeInfo::Slice(elem_ty.clone()), - elem_ty.span.source_id(), - ) + engines.te().insert_slice(engines, elem_ty) } TypeInfo::Tuple(mut type_arguments) => { for type_argument in type_arguments.iter_mut() { @@ -127,16 +111,10 @@ pub fn resolve_type( self_type, subst_ctx, ) - .unwrap_or_else(|err| { - engines - .te() - .insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); } - engines - .te() - .insert(engines, TypeInfo::Tuple(type_arguments), span.source_id()) + engines.te().insert_tuple(engines, type_arguments) } TypeInfo::TraitType { name, @@ -179,20 +157,9 @@ pub fn resolve_type( self_type, subst_ctx, ) - .unwrap_or_else(|err| { - engines - .te() - .insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); - engines.te().insert( - engines, - TypeInfo::Ref { - to_mutable_value, - referenced_type: ty.clone(), - }, - None, - ) + engines.te().insert_ref(engines, to_mutable_value, ty) } _ => type_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 e40c9148fda..0cbf326b070 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 @@ -542,11 +542,7 @@ pub fn item_fn_to_function_declaration( let return_type = match item_fn.fn_signature.return_type_opt { Some((_right_arrow, ty)) => ty_to_type_argument(context, handler, engines, ty)?, None => { - let type_id = engines.te().insert( - engines, - TypeInfo::Tuple(Vec::new()), - item_fn.fn_signature.span().source_id(), - ); + let type_id = engines.te().id_of_unit(); TypeArgument { type_id, initial_type_id: type_id, @@ -992,7 +988,7 @@ pub(crate) fn item_const_to_constant_declaration( return Err(errors); } } - engines.te().insert(engines, TypeInfo::Unknown, None).into() + engines.te().new_unknown().into() } }; @@ -1255,18 +1251,11 @@ fn generic_params_opt_to_type_parameters_with_parent( .into_inner() .into_iter() .map(|ident| { - let custom_type = type_engine.insert( - engines, - TypeInfo::Custom { - qualified_call_path: ident.clone().into(), - type_arguments: None, - }, - ident.span().source_id(), - ); + let custom_type = type_engine.new_custom_from_name(engines, ident.clone()); TypeParameter { type_id: custom_type, initial_type_id: custom_type, - name_ident: ident, + name: ident, trait_constraints: Vec::new(), trait_constraints_span: Span::dummy(), is_from_parent, @@ -1286,12 +1275,12 @@ fn generic_params_opt_to_type_parameters_with_parent( { let param_to_edit = if let Some(o) = params .iter_mut() - .find(|TypeParameter { name_ident, .. }| name_ident.as_str() == ty_name.as_str()) + .find(|TypeParameter { name, .. }| name.as_str() == ty_name.as_str()) { o } else if let Some(o2) = parent_params .iter() - .find(|TypeParameter { name_ident, .. }| name_ident.as_str() == ty_name.as_str()) + .find(|TypeParameter { name, .. }| name.as_str() == ty_name.as_str()) { params.push(o2.clone()); params.last_mut().unwrap() @@ -1405,11 +1394,7 @@ fn fn_args_to_function_parameters( (Some(reference), None) => reference.span(), (Some(reference), Some(mutable)) => Span::join(reference.span(), &mutable.span()), }; - let type_id = engines.te().insert( - engines, - TypeInfo::new_self_type(self_token.span()), - self_token.span().source_id(), - ); + let type_id = engines.te().new_self_type(engines, self_token.span()); let mut function_parameters = vec![FunctionParameter { name: Ident::new(self_token.span()), is_reference: ref_self.is_some(), @@ -1613,11 +1598,7 @@ fn fn_signature_to_trait_fn( let return_type = match &fn_signature.return_type_opt { Some((_right_arrow, ty)) => ty_to_type_argument(context, handler, engines, ty.clone())?, None => { - let type_id = engines.te().insert( - engines, - TypeInfo::Tuple(Vec::new()), - fn_signature.span().source_id(), - ); + let type_id = engines.te().id_of_unit(); TypeArgument { type_id, initial_type_id: type_id, @@ -2754,7 +2735,10 @@ fn expr_to_length( expr: Expr, ) -> Result { let span = expr.span(); - Ok(Length::new(expr_to_usize(context, handler, expr)?, span)) + Ok(Length::from_numeric_literal( + expr_to_usize(context, handler, expr)?, + span, + )) } fn expr_to_usize( @@ -3047,7 +3031,7 @@ fn match_expr_to_expression( let var_decl = engines.pe().insert(VariableDeclaration { type_ascription: { - let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); + let type_id = engines.te().new_unknown(); TypeArgument { type_id, initial_type_id: type_id, @@ -3131,7 +3115,7 @@ fn for_expr_to_expression( // Declare iterable with iterator return let iterable_decl = engines.pe().insert(VariableDeclaration { type_ascription: { - let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); + let type_id = engines.te().new_unknown(); TypeArgument { type_id, initial_type_id: type_id, @@ -3164,7 +3148,7 @@ fn for_expr_to_expression( // Declare value_opt = iterable.next() let value_opt_to_next_decl = engines.pe().insert(VariableDeclaration { type_ascription: { - let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); + let type_id = engines.te().new_unknown(); TypeArgument { type_id, initial_type_id: type_id, @@ -3820,7 +3804,7 @@ fn statement_let_to_ast_nodes_unfold( let type_ascription = match ty_opt { Some(ty) => ty_to_type_argument(context, handler, engines, ty)?, None => { - let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); + let type_id = engines.te().new_unknown(); TypeArgument { type_id, initial_type_id: type_id, @@ -3870,7 +3854,7 @@ fn statement_let_to_ast_nodes_unfold( let type_ascription = match &ty_opt { Some(ty) => ty_to_type_argument(context, handler, engines, ty.clone())?, None => { - let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); + let type_id = engines.te().new_unknown(); TypeArgument { type_id, initial_type_id: type_id, @@ -3954,52 +3938,38 @@ fn statement_let_to_ast_nodes_unfold( let tuple_name = generate_tuple_var_name(context.next_destructured_tuple_unique_suffix()); - let tuple_name = Ident::new_with_override(tuple_name, pat_tuple.span().clone()); + let tuple_name = Ident::new_with_override(tuple_name, pat_tuple.span()); - // Acript a second declaration to a tuple of placeholders to check that the tuple - // is properly sized to the pattern + // Ascribe a second declaration to a tuple of placeholders to check that the tuple + // is properly sized to the pattern. let placeholders_type_ascription = { - let type_id = engines.te().insert( + let type_id = engines.te().insert_tuple_without_annotations( engines, - TypeInfo::Tuple( - pat_tuple - .clone() - .into_inner() - .into_iter() - .map(|pat| { - let initial_type_id = - engines.te().insert(engines, TypeInfo::Unknown, None); - let dummy_type_param = TypeParameter { - type_id: initial_type_id, - initial_type_id, - name_ident: Ident::new_with_override( - "_".into(), - pat.span().clone(), - ), - trait_constraints: vec![], - trait_constraints_span: Span::dummy(), - is_from_parent: false, - }; - let initial_type_id = engines.te().insert( - engines, - TypeInfo::Placeholder(dummy_type_param), - None, - ); - TypeArgument { - type_id: initial_type_id, - initial_type_id, - call_path_tree: None, - span: Span::dummy(), - } - }) - .collect(), - ), - tuple_name.span().source_id(), + pat_tuple + .clone() + .into_inner() + .into_iter() + .map(|pat| { + // Since these placeholders are generated specifically for checks, the `pat.span()` must not + // necessarily point to a "_" string in code. E.g., in this example: + // let (a, _) = (0, 0); + // The first `pat.span()` will point to "a", while the second one will indeed point to "_". + // However, their `pat.span()`s will always be in the source file in which the placeholder + // is logically situated. + engines.te().new_placeholder(TypeParameter::new_placeholder( + engines.te().new_unknown(), + pat.span(), + )) + }) + .collect(), ); + + // The type argument is a tuple of place holders of unknowns pointing to + // the tuple pattern. TypeArgument { type_id, initial_type_id: type_id, - span: tuple_name.span(), + span: pat_tuple.span(), call_path_tree: None, } }; @@ -4313,14 +4283,14 @@ fn ty_to_type_parameter( ) -> Result { let type_engine = engines.te(); - let name_ident = match ty { + let name = match ty { Ty::Path(path_type) => path_type_to_ident(context, handler, path_type)?, Ty::Infer { underscore_token } => { - let unknown_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let unknown_type = type_engine.new_unknown(); return Ok(TypeParameter { type_id: unknown_type, initial_type_id: unknown_type, - name_ident: underscore_token.into(), + name: underscore_token.into(), trait_constraints: Vec::default(), trait_constraints_span: Span::dummy(), is_from_parent: false, @@ -4328,25 +4298,18 @@ fn ty_to_type_parameter( } Ty::Tuple(..) => panic!("tuple types are not allowed in this position"), Ty::Array(..) => panic!("array types are not allowed in this position"), - Ty::StringSlice(..) => panic!("str types are not allowed in this position"), - Ty::StringArray { .. } => panic!("str types are not allowed in this position"), + Ty::StringSlice(..) => panic!("str slice types are not allowed in this position"), + Ty::StringArray { .. } => panic!("str array types are not allowed in this position"), Ty::Ptr { .. } => panic!("__ptr types are not allowed in this position"), Ty::Slice { .. } => panic!("__slice types are not allowed in this position"), Ty::Ref { .. } => panic!("ref types are not allowed in this position"), Ty::Never { .. } => panic!("never types are not allowed in this position"), }; - let custom_type = type_engine.insert( - engines, - TypeInfo::Custom { - qualified_call_path: name_ident.clone().into(), - type_arguments: None, - }, - name_ident.span().source_id(), - ); + let custom_type = type_engine.new_custom_from_name(engines, name.clone()); Ok(TypeParameter { type_id: custom_type, initial_type_id: custom_type, - name_ident, + name, trait_constraints: Vec::new(), trait_constraints_span: Span::dummy(), is_from_parent: false, diff --git a/sway-core/src/type_system/ast_elements/binding.rs b/sway-core/src/type_system/ast_elements/binding.rs index 9a4c7c1dd43..3ea45397a51 100644 --- a/sway-core/src/type_system/ast_elements/binding.rs +++ b/sway-core/src/type_system/ast_elements/binding.rs @@ -238,7 +238,7 @@ impl TypeBinding> { EnforceTypeArguments::No, Some(&type_info_prefix), ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); Ok(type_id) } @@ -309,7 +309,7 @@ impl TypeCheckTypeBinding for TypeBinding { > { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); - let engines = ctx.engines(); + // Grab the declaration. let unknown_decl = ctx .resolve_call_path_with_visibility_check(handler, &self.inner)? @@ -339,9 +339,7 @@ impl TypeCheckTypeBinding for TypeBinding { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); } } } @@ -411,11 +409,7 @@ impl TypeCheckTypeBinding for TypeBinding { new_copy, decl_engine.get_parsed_decl_id(&struct_id).as_ref(), ); - let type_id = type_engine.insert( - engines, - TypeInfo::Struct(*new_struct_ref.id()), - new_struct_ref.span().source_id(), - ); + let type_id = type_engine.insert_struct(engines, *new_struct_ref.id()); Ok((new_struct_ref, Some(type_id), None)) } } @@ -464,11 +458,7 @@ impl TypeCheckTypeBinding for TypeBinding { // Insert the new copy into the declaration engine. let new_enum_ref = decl_engine.insert(new_copy, decl_engine.get_parsed_decl_id(&enum_id).as_ref()); - let type_id = type_engine.insert( - engines, - TypeInfo::Enum(*new_enum_ref.id()), - new_enum_ref.span().source_id(), - ); + let type_id = type_engine.insert_enum(engines, *new_enum_ref.id()); Ok((new_enum_ref, Some(type_id), Some(unknown_decl))) } } diff --git a/sway-core/src/type_system/ast_elements/length.rs b/sway-core/src/type_system/ast_elements/length.rs index 3decee557fd..913e9ce38c6 100644 --- a/sway-core/src/type_system/ast_elements/length.rs +++ b/sway-core/src/type_system/ast_elements/length.rs @@ -1,6 +1,17 @@ use sway_types::{span::Span, Spanned}; -/// Describes a fixed length for types that needs it such as arrays and strings +/// Describes a fixed length for types that need it, e.g., [crate::TypeInfo::Array]. +/// +/// Optionally, if the length is coming from a literal in code, the [Length] +/// also keeps the [Span] of that literal. In that case, we say that the length +/// is annotated. +/// +/// E.g., in this example, the two lengths coming from the literal `3` will +/// have two different spans pointing to the two different strings "3": +/// +/// ```ignore +/// fn copy(a: [u64;3], b: [u64;3]) +/// ``` #[derive(Debug, Clone, Hash)] pub struct Length { val: usize, @@ -8,13 +19,30 @@ pub struct Length { } impl Length { - pub fn new(val: usize, span: Span) -> Self { - Length { val, span } + /// Creates a new [Length] without span annotation. + pub fn new(val: usize) -> Self { + Length { + val, + span: Span::dummy(), + } + } + + /// Creates a new [Length] from a numeric literal. + /// The `span` will be set to the span of the numeric literal. + pub fn from_numeric_literal(val: usize, numeric_literal_span: Span) -> Self { + Length { + val, + span: numeric_literal_span, + } } pub fn val(&self) -> usize { self.val } + + pub fn is_annotated(&self) -> bool { + !self.span.is_dummy() + } } impl Spanned for Length { diff --git a/sway-core/src/type_system/ast_elements/trait_constraint.rs b/sway-core/src/type_system/ast_elements/trait_constraint.rs index e91411595bb..cfe0b41bcb1 100644 --- a/sway-core/src/type_system/ast_elements/trait_constraint.rs +++ b/sway-core/src/type_system/ast_elements/trait_constraint.rs @@ -170,11 +170,7 @@ impl TraitConstraint { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| { - ctx.engines - .te() - .insert(ctx.engines(), TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| ctx.engines.te().id_of_error_recovery(err)); } Ok(()) diff --git a/sway-core/src/type_system/ast_elements/type_argument.rs b/sway-core/src/type_system/ast_elements/type_argument.rs index 1476fe6627b..bdddde93ad4 100644 --- a/sway-core/src/type_system/ast_elements/type_argument.rs +++ b/sway-core/src/type_system/ast_elements/type_argument.rs @@ -2,15 +2,60 @@ use crate::{engine_threading::*, language::CallPathTree, type_system::priv_prelu use std::{cmp::Ordering, fmt, hash::Hasher}; use sway_types::{Span, Spanned}; +/// [TypeArgument] can be seen as an "annotated reference" to a [TypeInfo]. +/// It holds the [TypeArgument::type_id] which is the actual "reference" +/// to the type, as well as an additional information about that type, +/// called the annotation. +/// +/// If a [TypeArgument] only references a [TypeInfo] and is considered as +/// not being annotated, its `initial_type_id` must be the same as `type_id`, +/// its `span` must be [Span::dummy] and its `call_path_tree` must be `None`. +/// +/// The annotations are ignored when calculating the [TypeArgument]'s hash +/// (with engines) and equality (with engines). #[derive(Debug, Clone)] pub struct TypeArgument { + /// The [TypeId] of the "referenced" [TypeInfo]. pub type_id: TypeId, + /// Denotes the initial type that was referenced before the type + /// unification, monomorphization, or replacement of [TypeInfo::Custom]s. pub initial_type_id: TypeId, + /// The [Span] related in code to the [TypeInfo] represented by this + /// [TypeArgument]. This information is mostly used by the LSP and it + /// differs from use case to use case. + /// + /// E.g., in the following example: + /// + /// ```ignore + /// let a: [u64;2] = [0, 0]; + /// let b: [u64;2] = [1, 1]; + /// ``` + /// + /// the type arguments of the [TypeInfo::Array]s of `a` and `b` will + /// have two different spans pointing to two different strings "u64". + /// On the other hand, the two [TypeInfo::Array]s describing the + /// two instances `[0, 0]`, and `[1, 1]` will have neither the array + /// type span set, nor the length span, which means they will not be + /// annotated. pub span: Span, pub call_path_tree: Option, } +impl TypeArgument { + /// Returns true if `self` is annotated by having either + /// its [Self::initial_type_id] different from [Self::type_id], + /// or [Self::span] different from [Span::dummy] + /// or [Self::call_path_tree] different from `None`. + pub fn is_annotated(&self) -> bool { + self.type_id != self.initial_type_id + || self.call_path_tree.is_some() + || !self.span.is_dummy() + } +} + impl From for TypeArgument { + /// Creates *a non-annotated* [TypeArgument] that points + /// to the [TypeInfo] represented by the `type_id`. fn from(type_id: TypeId) -> Self { TypeArgument { type_id, @@ -102,7 +147,7 @@ impl From<&TypeParameter> for TypeArgument { TypeArgument { type_id: type_param.type_id, initial_type_id: type_param.initial_type_id, - span: type_param.name_ident.span(), + span: type_param.name.span(), call_path_tree: None, } } diff --git a/sway-core/src/type_system/ast_elements/type_parameter.rs b/sway-core/src/type_system/ast_elements/type_parameter.rs index 068f486b79f..cdd656aaef0 100644 --- a/sway-core/src/type_system/ast_elements/type_parameter.rs +++ b/sway-core/src/type_system/ast_elements/type_parameter.rs @@ -12,7 +12,7 @@ use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, }; -use sway_types::{ident::Ident, span::Span, Spanned}; +use sway_types::{ident::Ident, span::Span, BaseIdent, Spanned}; use std::{ cmp::Ordering, @@ -21,21 +21,47 @@ use std::{ hash::{Hash, Hasher}, }; -#[derive(Clone)] +/// [TypeParameter] describes a generic type parameter, including its +/// monomorphized version. It holds the `name` of the parameter, its +/// `type_id`, and the `initial_type_id`, as well as an additional +/// information about that type parameter, called the annotation. +/// +/// If a [TypeParameter] is considered as not being annotated, +/// its `initial_type_id` must be same as `type_id`, its +/// `trait_constraints_span` must be [Span::dummy] +/// and its `is_from_parent` must be false. +/// +/// The annotations are ignored when calculating the [TypeParameter]'s hash +/// (with engines) and equality (with engines). +#[derive(Debug, Clone)] pub struct TypeParameter { pub type_id: TypeId, + /// Denotes the initial type represented by the [TypeParameter], before + /// unification, monomorphization, or replacement of [TypeInfo::Custom]s. pub(crate) initial_type_id: TypeId, - pub name_ident: Ident, + pub name: Ident, pub(crate) trait_constraints: Vec, pub(crate) trait_constraints_span: Span, pub(crate) is_from_parent: bool, } +impl TypeParameter { + /// Returns true if `self` is annotated by heaving either + /// its [Self::initial_type_id] different from [Self::type_id], + /// or [Self::trait_constraints_span] different from [Span::dummy] + /// or [Self::is_from_parent] different from false. + pub fn is_annotated(&self) -> bool { + self.type_id != self.initial_type_id + || self.is_from_parent + || !self.trait_constraints_span.is_dummy() + } +} + impl HashWithEngines for TypeParameter { fn hash(&self, state: &mut H, engines: &Engines) { let TypeParameter { type_id, - name_ident, + name, trait_constraints, // these fields are not hashed because they aren't relevant/a // reliable source of obj v. obj distinction @@ -45,7 +71,7 @@ impl HashWithEngines for TypeParameter { } = self; let type_engine = engines.te(); type_engine.get(*type_id).hash(state, engines); - name_ident.hash(state); + name.hash(state); trait_constraints.hash(state, engines); } } @@ -57,7 +83,7 @@ impl PartialEqWithEngines for TypeParameter { type_engine .get(self.type_id) .eq(&type_engine.get(other.type_id), ctx) - && self.name_ident == other.name_ident + && self.name == other.name && self.trait_constraints.eq(&other.trait_constraints, ctx) } } @@ -66,7 +92,7 @@ impl OrdWithEngines for TypeParameter { fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering { let TypeParameter { type_id: lti, - name_ident: ln, + name: ln, trait_constraints: ltc, // these fields are not compared because they aren't relevant/a // reliable source of obj v. obj distinction @@ -76,7 +102,7 @@ impl OrdWithEngines for TypeParameter { } = self; let TypeParameter { type_id: rti, - name_ident: rn, + name: rn, trait_constraints: rtc, // these fields are not compared because they aren't relevant/a // reliable source of obj v. obj distinction @@ -106,7 +132,7 @@ impl SubstTypes for TypeParameter { impl Spanned for TypeParameter { fn span(&self) -> Span { - self.name_ident.span() + self.name.span() } } @@ -118,7 +144,7 @@ impl IsConcrete for TypeParameter { impl DebugWithEngines for TypeParameter { fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result { - write!(f, "{}", self.name_ident)?; + write!(f, "{}", self.name)?; if !self.trait_constraints.is_empty() { write!( f, @@ -134,37 +160,56 @@ impl DebugWithEngines for TypeParameter { } } -impl fmt::Debug for TypeParameter { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let _ = write!(f, "{}: {:?}", self.name_ident, self.type_id); - for c in &self.trait_constraints { - let _ = write!(f, "+ {:?}", c.trait_name); - } - write!(f, "") - } -} - impl TypeParameter { - pub(crate) fn new_self_type(engines: &Engines, span: Span) -> TypeParameter { + /// Creates a new [TypeParameter] that represents a `Self` type. + /// The returned type parameter will have its [TypeParameter::name] + /// set to "Self" with the provided `use_site_span`. + /// + /// `Self` type is a [TypeInfo::UnknownGeneric] and therefore [TypeParameter::type_id]s + /// will be set to newly created unknown generic type. + /// + /// Note that the span in general does not point to a reserved word "Self" in + /// the source code, nor is related to it. The `Self` type represents the type + /// in `impl`s and does not necessarily relate to the "Self" keyword in code. + /// + /// Therefore, *the span must always point to a location in the source file in which + /// the particular `Self` type is, e.g., being declared or implemented*. + pub(crate) fn new_self_type(engines: &Engines, use_site_span: Span) -> TypeParameter { let type_engine = engines.te(); - let name = Ident::new_with_override("Self".into(), span.clone()); - let type_id = type_engine.insert( - engines, - TypeInfo::UnknownGeneric { - name: name.clone(), - trait_constraints: VecSet(vec![]), - parent: None, - is_from_type_parameter: true, - }, - span.source_id(), - ); + let (type_id, name) = type_engine.new_unknown_generic_self(use_site_span, true); TypeParameter { type_id, initial_type_id: type_id, - name_ident: name, + name, trait_constraints: vec![], - trait_constraints_span: span, + trait_constraints_span: Span::dummy(), + is_from_parent: false, + } + } + + /// Creates a new [TypeParameter] specifically to be used as the type parameter + /// for a [TypeInfo::Placeholder]. The returned type parameter will have its + /// [TypeParameter::name] set to "_" with the provided `placeholder_or_use_site_span` + /// and its [TypeParameter::type_id]s set to the `type_id`. + /// + /// Note that in the user written code, the span will always point to the place in + /// the source code where "_" is located. In the compiler generated code that is not always the case + /// be the case. For cases when the span does not point to "_" see the comments + /// in the usages of this method. + /// + /// However, *the span must always point to a location in the source file in which + /// the particular placeholder is considered to be used*. + pub(crate) fn new_placeholder( + type_id: TypeId, + placeholder_or_use_site_span: Span, + ) -> TypeParameter { + TypeParameter { + type_id, + initial_type_id: type_id, + name: BaseIdent::new_with_override("_".into(), placeholder_or_use_site_span), + trait_constraints: vec![], + trait_constraints_span: Span::dummy(), is_from_parent: false, } } @@ -176,11 +221,11 @@ impl TypeParameter { ) { let type_parameter_decl = ty::TyDecl::GenericTypeForFunctionScope(ty::GenericTypeForFunctionScope { - name: self.name_ident.clone(), + name: self.name.clone(), type_id: self.type_id, }); - let name_a = Ident::new_with_override("self".into(), self.name_ident.span()); - let name_b = Ident::new_with_override("Self".into(), self.name_ident.span()); + let name_a = Ident::new_with_override("self".into(), self.name.span()); + let name_b = Ident::new_with_override("Self".into(), self.name.span()); let _ = ctx.insert_symbol(handler, name_a, type_parameter_decl.clone()); let _ = ctx.insert_symbol(handler, name_b, type_parameter_decl); } @@ -266,11 +311,10 @@ impl TypeParameter { type_parameter: TypeParameter, ) -> Result { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let TypeParameter { initial_type_id, - name_ident, + name, trait_constraints, trait_constraints_span, is_from_parent, @@ -296,19 +340,15 @@ impl TypeParameter { // Create type id and type parameter before type checking trait constraints. // This order is required because a trait constraint may depend on its own type parameter. - let type_id = type_engine.insert( - engines, - TypeInfo::UnknownGeneric { - name: name_ident.clone(), - trait_constraints: VecSet(trait_constraints_with_supertraits.clone()), - parent, - is_from_type_parameter: true, - }, - name_ident.span().source_id(), + let type_id = type_engine.new_unknown_generic( + name.clone(), + VecSet(trait_constraints_with_supertraits.clone()), + parent, + true, ); let type_parameter = TypeParameter { - name_ident: name_ident.clone(), + name, type_id, initial_type_id, trait_constraints, @@ -360,15 +400,11 @@ impl TypeParameter { type_engine.replace( ctx.engines(), type_parameter.type_id, - TypeSourceInfo { - type_info: TypeInfo::UnknownGeneric { - name: type_parameter.name_ident.clone(), - trait_constraints: VecSet(trait_constraints_with_supertraits.clone()), - parent, - is_from_type_parameter: true, - } - .into(), - source_id: type_parameter.name_ident.span().source_id().copied(), + TypeInfo::UnknownGeneric { + name: type_parameter.name.clone(), + trait_constraints: VecSet(trait_constraints_with_supertraits.clone()), + parent, + is_from_type_parameter: true, }, ); @@ -405,7 +441,7 @@ impl TypeParameter { ) -> Result<(), ErrorEmitted> { let Self { is_from_parent, - name_ident, + name, type_id, .. } = self; @@ -418,7 +454,7 @@ impl TypeParameter { .module(ctx.engines()) .current_items() .symbols - .get(name_ident) + .get(name) .unwrap(); match sy.expect_typed_ref() { @@ -440,15 +476,11 @@ impl TypeParameter { ctx.engines.te().replace( ctx.engines(), *type_id, - TypeSourceInfo { - type_info: TypeInfo::UnknownGeneric { - name: name.clone(), - trait_constraints: trait_constraints.clone(), - parent: Some(*parent_type_id), - is_from_type_parameter: *is_from_type_parameter, - } - .into(), - source_id: name.span().source_id().copied(), + TypeInfo::UnknownGeneric { + name: name.clone(), + trait_constraints: trait_constraints.clone(), + parent: Some(*parent_type_id), + is_from_type_parameter: *is_from_type_parameter, }, ); } @@ -456,7 +488,7 @@ impl TypeParameter { _ => { handler.emit_err(CompileError::Internal( "Unexpected TyDeclaration for TypeParameter.", - self.name_ident.span(), + self.name.span(), )); } } @@ -466,10 +498,10 @@ impl TypeParameter { // declaration. let type_parameter_decl = ty::TyDecl::GenericTypeForFunctionScope(ty::GenericTypeForFunctionScope { - name: name_ident.clone(), + name: name.clone(), type_id: *type_id, }); - ctx.insert_symbol(handler, name_ident.clone(), type_parameter_decl) + ctx.insert_symbol(handler, name.clone(), type_parameter_decl) .ok(); Ok(()) diff --git a/sway-core/src/type_system/engine.rs b/sway-core/src/type_system/engine.rs index 7dea1cbb281..8c97dd475af 100644 --- a/sway-core/src/type_system/engine.rs +++ b/sway-core/src/type_system/engine.rs @@ -2,25 +2,140 @@ use crate::{ concurrent_slab::{ConcurrentSlab, ListDisplay}, decl_engine::*, engine_threading::*, + language::{ + parsed::{EnumDeclaration, StructDeclaration}, + ty::{TyEnumDecl, TyExpression, TyStructDecl}, + QualifiedCallPath, + }, type_system::priv_prelude::*, }; use core::fmt::Write; use hashbrown::{hash_map::RawEntryMut, HashMap}; use parking_lot::RwLock; -use std::{sync::Arc, time::Instant}; +use std::{ + hash::{BuildHasher, Hash, Hasher}, + sync::Arc, + time::Instant, +}; use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, type_error::TypeError, }; -use sway_types::{integer_bits::IntegerBits, span::Span, ProgramId, SourceId}; +use sway_types::{integer_bits::IntegerBits, span::Span, Ident, ProgramId, SourceId, Spanned}; use super::unify::unifier::UnifyKind; +/// To be able to garbage-collect [TypeInfo]s from the [TypeEngine] +/// we need to track which types need to be GCed when a particular +/// module, represented by its source id, is GCed. [TypeSourceInfo] +/// encapsulates this information. +/// +/// For types that should never be GCed the `source_id` must be `None`. +/// +/// The concrete logic of assigning `source_id`s to `type_info`s is +/// given in the [TypeEngine::get_type_fallback_source_id]. +// TODO: This logic will be further improved when https://github.com/FuelLabs/sway/issues/6603 +// is implemented (Optimize `TypeEngine` for garbage collection). +#[derive(Debug, Default, Clone)] +struct TypeSourceInfo { + type_info: Arc, + source_id: Option, +} + +impl TypeSourceInfo { + /// Returns true if the `self` would be equal to another [TypeSourceInfo] + /// created from `type_info` and `source_id`. + /// + /// This method allows us to test equality "upfront", without the need to + /// create a new [TypeSourceInfo] which would require a heap allocation + /// of a new [TypeInfo]. + pub(crate) fn equals( + &self, + type_info: &TypeInfo, + source_id: &Option, + ctx: &PartialEqWithEnginesContext, + ) -> bool { + &self.source_id == source_id && self.type_info.eq(type_info, ctx) + } +} + +impl HashWithEngines for TypeSourceInfo { + fn hash(&self, state: &mut H, engines: &Engines) { + self.type_info.hash(state, engines); + self.source_id.hash(state); + } +} + +impl EqWithEngines for TypeSourceInfo {} +impl PartialEqWithEngines for TypeSourceInfo { + fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool { + self.equals(&other.type_info, &other.source_id, ctx) + } +} + +/// Holds the singleton instances of [TypeSourceInfo]s of *replaceable types* that, +/// although being inserted anew into the [TypeEngine], all share the single definition. +/// This means that, e.g., all the different [TypeEngine::slab] entries representing +/// the, e.g., [TypeInfo::Unknown] will point to the same singleton instance +/// of the corresponding [TypeSourceInfo]. +#[derive(Debug, Clone)] +struct SingletonTypeSourceInfos { + /// The single instance of the [TypeSourceInfo] + /// representing the [TypeInfo::Unknown] replaceable type. + unknown: Arc, + /// The single instance of the [TypeSourceInfo] + /// representing the [TypeInfo::Numeric] replaceable type. + numeric: Arc, +} + +/// Holds the instances of [TypeInfo]s and allows exchanging them for [TypeId]s. +/// Supports LSP garbage collection of unused [TypeInfo]s assigned to a particular [SourceId]. +/// +/// ## Intended Usage +/// Inserting [TypeInfo]s into the type engine returns a [TypeId] that can later be used +/// to get the same [TypeInfo] by using the [TypeEngine::get] method. +/// +/// Properly using the various inserting methods is crucial for the optimal work of the type engine. +/// +/// These methods are grouped by the following convention and are intended to be used in the +/// order of precedence given below: +/// - `id_of_`: methods that always return the same [TypeId] for a type. +/// These methods, when inlined, compile to constant [TypeId]s. +/// - `new_`: methods that always return a new [TypeId] for a type. +/// - `insert_[_]`: methods that might insert a new type into the engine, +/// and return a new [TypeId], but also reuse an existing [TypeInfo] and return an existing [TypeId]. +/// - `insert`: the fallback method that should be used only in cases when the type is not known +/// at the call site. +/// +/// ## Internal Implementation +/// [TypeInfo]s are stored in a private [TypeSourceInfo] structure that binds them with a [SourceId] +/// of the module in which they are used. Those [TypeSourceInfo]s are referenced from the `slab`. +/// The actual [TypeId] of a [TypeInfo] is just an index in the `slab`. +/// +/// The engine attempts to maximize the reuse of [TypeSourceInfo]s by holding _shareable types_ +/// (see: [Self::is_type_shareable]) in the `shareable_types` hash map. +/// +/// TODO: Note that the reuse currently happens on the level of [TypeSourceInfo]s, and not [TypeInfo]s. +/// This is not optimal and will be improved in https://github.com/FuelLabs/sway/issues/6603. +/// Also note that because of that, having [TypeInfo] stored in `Arc` within the [TypeSourceInfo] +/// does not bring any real benefits. +/// +/// The implementation of the type engine is primarily directed with the goal of maximizing the +/// reuse of the [TypeSourceInfo]s while at the same time having the [TypeInfo]s bound to [SourceId]s +/// of their use site, so that they can be garbage collected. +/// +/// TODO: Note that the assignment of [SourceId]s to [TypeInfo]s is currently not as optimal as it +/// can be. This will be improved in https://github.com/FuelLabs/sway/issues/6603. #[derive(Debug)] pub struct TypeEngine { slab: ConcurrentSlab, - id_map: RwLock>, + /// Holds [TypeId]s of [TypeSourceInfo]s of shareable types (see: [Self::is_type_shareable]). + /// [TypeSourceInfo]s of shareable types can be reused if the type is used more + /// then once. In that case, for every usage, instead of inserting a new [TypeSourceInfo] instance + /// into the [Self::slab], the [TypeId] of an existing instance is returned. + shareable_types: RwLock, TypeId>>, + singleton_types: RwLock, unifications: ConcurrentSlab, last_replace: RwLock, } @@ -40,12 +155,28 @@ pub(crate) struct Unification { impl Default for TypeEngine { fn default() -> Self { - TypeEngine { + let singleton_types = SingletonTypeSourceInfos { + unknown: TypeSourceInfo { + type_info: TypeInfo::Unknown.into(), + source_id: None, + } + .into(), + numeric: TypeSourceInfo { + type_info: TypeInfo::Numeric.into(), + source_id: None, + } + .into(), + }; + + let mut te = TypeEngine { slab: Default::default(), - id_map: Default::default(), + shareable_types: Default::default(), + singleton_types: RwLock::new(singleton_types), unifications: Default::default(), last_replace: RwLock::new(Instant::now()), - } + }; + te.insert_shareable_built_in_types(); + te } } @@ -53,14 +184,614 @@ impl Clone for TypeEngine { fn clone(&self) -> Self { TypeEngine { slab: self.slab.clone(), - id_map: RwLock::new(self.id_map.read().clone()), + shareable_types: RwLock::new(self.shareable_types.read().clone()), + singleton_types: RwLock::new(self.singleton_types.read().clone()), unifications: self.unifications.clone(), last_replace: RwLock::new(*self.last_replace.read()), } } } +/// Generates: +/// - `id_of_` methods for every provided shareable built-in type. +/// - `insert_shareable_built_in_types` method for initial creation of built-in types within the [TypeEngine]. +/// - `get_shareable_built_in_type_id` method for potential retrieval of built-in types in the [TypeEngine::insert] method. +/// +/// Note that, when invoking the macro, the `unit` and the [TypeInfo::ErrorRecovery] types *must not be provided in the list*. +/// The shareable `unit` type requires a special treatment within the macro, because it is modeled +/// as [TypeInfo::Tuple] with zero elements and not as a separate [TypeInfo] variant. +/// The [TypeInfo::ErrorRecovery], although being an enum variant with the parameter (the [ErrorEmitted] proof), is +/// actually a single type because all the [ErrorEmitted] proofs are the same. +/// This special case is also handled within the macro. +/// +/// Unfortunately, due to limitations of Rust's macro-by-example, the [TypeInfo] must be +/// provided twice during the macro invocation, once as an expression `expr` and once as a pattern `pat`. +/// +/// The macro recursively creates the `id_of_` methods in order to get the proper `usize` value +/// generated, which corresponds to the index of those types within the slab. +macro_rules! type_engine_shareable_built_in_types { + // The base recursive case. + (@step $_idx:expr,) => {}; + + // The actual recursion step that generates the `id_of_` functions. + (@step $idx:expr, ($ty_name:ident, $ti:expr, $ti_pat:pat), $(($tail_ty_name:ident, $tail_ti:expr, $tail_ti_pat:pat),)*) => { + paste::paste! { + pub(crate) const fn [](&self) -> TypeId { + TypeId::new($idx) + } + } + + type_engine_shareable_built_in_types!(@step $idx + 1, $(($tail_ty_name, $tail_ti, $tail_ti_pat),)*); + }; + + // The entry point. Invoking the macro matches this arm. + ($(($ty_name:ident, $ti:expr, $ti_pat:pat),)*) => { + // The `unit` type is a special case. It will be inserted in the slab as the first type. + pub(crate) const fn id_of_unit(&self) -> TypeId { + TypeId::new(0) + } + + // The error recovery type is a special case. It will be inserted in the slab as the second type. + // To preserve the semantics of the `TypeInfo::ErrorRecovery(ErrorEmitted)`, we still insist on + // providing the proof of the error being emitted, although that proof is actually + // not needed to obtain the type id, nor is used within this method at all. + #[allow(unused_variables)] + pub(crate) const fn id_of_error_recovery(&self, error_emitted: ErrorEmitted) -> TypeId { + TypeId::new(1) + } + + // Generate the remaining `id_of_` methods. We start counting the indices from 2. + type_engine_shareable_built_in_types!(@step 2, $(($ty_name, $ti, $ti_pat),)*); + + // Generate the method that initially inserts the built-in shareable types into the `slab` in the right order. + // + // Note that we are inserting the types **only into the `slab`, but not into the `shareable_types`**, + // although they should, by definition, be in the `shareable_types` as well. + // + // What is the reason for not inserting them into the `shareable_types`? + // + // To insert them into the `shareable_types` we need `Engines` to be able to calculate + // the hash and equality with engines, and method is supposed be called internally during the creation + // of the `TypeEngine`. At that moment, we are creating a single, isolated engine, and do not + // have all the engines available. The only way to have it called with all the engines, is + // to do it when `Engines` are created. But this would mean that we cannot have a semantically + // valid `TypeEngine` created in isolation, without the `Engines`, which would be a problematic + // design that breaks cohesion and creates unexpected dependency. + // + // Note that having the built-in shareable types initially inserted only in the `slab` does + // not cause any issues with type insertion and retrieval. The `id_of_` methods return + // indices that are compile-time constants and there is no need for `shareable_types` access. + // Also, calling `insert` with built-in shareable types has an optimized path which will redirect + // to `id_of_` methods, again bypassing the `shareable_types`. + // + // The only negligible small "penalty" comes during replacements of replaceable types, + // where a potential replacement with a built-in shareable type will create a separate instance + // of that built-in type and add it to `shareable_types`. + fn insert_shareable_built_in_types(&mut self) { + use TypeInfo::*; + + let tsi = TypeSourceInfo { + type_info: Tuple(vec![]).into(), + source_id: None, + }; + self.slab.insert(tsi); + + // For the `ErrorRecovery`, we need an `ErrorEmitted` instance. + // All of its instances are the same, so we will use, or perhaps misuse, + // the `Handler::cancel` method here to obtain an instance. + let tsi = TypeSourceInfo { + type_info: ErrorRecovery(crate::Handler::default().cancel()).into(), + source_id: None, + }; + self.slab.insert(tsi); + + $( + let tsi = TypeSourceInfo { + type_info: $ti.into(), + source_id: None, + }; + self.slab.insert(tsi); + )* + } + + /// Returns the [TypeId] of the `type_info` only if the type info is + /// a shareable built-in type, otherwise `None`. + /// + /// For a particular shareable built-in type, the method guarantees to always + /// return the same, existing [TypeId]. + fn get_shareable_built_in_type_id(&self, type_info: &TypeInfo) -> Option { + paste::paste! { + use TypeInfo::*; + match type_info { + Tuple(v) if v.is_empty() => Some(self.id_of_unit()), + // Here we also "pass" the dummy value obtained from `Handler::cancel` which will be + // optimized away. + ErrorRecovery(_) => Some(self.id_of_error_recovery(crate::Handler::default().cancel())), + $( + $ti_pat => Some(self.[]()), + )* + _ => None + } + } + } + + /// Returns true if the type represented by the `type_info` + /// is a shareable built-in type. + fn is_shareable_built_in_type(&self, type_info: &TypeInfo) -> bool { + use TypeInfo::*; + match type_info { + Tuple(v) if v.is_empty() => true, + // Here we also "pass" the dummy value obtained from `Handler::cancel` which will be + // optimized away. + ErrorRecovery(_) => true, + $( + $ti_pat => true, + )* + _ => false + } + } + } +} + impl TypeEngine { + type_engine_shareable_built_in_types!( + (never, Never, Never), + (string_slice, StringSlice, StringSlice), + ( + u8, + UnsignedInteger(IntegerBits::Eight), + UnsignedInteger(IntegerBits::Eight) + ), + ( + u16, + UnsignedInteger(IntegerBits::Sixteen), + UnsignedInteger(IntegerBits::Sixteen) + ), + ( + u32, + UnsignedInteger(IntegerBits::ThirtyTwo), + UnsignedInteger(IntegerBits::ThirtyTwo) + ), + ( + u64, + UnsignedInteger(IntegerBits::SixtyFour), + UnsignedInteger(IntegerBits::SixtyFour) + ), + ( + u256, + UnsignedInteger(IntegerBits::V256), + UnsignedInteger(IntegerBits::V256) + ), + (bool, Boolean, Boolean), + (b256, B256, B256), + (contract, Contract, Contract), + (raw_ptr, RawUntypedPtr, RawUntypedPtr), + (raw_slice, RawUntypedSlice, RawUntypedSlice), + ); + + /// Inserts a new [TypeInfo::Unknown] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::Unknown] is an always replaceable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_unknown(&self) -> TypeId { + TypeId::new( + self.slab + .insert_arc(self.singleton_types.read().unknown.clone()), + ) + } + + /// Inserts a new [TypeInfo::Numeric] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::Numeric] is an always replaceable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_numeric(&self) -> TypeId { + TypeId::new( + self.slab + .insert_arc(self.singleton_types.read().numeric.clone()), + ) + } + + /// Inserts a new [TypeInfo::Placeholder] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::Placeholder] is an always replaceable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_placeholder(&self, type_parameter: TypeParameter) -> TypeId { + self.new_placeholder_impl(TypeInfo::Placeholder(type_parameter)) + } + + fn new_placeholder_impl(&self, placeholder: TypeInfo) -> TypeId { + let source_id = self.get_placeholder_fallback_source_id(&placeholder); + let tsi = TypeSourceInfo { + type_info: placeholder.into(), + source_id, + }; + TypeId::new(self.slab.insert(tsi)) + } + + /// Inserts a new [TypeInfo::UnknownGeneric] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::UnknownGeneric] is an always replaceable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_unknown_generic( + &self, + name: Ident, + trait_constraints: VecSet, + parent: Option, + is_from_type_parameter: bool, + ) -> TypeId { + self.new_unknown_generic_impl(TypeInfo::UnknownGeneric { + name, + trait_constraints, + parent, + is_from_type_parameter, + }) + } + + fn new_unknown_generic_impl(&self, unknown_generic: TypeInfo) -> TypeId { + let source_id = Self::get_unknown_generic_fallback_source_id(&unknown_generic); + let tsi = TypeSourceInfo { + type_info: unknown_generic.into(), + source_id, + }; + TypeId::new(self.slab.insert(tsi)) + } + + /// Inserts a new [TypeInfo::UnknownGeneric] into the [TypeEngine] + /// that represents a `Self` type and returns its [TypeId]. + /// The unknown generic `name` [Ident] will be set to "Self" with the provided `use_site_span`. + /// + /// Note that the span in general does not point to a reserved word "Self" in + /// the source code, nor is related to it. The `Self` type represents the type + /// in `impl`s and does not necessarily relate to the "Self" keyword in code. + /// + /// Therefore, *the span must always point to a location in the source file in which + /// the particular `Self` type is, e.g., being declared or implemented*. + /// + /// Returns the [TypeId] and the [Ident] set to "Self" and the provided `use_site_span`. + pub(crate) fn new_unknown_generic_self( + &self, + use_site_span: Span, + is_from_type_parameter: bool, + ) -> (TypeId, Ident) { + let name = Ident::new_with_override("Self".into(), use_site_span); + let type_id = + self.new_unknown_generic(name.clone(), VecSet(vec![]), None, is_from_type_parameter); + (type_id, name) + } + + /// Inserts a new [TypeInfo::Enum] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable enum type + /// that corresponds to the enum given by the `decl_id`. + pub(crate) fn insert_enum(&self, engines: &Engines, decl_id: DeclId) -> TypeId { + let decl = engines.de().get_enum(&decl_id); + let source_id = Self::get_enum_fallback_source_id(&decl); + let is_shareable_type = self.is_shareable_enum(engines, &decl); + let type_info = TypeInfo::Enum(decl_id); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::Struct] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable struct type + /// that corresponds to the struct given by the `decl_id`. + pub(crate) fn insert_struct(&self, engines: &Engines, decl_id: DeclId) -> TypeId { + let decl = engines.de().get_struct(&decl_id); + let source_id = Self::get_struct_fallback_source_id(&decl); + let is_shareable_type = self.is_shareable_struct(engines, &decl); + let type_info = TypeInfo::Struct(decl_id); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::Tuple] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable tuple type + /// that corresponds to the tuple given by the `elements`. + pub(crate) fn insert_tuple(&self, engines: &Engines, elements: Vec) -> TypeId { + let source_id = self.get_tuple_fallback_source_id(&elements); + let is_shareable_type = self.is_shareable_tuple(engines, &elements); + let type_info = TypeInfo::Tuple(elements); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Same as [Self::insert_tuple], but intended to be used mostly in the code generation, + /// where the tuple elements are non-annotated [TypeArgument]s that contain + /// only the [TypeId]s provided in the `elements`. + pub(crate) fn insert_tuple_without_annotations( + &self, + engines: &Engines, + elements: Vec, + ) -> TypeId { + self.insert_tuple( + engines, + elements.into_iter().map(|type_id| type_id.into()).collect(), + ) + } + + /// Inserts a new [TypeInfo::Array] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable array type + /// that corresponds to the array given by the `elem_type` and the `length`. + pub(crate) fn insert_array( + &self, + engines: &Engines, + elem_type: TypeArgument, + length: Length, + ) -> TypeId { + let source_id = self.get_array_fallback_source_id(&elem_type, &length); + let is_shareable_type = self.is_shareable_array(engines, &elem_type, &length); + let type_info = TypeInfo::Array(elem_type, length); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Same as [Self::insert_array], but intended to insert arrays without annotations. + // TODO: Unlike `insert_array`, once the https://github.com/FuelLabs/sway/issues/6603 gets implemented, + // this method will get the additional `use_site_source_id` parameter. + pub(crate) fn insert_array_without_annotations( + &self, + engines: &Engines, + elem_type: TypeId, + length: usize, + ) -> TypeId { + self.insert_array(engines, elem_type.into(), Length::new(length)) + } + + /// Inserts a new [TypeInfo::StringArray] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable string array type + /// that corresponds to the string array given by the `length`. + pub(crate) fn insert_string_array(&self, engines: &Engines, length: Length) -> TypeId { + let source_id = Self::get_string_array_fallback_source_id(&length); + let is_shareable_type = self.is_shareable_string_array(&length); + let type_info = TypeInfo::StringArray(length); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Same as [Self::insert_string_array], but intended to insert string arrays without annotations. + // TODO: Unlike `insert_string_array`, once the https://github.com/FuelLabs/sway/issues/6603 gets implemented, + // this method will get the additional `use_site_source_id` parameter. + pub(crate) fn insert_string_array_without_annotations( + &self, + engines: &Engines, + length: usize, + ) -> TypeId { + self.insert_string_array(engines, Length::new(length)) + } + + /// Inserts a new [TypeInfo::ContractCaller] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::ContractCaller] is not a shareable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_contract_caller( + &self, + engines: &Engines, + abi_name: AbiName, + address: Option>, + ) -> TypeId { + // The contract caller type shareability would be calculated as: + // + // !(Self::is_replaceable_contract_caller(abi_name, address) + // || + // Self::is_contract_caller_distinguishable_by_annotations(abi_name, address)) + // + // If the contract caller is replaceable, either the `abi_name` id `Deferred` or the `address` is `None`. + // On the other hand, if the `abi_name` is `Known` or the `address` is `Some`, it will be distinguishable by annotations. + // Which means, it will be either replaceable or distinguishable by annotations, which makes the condition always + // evaluating to false. + // + // The fact that we cannot share `ContractCaller`s is not an issue. In any real-life project, the number of contract callers + // will be negligible, order of magnitude of ~10. + let source_id = Self::get_contract_caller_fallback_source_id(&abi_name, &address); + let type_info = TypeInfo::ContractCaller { abi_name, address }; + self.insert_or_replace_type_source_info(engines, type_info, source_id, false, None) + } + + /// Inserts a new [TypeInfo::Alias] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::Alias] is not a shareable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_alias(&self, engines: &Engines, name: Ident, ty: TypeArgument) -> TypeId { + // The alias type shareability would be calculated as `!(false || true) ==>> false`. + let source_id = self.get_alias_fallback_source_id(&name, &ty); + let type_info = TypeInfo::Alias { name, ty }; + self.insert_or_replace_type_source_info(engines, type_info, source_id, false, None) + } + + /// Inserts a new [TypeInfo::Custom] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::Custom] is not a shareable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_custom( + &self, + engines: &Engines, + qualified_call_path: QualifiedCallPath, + type_arguments: Option>, + ) -> TypeId { + let source_id = self.get_custom_fallback_source_id(&qualified_call_path, &type_arguments); + // The custom type shareability would be calculated as `!(true || true) ==>> false`. + // TODO: Improve handling of `TypeInfo::Custom` and `TypeInfo::TraitType`` within the `TypeEngine`: + // https://github.com/FuelLabs/sway/issues/6601 + let is_shareable_type = false; + let type_info = TypeInfo::Custom { + qualified_call_path, + type_arguments, + }; + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::Custom] into the [TypeEngine] and returns its [TypeId]. + /// The custom type is defined only by its `name`. In other words, it does not have + /// the qualified call path or type arguments. This is a very common situation in + /// the code that just uses the type name, like, e.g., when instantiating structs: + /// + /// ```ignore + /// let _ = Struct { }; + /// ``` + /// + /// [TypeInfo::Custom] is not a shareable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_custom_from_name(&self, engines: &Engines, name: Ident) -> TypeId { + self.new_custom(engines, name.into(), None) + } + + /// Creates a new [TypeInfo::Custom] that represents a Self type. + /// + /// The `span` must either be a [Span::dummy] or a span pointing + /// to text "Self" or "self", otherwise the method panics. + /// + /// [TypeInfo::Custom] is not a shareable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_self_type(&self, engines: &Engines, span: Span) -> TypeId { + let source_id = span.source_id().copied(); + // The custom type shareability would be calculated as `!(true || true) ==>> false`. + // TODO: Improve handling of `TypeInfo::Custom` and `TypeInfo::TraitType`` within the `TypeEngine`: + // https://github.com/FuelLabs/sway/issues/6601 + let is_shareable_type = false; + let type_info = TypeInfo::new_self_type(span); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::Slice] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable slice type + /// that corresponds to the slice given by the `elem_type`. + pub(crate) fn insert_slice(&self, engines: &Engines, elem_type: TypeArgument) -> TypeId { + let source_id = self.get_slice_fallback_source_id(&elem_type); + let is_shareable_type = self.is_shareable_slice(engines, &elem_type); + let type_info = TypeInfo::Slice(elem_type); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::Ptr] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable pointer type + /// that corresponds to the pointer given by the `pointee_type`. + pub(crate) fn insert_ptr(&self, engines: &Engines, pointee_type: TypeArgument) -> TypeId { + let source_id = self.get_ptr_fallback_source_id(&pointee_type); + let is_shareable_type = self.is_shareable_ptr(engines, &pointee_type); + let type_info = TypeInfo::Ptr(pointee_type); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::Ref] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable reference type + /// that corresponds to the reference given by the `referenced_type` and `to_mutable_value`. + pub(crate) fn insert_ref( + &self, + engines: &Engines, + to_mutable_value: bool, + referenced_type: TypeArgument, + ) -> TypeId { + let source_id = self.get_ref_fallback_source_id(&referenced_type); + let is_shareable_type = self.is_shareable_ref(engines, &referenced_type); + let type_info = TypeInfo::Ref { + to_mutable_value, + referenced_type, + }; + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::TraitType] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable trait type type + /// that corresponds to the trait type given by the `name` and `trait_type_id`. + pub(crate) fn insert_trait_type( + &self, + engines: &Engines, + name: Ident, + trait_type_id: TypeId, + ) -> TypeId { + let source_id = self.get_trait_type_fallback_source_id(&name, &trait_type_id); + // The trait type type shareability would be calculated as `!(false || false) ==>> true`. + // TODO: Improve handling of `TypeInfo::Custom` and `TypeInfo::TraitType`` within the `TypeEngine`: + // https://github.com/FuelLabs/sway/issues/6601 + let is_shareable_type = true; + let type_info = TypeInfo::TraitType { + name, + trait_type_id, + }; + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Same as [Self::insert_ref], but intended to insert references without annotations. + // TODO: Unlike `insert_ref`, once the https://github.com/FuelLabs/sway/issues/6603 gets implemented, + // this method will get the additional `use_site_source_id` parameter. + pub(crate) fn insert_ref_without_annotations( + &self, + engines: &Engines, + to_mutable_value: bool, + referenced_type: TypeId, + ) -> TypeId { + self.insert_ref(engines, to_mutable_value, referenced_type.into()) + } + /// Inserts a [TypeInfo] into the [TypeEngine] and returns a [TypeId] /// referring to that [TypeInfo]. pub(crate) fn insert( @@ -69,37 +800,1071 @@ impl TypeEngine { ty: TypeInfo, source_id: Option<&SourceId>, ) -> TypeId { - let source_id = source_id.copied().or_else(|| info_to_source_id(&ty)); - let tsi = TypeSourceInfo { - type_info: ty.clone().into(), - source_id, + // Avoid all of the heavy lifting of inserting and replacing logic, if `ty` is a shareable built-in type. + // + // Note that we are ignoring here the eventual `source_id` that could be provided by the caller. + // Ideally, for shareable built-in types that should never be the case, but `insert` is called in + // rare cases where the `ty` is not known and not inspected and is usually providing the use site span. + // + // The reason for ignoring the `source_id` is, because we want these types to be reused and "live forever" + // and never be garbage-collected and thus we do not assign any source id to them. + if let Some(type_id) = self.get_shareable_built_in_type_id(&ty) { + return type_id; + } + + // Same for the replaceable types, avoid heavy lifting. + // Note that we don't want to pack this `match` into a method, because we want to avoid cloning + // of `ty` in the case of it being a `Placeholder` or `UnknownGeneric`. + // + // TODO: Also, note that also here we are ignoring the `source_id` provided by the caller. + // This is only temporary until https://github.com/FuelLabs/sway/issues/6603 gets implemented. + // Until then, this shortcut corresponds to the current `TypeEngine` behavior: + // - `Unknown`s and `Numeric`s never have `source_id` assigned. + // - for `Placeholder`s and `UnknownGeneric`s, the `source_id` is extracted from the call site. + match ty { + TypeInfo::Unknown => return self.new_unknown(), + TypeInfo::Numeric => return self.new_numeric(), + TypeInfo::Placeholder(_) => return self.new_placeholder_impl(ty), + TypeInfo::UnknownGeneric { .. } => return self.new_unknown_generic_impl(ty), + _ => (), + } + + let is_shareable_type = self.is_type_shareable(engines, &ty); + let source_id = source_id + .copied() + .or_else(|| self.get_type_fallback_source_id(engines, &ty)); + + self.insert_or_replace_type_source_info(engines, ty, source_id, is_shareable_type, None) + } + + /// This method performs two actions, depending on the `replace_at_type_id`. + /// + /// If the `replace_at_type_id` is `Some`, this indicates that we want to unconditionally replace the [TypeSourceInfo] + /// currently located at `replace_at_type_id` with the one made of the `ty` + `source_id` pair. + /// In the case of replacement the method always return the [TypeId] provided in `replace_at_type_id`. + /// + /// If the `replace_at_type_id` is `None`, this indicates that we want to insert the [TypeSourceInfo], made of the + /// `ty` + `source_id` pair, into the `TypeEngine`. The insertion into the engine might require a new insert into + /// the `slab` or just returning a [TypeId] of an existing shareable [TypeSourceInfo] that is equal to the one defined by + /// the `ty` + `source_id` pair. + /// + /// If a new insertion is always made, or a reuse is possible, depends on the shareability of `ty` that is given by + /// `is_shareable_type`. + fn insert_or_replace_type_source_info( + &self, + engines: &Engines, + ty: TypeInfo, + source_id: Option, + is_shareable_type: bool, + replace_at_type_id: Option, + ) -> TypeId { + if !is_shareable_type { + let tsi = TypeSourceInfo { + type_info: ty.into(), + source_id, + }; + match replace_at_type_id { + Some(existing_id) => { + self.slab.replace(existing_id.index(), tsi); + existing_id + } + None => TypeId::new(self.slab.insert(tsi)), + } + } else { + let mut shareable_types = self.shareable_types.write(); + + let hash_builder = shareable_types.hasher().clone(); + let ty_hash = + self.compute_hash_without_heap_allocation(engines, &hash_builder, &ty, &source_id); + + let raw_entry = shareable_types.raw_entry_mut().from_hash(ty_hash, |x| { + // Not that the equality with engines of the types contained in the + // `shareable_types` is "strict" in the sense that only one element can equal. + // This is because the types that have annotation fields, a.k.a. distinguishable by + // annotations types, will never end up in the hash map because they are considered + // not to be shareable. + x.equals(&ty, &source_id, &PartialEqWithEnginesContext::new(engines)) + }); + match raw_entry { + RawEntryMut::Occupied(o) => match replace_at_type_id { + Some(existing_id) => { + let existing_type_source_info = o.key(); + self.slab + .replace_arc(existing_id.index(), existing_type_source_info.clone()); + existing_id + } + None => *o.get(), + }, + RawEntryMut::Vacant(v) => { + let tsi = TypeSourceInfo { + type_info: ty.into(), + source_id, + }; + let tsi_arc = Arc::new(tsi); + let type_id = TypeId::new(self.slab.insert_arc(tsi_arc.clone())); + v.insert_with_hasher( + ty_hash, + tsi_arc.clone(), + type_id, + make_hasher(&hash_builder, engines), + ); + match replace_at_type_id { + Some(existing_id) => { + self.slab.replace_arc(existing_id.index(), tsi_arc); + existing_id + } + None => type_id, + } + } + } + } + } + + /// Computes the same hash as the [Hasher] returned by [make_hasher] but without + /// allocating a new [TypeInfo] on the heap. + fn compute_hash_without_heap_allocation( + &self, + engines: &Engines, + hash_builder: &impl BuildHasher, + type_info: &TypeInfo, + source_id: &Option, + ) -> u64 { + let mut state = hash_builder.build_hasher(); + type_info.hash(&mut state, engines); + source_id.hash(&mut state); + state.finish() + } + + /// Returns true if the `ty` is a type that can be replaced by using + /// the [Self::replace] method during the type unification. + fn is_replaceable_type(ty: &TypeInfo) -> bool { + match ty { + TypeInfo::Unknown + | TypeInfo::Numeric + | TypeInfo::Placeholder(_) + | TypeInfo::UnknownGeneric { .. } => true, + TypeInfo::ContractCaller { abi_name, address } => { + Self::is_replaceable_contract_caller(abi_name, address) + } + _ => false, + } + } + + fn is_replaceable_contract_caller( + abi_name: &AbiName, + address: &Option>, + ) -> bool { + address.is_none() || matches!(abi_name, AbiName::Deferred) + } + + /// Returns true if the `ty` is a shareable type. + /// + /// A shareable type instance can be reused by the engine and is put into the [Self::shareable_types]. + fn is_type_shareable(&self, engines: &Engines, ty: &TypeInfo) -> bool { + !(self.is_type_changeable(engines, ty) || self.is_type_distinguishable_by_annotations(ty)) + } + + /// Returns true if the `ty` is a changeable type. A changeable type is either: + /// - a type that can be replaced during the type unification (by calling [Self::replace]). + /// We call such types replaceable types. A typical example would be [TypeInfo::UnknownGeneric]. + /// - or a type that is recursively defined over one or more replaceable types. E.g., a + /// generic enum type `SomeEnum` that is still not monomorphized is a changeable type. + /// Note that a monomorphized version of `SomeEnum`, like e.g., `SomeEnum` *is not + /// changeable*. + /// + /// Note that the changeability of a type is tightly related to the unification process + /// and the process of handling the types within the [TypeEngine]. As such, it is not + /// seen as a property of a type itself, but rather as an information on how the [TypeEngine] + /// treats the type. That's why the definition of the changeability of a type resides + /// inside of the [TypeEngine]. + pub(crate) fn is_type_changeable(&self, engines: &Engines, ty: &TypeInfo) -> bool { + let decl_engine = engines.de(); + let parsed_decl_engine = engines.pe(); + match ty { + // Shareable built-in types are unchangeable by definition. + // These type have only one shared `TypeInfo` instance per type + // (and one for each unsigned integer). + TypeInfo::StringSlice + | TypeInfo::UnsignedInteger(_) + | TypeInfo::Boolean + | TypeInfo::B256 + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::ErrorRecovery(_) + | TypeInfo::Contract + | TypeInfo::Never => false, + + // Note that `TypeParam` is currently not used at all. + TypeInfo::TypeParam(_) => false, + + // `StringArray`s are not changeable. We will have one shared + // `TypeInfo` instance for every string size. Note that in case + // of explicitly defined string arrays, e.g. in the storage or type ascriptions + // like `str[5]`, we can also have different instances for string + // arrays of the same size, because the `Length` in that case contains + // as well the span of the size (`5` in the example). + TypeInfo::StringArray(_) => false, + + // Replaceable types are, by definition, changeable. + TypeInfo::Unknown + | TypeInfo::Numeric + | TypeInfo::Placeholder(_) + | TypeInfo::UnknownGeneric { .. } => true, + + // The `ContractCaller` can be replaceable, and thus, sometimes changeable. + TypeInfo::ContractCaller { abi_name, address } => { + Self::is_replaceable_contract_caller(abi_name, address) + } + + // For the types are defined over other types, inspect recursively their constituting types. + TypeInfo::Enum(decl_id) => { + let decl = decl_engine.get_enum(decl_id); + self.is_changeable_enum(engines, &decl) + } + TypeInfo::UntypedEnum(decl_id) => { + let decl = parsed_decl_engine.get_enum(decl_id); + self.is_changeable_untyped_enum(engines, &decl) + } + TypeInfo::Struct(decl_id) => { + let decl = decl_engine.get_struct(decl_id); + self.is_changeable_struct(engines, &decl) + } + TypeInfo::UntypedStruct(decl_id) => { + let decl = parsed_decl_engine.get_struct(decl_id); + self.is_changeable_untyped_struct(engines, &decl) + } + TypeInfo::Tuple(elements) => self.is_changeable_tuple(engines, elements), + + // Currently, we support only non-generic aliases. Which means the alias + // will never be changeable. + // TODO: (GENERIC-TYPE-ALIASES) If we ever introduce generic type aliases, update this accordingly. + TypeInfo::Alias { name: _, ty: _ } => false, + + // The following types are changeable if their type argument is changeable. + TypeInfo::Array(ta, _) + | TypeInfo::Slice(ta) + | TypeInfo::Ptr(ta) + | TypeInfo::Ref { + referenced_type: ta, + .. + } => self.is_changeable_type_argument(engines, ta), + + // TODO: Improve handling of `TypeInfo::Custom` and `TypeInfo::TraitType`` within the `TypeEngine`: + // https://github.com/FuelLabs/sway/issues/6601 + TypeInfo::Custom { .. } => true, + TypeInfo::TraitType { .. } => false, + } + } + + /// Returns true if two [TypeInfo] instances that are equal (with engines) and have same hashes (with engines) + /// should potentially still be treated, within the type engine, as different types. + /// + /// [TypeParameter]s, [TypeArgument]s, and [Length]s can be "annotated". This means that, aside from the information they + /// provide, like, e.g., [TypeArgument::type_id] or [Length::val], they can also, optionally, provide additional information + /// most notably various spans. + /// + /// Same is with [Ident]s. From the hashing and equality (with engines) perspective, only the string value matters, + /// but from the strict equality point of view, [Ident]'s span is also relevant. + /// + /// Thus, from the unification and type equivalence perspective, two [TypeArgument]s with the same `type_id` represent + /// the same type. But if those two type arguments differ in their annotations, the [TypeEngine] must be able to distinguish between + /// the equal (from the unification perspective) types that use those two different type arguments. + /// + /// In this example: + /// + /// ```ignore + /// let a: [u64;3] = (0, 0, 0); + /// let b: [u64;3] = (0, 0, 0); + /// ``` + /// + /// `a` and `b` will have the same type, but the span annotations in their [TypeArgument]s and [Length]s will be different + /// (different spans pointing to two "u64"s and two "3"s) and thus the [TypeEngine] must treat those two types as two + /// different types and when inserting them, assign them two different [TypeId]s, although the types themselves are not + /// changeable. + /// + /// To sum it up: + /// - if the `ty` consists of [TypeArgument]s, [TypeParameter]s, or [Length]s, they myst be check for annotations. + /// - if the `ty` contains, e.g., [Ident]s, it is considered to be distinguishable by annotations. + fn is_type_distinguishable_by_annotations(&self, ty: &TypeInfo) -> bool { + match ty { + // Types that do not have any annotations. + TypeInfo::StringSlice + | TypeInfo::UnsignedInteger(_) + | TypeInfo::Boolean + | TypeInfo::B256 + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::ErrorRecovery(_) + | TypeInfo::Never + | TypeInfo::Unknown + | TypeInfo::Numeric + | TypeInfo::Contract + | TypeInfo::TypeParam(_) => false, + + // Types that are always distinguishable because they have the `name: Ident`. + // + // Let's explain this in more detail, taking the `TypeInfo::Alias` as an example. + // `TypeInfo::Alias` consists of the `name: Ident` and the `ty: TypeArgument`. + // + // Consider that we have two aliases with the same name and aliasing the same type but defined in different modules. + // Thus, they would be two _different_ alias types. But because the spans in the `name` and `ty` do not count + // neither for the equality check nor for the hash calculation, those two types will always be equal (with engines) + // and also have the same hashes (with engines). + // + // This means that the `TypeEngine` would see them as the same type which would be wrong. + // The fact that they are always distinguishable by annotations (span in the `name` and spans in the `ty`) + // is actually a fortunate fact here, because it will help the `TypeEngine` to distinguish them. + // + // The consequence of this fact is, that all `TypeInfo::Alias`es are _always distinguishable by annotations_. + // + // The downside is that repeated usages of an actually *same* alias type will create + // unnecessary new instances in the `TypeEngine` for every usage :-( + // + // Luckily, `TraitType`s and `Alias`es are rarely used and the number of their instances + // within the `TypeEngine` will always be negligible, so we don't need to worry about this downside. + // (At the time of writing this comment, out of ~200,000 types in the `TypeEngine` in a + // realistic real-world project only ~20 were type aliases and only ~5 were trait types.) + // And the `UnknownGeneric` is anyhow a changeable type. + TypeInfo::UnknownGeneric { .. } + // | TypeInfo::TraitType { .. } + | TypeInfo::Alias { .. } => true, + + TypeInfo::StringArray(l) => l.is_annotated(), + + // If the contract caller has the `abi_name` defined (AbiName::Know) the span information + // that comes with the `Ident`s of the `CallPath` is not relevant for the equality + // and hashing (with engines) but makes two same names distinguishable. The same thing is + // with the `address` expression. It can be, e.g., the same literal, but it will have different + // spans. Moreover, the same `abi_name`, depending on the context, can represent different + // ABI declarations, like in the example below: + // + // fn a() { + // use ::lib_a::Abi as Abi; // <<<--- `Abi` coming from `lib_**a**`. + // let _ = abi(Abi, 0x1111111111111111111111111111111111111111111111111111111111111111); + // } + + // fn b() { + // use ::lib_b::Abi as Abi; // <<<--- `Abi` coming from `lib_**b**`. + // let _ = abi(Abi, 0x1111111111111111111111111111111111111111111111111111111111111111); + // } + // + // This all means, if a `ContractCaller` has either the `abi_name` or the `address` defined, + // it is distinguishable by annotations. + TypeInfo::ContractCaller { abi_name, address } => Self::is_contract_caller_distinguishable_by_annotations(abi_name, address), + + // Enums `decl`s are either coming from enum declarations, + // or from their monomorphizations. If an enum declaration is generic, + // its type parameters will always be annotated, having, e.g., spans of + // generic parameter names, like, e.g., "T". + // Also, all the enum variants have `TypeArguments` that are _always_ annotated + // with the type span. + // + // In other words, all `TyEnumDecl`s are annotated. + // The question is, if the monomorphization can produce two same `decl`s that + // are differently annotated. E.g., when unifying the generic parameter "T" with "u64", + // like in the below example, will the span of the type parameter "T" change + // to "u64": + // + // let _ = GenericEnum::::A(42u64); + // let _ = GenericEnum::::A(42u64); + // + // In that case, the two equal `decl`s obtained via two monomorphizations above, + // would be differently annotated, and thus, distinguishable by annotations. + // + // The answer is *no*. The monomorphization changes only the `TypeId`s of the + // `TypeParameter`s and `TypeArgument`s but leaves the original spans untouched. + // Therefore, we can never end up in a situation that an annotation differs from + // the one in the original `TyEnumDecl` coming from the enum declaration. + // + // Thus, any two equal `TyEnumDecl`s are never distinguishable by annotations. + TypeInfo::Enum(_) => false, + + // The same argument as above applies to struct and `TyStructDecl`s. + TypeInfo::Struct(_) => false, + + // TODO: (UNTYPED-TYPES) Reassess this once `UntypedEnum` and `UntypedStruct` + // start getting logic. + TypeInfo::UntypedEnum(_) => false, + + // TODO: (UNTYPED-TYPES) Reassess this once `UntypedEnum` and `UntypedStruct` + // start getting logic. + TypeInfo::UntypedStruct(_) => false, + + // Equal (with engines) tuple types can have different annotations and are in that case + // distinguishable by those annotations. E.g., in the example below, the two + // `(u64, u8)` tuples will have different spans for two "u64"s and two "u8"s. + // + // let _: (u64, u8) = (64u64, 8u8); + // let _: (u64, u8) = (64u64, 8u8); + // + // Note that _all the tuples used in code will always be distinguishable by annotations_, + // because they will always have spans either pointing to the values like in `(64u64, 8u8)` + // or to types like in `(u64, u8)`. + // + // Only the tuples used in generated code will not be distinguishable by annotations, + // as well as tuples representing unit types. + TypeInfo::Tuple(elements) => self.is_tuple_distinguishable_by_annotations(elements), + + // The below types are those have `TypeArgument`s (`ta`s) in their definitions. + // Note that we are checking only if those `ta`s are annotated, but not + // recursively if the types they "reference" are annotated ;-) + // We don't need to recursively check if the types behind + // the `ta.type_id`s are distinguishable by annotations. + // This is because two equal (with engines) parent types + // containing `ta`s that pass the above check are also equal in + // case when their full type argument content is compared, + // because the type arguments will be equal in all their fields. + + TypeInfo::Slice(ta) + | TypeInfo::Ptr(ta) + | TypeInfo::Ref { referenced_type: ta, .. } => ta.is_annotated(), + + TypeInfo::Array(ta, l) => { + ta.is_annotated() || l.is_annotated() + } + + // The above reasoning for `TypeArgument`s applies also for the `TypeParameter`s. + // We only need to check if the `tp` is annotated. + TypeInfo::Placeholder(tp) => tp.is_annotated(), + + // TODO: Improve handling of `TypeInfo::Custom` and `TypeInfo::TraitType`` within the `TypeEngine`: + // https://github.com/FuelLabs/sway/issues/6601 + TypeInfo::Custom { .. } => true, + TypeInfo::TraitType { .. } => false, + } + } + + fn is_tuple_distinguishable_by_annotations(&self, elements: &[TypeArgument]) -> bool { + if elements.is_empty() { + false + } else { + elements.iter().any(|ta| ta.is_annotated()) + } + } + + fn is_contract_caller_distinguishable_by_annotations( + abi_name: &AbiName, + address: &Option>, + ) -> bool { + address.is_some() || matches!(abi_name, AbiName::Known(_)) + } + + /// Returns true if the `type_id` represents a changeable type. + /// For the type changeability see [Self::is_type_changeable]. + fn is_type_id_of_changeable_type(&self, engines: &Engines, type_id: TypeId) -> bool { + self.is_type_changeable(engines, &self.slab.get(type_id.index()).type_info) + } + + fn is_changeable_type_argument(&self, engines: &Engines, ta: &TypeArgument) -> bool { + self.is_type_id_of_changeable_type(engines, ta.type_id) + } + + fn is_changeable_enum(&self, engines: &Engines, decl: &TyEnumDecl) -> bool { + self.are_changeable_type_parameters(engines, &decl.type_parameters) + // TODO: Remove once https://github.com/FuelLabs/sway/issues/6687 is fixed. + || + self.module_might_outlive_type_parameters(engines, decl.span.source_id(), &decl.type_parameters) + } + + fn is_changeable_untyped_enum(&self, engines: &Engines, decl: &EnumDeclaration) -> bool { + self.are_changeable_type_parameters(engines, &decl.type_parameters) + // TODO: Remove once https://github.com/FuelLabs/sway/issues/6687 is fixed. + || + self.module_might_outlive_type_parameters(engines, decl.span.source_id(), &decl.type_parameters) + } + + fn is_changeable_struct(&self, engines: &Engines, decl: &TyStructDecl) -> bool { + self.are_changeable_type_parameters(engines, &decl.type_parameters) + // TODO: Remove once https://github.com/FuelLabs/sway/issues/6687 is fixed. + || + self.module_might_outlive_type_parameters(engines, decl.span.source_id(), &decl.type_parameters) + } + + fn is_changeable_untyped_struct(&self, engines: &Engines, decl: &StructDeclaration) -> bool { + self.are_changeable_type_parameters(engines, &decl.type_parameters) + // TODO: Remove once https://github.com/FuelLabs/sway/issues/6687 is fixed. + || + self.module_might_outlive_type_parameters(engines, decl.span.source_id(), &decl.type_parameters) + } + + fn is_changeable_tuple(&self, engines: &Engines, elements: &[TypeArgument]) -> bool { + if elements.is_empty() { + false + } else { + elements + .iter() + .any(|ta| self.is_type_id_of_changeable_type(engines, ta.type_id)) + } + } + + fn are_changeable_type_parameters( + &self, + engines: &Engines, + type_parameters: &[TypeParameter], + ) -> bool { + if type_parameters.is_empty() { + false + } else { + type_parameters + .iter() + .any(|tp| self.is_type_id_of_changeable_type(engines, tp.type_id)) + } + } + + // TODO: Remove this and all `module_might_outlive_xyz` methods once https://github.com/FuelLabs/sway/issues/6687 is fixed. + // + // This method represents the best effort to partially mitigate the issue + // described in https://github.com/FuelLabs/sway/issues/6687, by doing changes only in the `TypeEngine`. + // + // Enum and struct types use it to restrict their shareability and reduce the chance of accessing + // GCed types. + // + // The method takes an **existing** `type_id` and the source id of a particular module (`module_source_id`) + // and checks if the module represented by the `module_source_id` **might** survive LSP garbage collection + // even if the module to which `type_id` is bound gets GCed. + // + // E.g., if the `module_source_id` points to the `Option` declaration of a monomorphized `Option`, + // this method will return true if the `type_id` represents `MyStruct`, because if the `MyStruct`'s module + // gets GCed, the `Option`'s module will "survive" and outlive it, thus pointing via its `TypeArgument` to a + // non-existing, GCed, `MyStruct` type. + // + // E.g., if the `module_source_id` points to the `Option` declaration of a monomorphized `Option`, + // this method will return false if the `type_id` represents `u64`, because the `u64` is not bound to + // any module, and thus, can never be GCed. This means that the `Option`'s module can never outlive it. + fn module_might_outlive_type( + &self, + engines: &Engines, + module_source_id: Option<&SourceId>, + type_id: TypeId, + ) -> bool { + fn module_might_outlive_type_source_id( + module_source_id: Option<&SourceId>, + type_source_id: Option, + ) -> bool { + // If the type represented by the `type_id` is not bound to a source id (`type_source_id.is_none()`) + // it cannot be outlived by the module. + // Otherwise, if `type_source_id.is_some()` but is the same as the `module_source_id`, it can be GCed only if + // the `module_source_id` is GCed. + // Otherwise, we cannot guarantee that the module will not outlive the type's module and we must + // be pessimistic and return false. + type_source_id.is_some() && type_source_id != module_source_id.copied() + } + + let tsi = self.slab.get(type_id.index()); + let type_info = &*tsi.type_info; + let type_source_id = tsi.source_id; + + let decl_engine = engines.de(); + let parsed_decl_engine = engines.pe(); + + // We always must check the `type_id` itself, like, e.h., `MyStruct` in `Option`, ... + module_might_outlive_type_source_id(module_source_id, type_source_id) + || + // ... and also all types it transitively depends on, like, e.g., in `Option>`. + match type_info { + // If a type does not transitively depends on other types, just return `false`. + TypeInfo::StringSlice + | TypeInfo::UnsignedInteger(_) + | TypeInfo::Boolean + | TypeInfo::B256 + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::ErrorRecovery(_) + | TypeInfo::Contract + | TypeInfo::Never => false, + + // Note that `TypeParam` is currently not used at all. + TypeInfo::TypeParam(_) => false, + + TypeInfo::StringArray(_) => false, + + TypeInfo::Unknown + | TypeInfo::Numeric => false, + + TypeInfo::Placeholder(tp) => self.module_might_outlive_type_parameter(engines, module_source_id, tp), + TypeInfo::UnknownGeneric { trait_constraints, parent, .. } => { + parent.is_some_and(|parent_type_id| self.module_might_outlive_type(engines, module_source_id, parent_type_id)) + || + self.module_might_outlive_trait_constraints(engines, module_source_id, trait_constraints) + }, + + TypeInfo::ContractCaller { .. } => false, + + TypeInfo::Enum(decl_id) => { + let decl = decl_engine.get_enum(decl_id); + self.module_might_outlive_type_parameters(engines, module_source_id, &decl.type_parameters) + } + TypeInfo::UntypedEnum(decl_id) => { + let decl = parsed_decl_engine.get_enum(decl_id); + self.module_might_outlive_type_parameters(engines, module_source_id, &decl.type_parameters) + } + TypeInfo::Struct(decl_id) => { + let decl = decl_engine.get_struct(decl_id); + self.module_might_outlive_type_parameters(engines, module_source_id, &decl.type_parameters) + } + TypeInfo::UntypedStruct(decl_id) => { + let decl = parsed_decl_engine.get_struct(decl_id); + self.module_might_outlive_type_parameters(engines, module_source_id, &decl.type_parameters) + } + TypeInfo::Tuple(elements) => self.module_might_outlive_type_arguments(engines, module_source_id, elements), + + TypeInfo::Alias { ty, .. } => self.module_might_outlive_type_argument(engines, module_source_id, ty), + + TypeInfo::Array(ta, _) + | TypeInfo::Slice(ta) + | TypeInfo::Ptr(ta) + | TypeInfo::Ref { + referenced_type: ta, + .. + } => self.module_might_outlive_type_argument(engines, module_source_id, ta), + + TypeInfo::Custom { type_arguments, .. } => + type_arguments.as_ref().is_some_and(|type_arguments| + self.module_might_outlive_type_arguments(engines, module_source_id, type_arguments)), + TypeInfo::TraitType { trait_type_id, .. } => self.module_might_outlive_type(engines, module_source_id, *trait_type_id) + } + } + + fn module_might_outlive_type_parameter( + &self, + engines: &Engines, + module_source_id: Option<&SourceId>, + type_parameter: &TypeParameter, + ) -> bool { + self.module_might_outlive_type(engines, module_source_id, type_parameter.type_id) + || self.module_might_outlive_type( + engines, + module_source_id, + type_parameter.initial_type_id, + ) + || self.module_might_outlive_trait_constraints( + engines, + module_source_id, + &type_parameter.trait_constraints, + ) + } + + fn module_might_outlive_type_parameters( + &self, + engines: &Engines, + module_source_id: Option<&SourceId>, + type_parameters: &[TypeParameter], + ) -> bool { + if type_parameters.is_empty() { + false + } else { + type_parameters + .iter() + .any(|tp| self.module_might_outlive_type_parameter(engines, module_source_id, tp)) + } + } + + fn module_might_outlive_type_argument( + &self, + engines: &Engines, + module_source_id: Option<&SourceId>, + type_argument: &TypeArgument, + ) -> bool { + self.module_might_outlive_type(engines, module_source_id, type_argument.type_id) + || self.module_might_outlive_type( + engines, + module_source_id, + type_argument.initial_type_id, + ) + } + + fn module_might_outlive_type_arguments( + &self, + engines: &Engines, + module_source_id: Option<&SourceId>, + type_arguments: &[TypeArgument], + ) -> bool { + if type_arguments.is_empty() { + false + } else { + type_arguments + .iter() + .any(|ta| self.module_might_outlive_type_argument(engines, module_source_id, ta)) + } + } + + fn module_might_outlive_trait_constraint( + &self, + _engines: &Engines, + _module_source_id: Option<&SourceId>, + trait_constraint: &TraitConstraint, + ) -> bool { + // `TraitConstraint`s can contain `TypeArgument`s that can cause endless recursion, + // unless we track already visited types. This happens in cases of recursive generic + // traits like, e.g., `T: Trait`. + // + // We deliberately decide not to track visited types because: + // - `module_might_outlive_type` represents a best effort to mitigate the issue of modules outliving their types. + // It is already not exact. + // - trait constraints with type arguments are rather rare. + // - tracking already visited types is expensive and `module_might_outlive_type` already adds an overhead. + // + // Instead, if the `trait_constraint` contains type arguments, we will bail out and + // conclude that the module might outlive the types in the trait constraint. + !trait_constraint.type_arguments.is_empty() + } + + fn module_might_outlive_trait_constraints( + &self, + engines: &Engines, + module_source_id: Option<&SourceId>, + trait_constraint: &[TraitConstraint], + ) -> bool { + trait_constraint + .iter() + .any(|tc| self.module_might_outlive_trait_constraint(engines, module_source_id, tc)) + } + + // In the `is_shareable_` methods we reuse the logic from the + // `is_type_changeable` and `is_type_distinguishable_by_annotations`. + // This is a very slight and minimal copy of logic, that improves performance + // (Inlining, no additional fetching from the `DeclEngine`, no intensive function + // calls, etc. Don't forget that this is all on a *very* hot path.) + + fn is_shareable_enum(&self, engines: &Engines, decl: &TyEnumDecl) -> bool { + // !(self.is_changeable_enum(decl_engine, decl) || false) + !self.is_changeable_enum(engines, decl) + } + + fn is_shareable_struct(&self, engines: &Engines, decl: &TyStructDecl) -> bool { + // !(self.is_changeable_struct(decl_engine, decl) || false) + !self.is_changeable_struct(engines, decl) + } + + fn is_shareable_tuple(&self, engines: &Engines, elements: &[TypeArgument]) -> bool { + !(self.is_changeable_tuple(engines, elements) + || self.is_tuple_distinguishable_by_annotations(elements)) + } + + fn is_shareable_array( + &self, + engines: &Engines, + elem_type: &TypeArgument, + length: &Length, + ) -> bool { + !(self.is_changeable_type_argument(engines, elem_type) + || elem_type.is_annotated() + || length.is_annotated()) + } + + fn is_shareable_string_array(&self, length: &Length) -> bool { + // !(false || length.is_annotated()) + !length.is_annotated() + } + + fn is_shareable_slice(&self, engines: &Engines, elem_type: &TypeArgument) -> bool { + !(self.is_changeable_type_argument(engines, elem_type) || elem_type.is_annotated()) + } + + fn is_shareable_ptr(&self, engines: &Engines, pointee_type: &TypeArgument) -> bool { + !(self.is_changeable_type_argument(engines, pointee_type) || pointee_type.is_annotated()) + } + + fn is_shareable_ref(&self, engines: &Engines, referenced_type: &TypeArgument) -> bool { + !(self.is_changeable_type_argument(engines, referenced_type) + || referenced_type.is_annotated()) + } + + // TODO: This and other, type-specific, methods that calculate `source_id` have `fallback` in their name. + // They will be called if the `source_id` is not provided in `new` or `insert` methods, + // thus, fallbacks. + // However, some of them actually do calculate the appropriate `source_id` which will for certain + // types and situations always be extracted from the `TypeInfo` and not allowed to be provided + // in `new` or `insert` methods. + // Until https://github.com/FuelLabs/sway/issues/6603 gets implemented, we will call them all + // fallbacks, which corresponds to the current usage, and eventually rename them accordingly + // once we optimize the `TypeEngine` for garbage collection (#6603). + + fn get_type_fallback_source_id(&self, engines: &Engines, ty: &TypeInfo) -> Option { + let decl_engine = engines.de(); + let parsed_decl_engine = engines.pe(); + match ty { + TypeInfo::Unknown + | TypeInfo::Never + | TypeInfo::TypeParam(_) + | TypeInfo::UnsignedInteger(_) + | TypeInfo::Boolean + | TypeInfo::B256 + | TypeInfo::Numeric + | TypeInfo::ErrorRecovery(_) + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::Contract + | TypeInfo::StringSlice => None, + + TypeInfo::UnknownGeneric { .. } => Self::get_unknown_generic_fallback_source_id(ty), + TypeInfo::Placeholder(_) => self.get_placeholder_fallback_source_id(ty), + TypeInfo::StringArray(length) => Self::get_source_id_from_length(length), + TypeInfo::Enum(decl_id) => { + let decl = decl_engine.get_enum(decl_id); + Self::get_enum_fallback_source_id(&decl) + } + TypeInfo::UntypedEnum(decl_id) => { + let decl = parsed_decl_engine.get_enum(decl_id); + Self::get_untyped_enum_fallback_source_id(&decl) + } + TypeInfo::Struct(decl_id) => { + let decl = decl_engine.get_struct(decl_id); + Self::get_struct_fallback_source_id(&decl) + } + TypeInfo::UntypedStruct(decl_id) => { + let decl = parsed_decl_engine.get_struct(decl_id); + Self::get_untyped_struct_fallback_source_id(&decl) + } + TypeInfo::Tuple(elements) => self.get_tuple_fallback_source_id(elements), + TypeInfo::Array(elem_type, length) => { + self.get_array_fallback_source_id(elem_type, length) + } + + TypeInfo::ContractCaller { abi_name, address } => { + Self::get_contract_caller_fallback_source_id(abi_name, address) + } + + TypeInfo::Alias { name, ty } => self.get_alias_fallback_source_id(name, ty), + + TypeInfo::Ptr(ta) + | TypeInfo::Slice(ta) + | TypeInfo::Ref { + referenced_type: ta, + .. + } => self.get_source_id_from_type_argument(ta), + + TypeInfo::Custom { + qualified_call_path, + type_arguments, + } => self.get_custom_fallback_source_id(qualified_call_path, type_arguments), + + TypeInfo::TraitType { + name, + trait_type_id, + } => self.get_trait_type_fallback_source_id(name, trait_type_id), + } + } + + fn get_source_id_from_length(length: &Length) -> Option { + length.span().source_id().copied() + } + + fn get_source_id_from_type_argument(&self, ta: &TypeArgument) -> Option { + // If the `ta` is span-annotated, take the source id from its `span`, + // otherwise, take the source id of the type it represents. + ta.span + .source_id() + .copied() + .or_else(|| self.get_type_source_id(ta.type_id)) + } + + fn get_source_id_from_type_arguments( + &self, + type_arguments: &[TypeArgument], + ) -> Option { + // For type arguments, if they are annotated, we take the use site source file. + // In semantically valid usages, in a vector of `TypeArgument`s, the use site source file + // will be the same for all the elements, so we are taking it from the + // first one that is annotated (which will be the first one or none). + // E.g., in a `TypeInfo::Tuple`, all the `TypeArgument`s will either not be annotated, or will + // all be annotated and situated within the same file. + // + // If the type arguments are not annotated, we are taking the source file of the first type + // pointed by a type argument, that has a source id. + if type_arguments.is_empty() { + None + } else { + type_arguments + .iter() + .find_map(|ta| ta.span.source_id().copied()) + .or_else(|| { + type_arguments + .iter() + .find_map(|ta| self.get_type_source_id(ta.type_id)) + }) + } + } + + fn get_source_id_from_type_parameter(&self, tp: &TypeParameter) -> Option { + // If the `tp` is span-annotated, take the source id from its `span`, + // otherwise, take the source id of the type it represents. + tp.name + .span() + .source_id() + .copied() + .or_else(|| self.get_type_source_id(tp.type_id)) + } + + fn get_placeholder_fallback_source_id(&self, placeholder: &TypeInfo) -> Option { + // `TypeInfo::Placeholder` is an always replaceable type and we know we will + // get a new instance of it in the engine for every "_" occurrence. This means + // that it can never happen that instances from different source files point + // to the same `TypeSourceInfo`. Therefore, we can safely remove an instance + // of a `Placeholder` from the engine if its source file is garbage collected. + // + // The source file itself is always the one in which the `name`, means "_", + // is situated. + let TypeInfo::Placeholder(tp) = &placeholder else { + unreachable!("The `placeholder` is checked to be of variant `TypeInfo::Placeholder`."); + }; + + self.get_source_id_from_type_parameter(tp) + } + + fn get_unknown_generic_fallback_source_id(unknown_generic: &TypeInfo) -> Option { + // `TypeInfo::UnknownGeneric` is an always replaceable type and we know we will + // get a new instance of it in the engine for every, e.g., "", "", etc. occurrence. + // This means that it can never happen that instances from different source files point + // to the same `TypeSourceInfo`. Therefore, we can safely remove an instance + // of an `UnknownGeneric` from the engine if its source file is garbage collected. + // + // The source file itself is always the one in which the `name`, means, e.g. "T1", "T2", etc. + // is situated. + let TypeInfo::UnknownGeneric { name, .. } = &unknown_generic else { + unreachable!( + "The `unknown_generic` is checked to be of variant `TypeInfo::UnknownGeneric`." + ); }; - let mut id_map = self.id_map.write(); + name.span().source_id().copied() + } + + fn get_enum_fallback_source_id(decl: &TyEnumDecl) -> Option { + // For `TypeInfo::Enum`, we are taking the source file in which the enum is declared. + decl.span.source_id().copied() + } + + fn get_untyped_enum_fallback_source_id(decl: &EnumDeclaration) -> Option { + // For `TypeInfo::UntypedEnum`, we are taking the source file in which the enum is declared. + decl.span.source_id().copied() + } + + fn get_struct_fallback_source_id(decl: &TyStructDecl) -> Option { + // For `TypeInfo::Struct`, we are taking the source file in which the struct is declared. + decl.span.source_id().copied() + } + + fn get_untyped_struct_fallback_source_id(decl: &StructDeclaration) -> Option { + // For `TypeInfo::UntypedStruct`, we are taking the source file in which the struct is declared. + decl.span.source_id().copied() + } + + fn get_tuple_fallback_source_id(&self, elements: &[TypeArgument]) -> Option { + self.get_source_id_from_type_arguments(elements) + } + + fn get_array_fallback_source_id( + &self, + elem_type: &TypeArgument, + length: &Length, + ) -> Option { + // For `TypeInfo::Array`, if it is annotated, we take the use site source file. + // This can be found in the `elem_type` and the `length`. + // + // If the array type is not annotated, we are taking the source file of the array element. + assert_eq!( + elem_type.span.source_id(), + length.span().source_id(), + "If an array is annotated, the type argument and the length spans must have the same source id." + ); - let hash_builder = id_map.hasher().clone(); - let ty_hash = make_hasher(&hash_builder, engines)(&tsi); + self.get_source_id_from_type_argument(elem_type) + } - let raw_entry = id_map.raw_entry_mut().from_hash(ty_hash, |x| { - x.eq(&tsi, &PartialEqWithEnginesContext::new(engines)) - }); - match raw_entry { - RawEntryMut::Occupied(o) => return *o.get(), - RawEntryMut::Vacant(_) if ty.can_change(engines) => TypeId::new(self.slab.insert(tsi)), - RawEntryMut::Vacant(v) => { - let type_id = TypeId::new(self.slab.insert(tsi.clone())); - v.insert_with_hasher(ty_hash, tsi, type_id, make_hasher(&hash_builder, engines)); - type_id + fn get_string_array_fallback_source_id(length: &Length) -> Option { + // For `TypeInfo::StringArray`, if it is annotated, we take the use site source file found in the `length`. + Self::get_source_id_from_length(length) + } + + fn get_contract_caller_fallback_source_id( + abi_name: &AbiName, + address: &Option>, + ) -> Option { + // For `TypeInfo::ContractCaller`, if it has an `address`, we take the use site source file found in the it. + // Otherwise, if it has an `abi_name`, we take the source file of the ABI definition. + match address { + Some(addr_expr) => addr_expr.span.source_id().copied(), + None => { + if let AbiName::Known(name) = abi_name { + name.span().source_id().copied() + } else { + None + } } } } + fn get_alias_fallback_source_id(&self, name: &Ident, ty: &TypeArgument) -> Option { + // For `TypeInfo::Alias`, we take the source file in which the alias is declared, if it exists. + // Otherwise, we take the source file of the aliased type `ty`. + name.span() + .source_id() + .copied() + .or_else(|| self.get_source_id_from_type_argument(ty)) + } + + fn get_slice_fallback_source_id(&self, elem_type: &TypeArgument) -> Option { + self.get_source_id_from_type_argument(elem_type) + } + + fn get_ptr_fallback_source_id(&self, pointee_type: &TypeArgument) -> Option { + self.get_source_id_from_type_argument(pointee_type) + } + + fn get_ref_fallback_source_id(&self, referenced_type: &TypeArgument) -> Option { + self.get_source_id_from_type_argument(referenced_type) + } + + fn get_custom_fallback_source_id( + &self, + qualified_call_path: &QualifiedCallPath, + type_arguments: &Option>, + ) -> Option { + // For `TypeInfo::Custom`, we take the source file in which the custom type is used, extracted from the `qualified_call_path`. + // For non-generated source code, this will always exists. + // For potential situation of having a `qualified_call_path` without spans in generated code, we do a fallback and + // extract the source id from the remaining parameters. + qualified_call_path + .call_path + .suffix + .span() + .source_id() + .copied() + .or_else(|| { + type_arguments + .as_ref() + .and_then(|tas| self.get_source_id_from_type_arguments(tas)) + }) + } + + fn get_trait_type_fallback_source_id( + &self, + name: &Ident, + trait_type_id: &TypeId, + ) -> Option { + // For `TypeInfo::TraitType`, we take the source file in which the trait type is declared, extracted from the `name`. + // For non-generated source code, this will always exists. + // For potential situation of having a `name` without spans in generated code, we do a fallback and + // extract the source id from the `trait_type_id`. + name.span() + .source_id() + .copied() + .or_else(|| self.get_type_source_id(*trait_type_id)) + } + + /// Returns the known [SourceId] of a type that already exists + /// in the [TypeEngine]. The type is given by its `type_id`. + fn get_type_source_id(&self, type_id: TypeId) -> Option { + self.slab.get(type_id.index()).source_id + } + fn clear_items(&mut self, keep: F) where F: Fn(&SourceId) -> bool, { self.slab .retain(|_, tsi| tsi.source_id.as_ref().map_or(true, &keep)); - self.id_map + self.shareable_types .write() .retain(|tsi, _| tsi.source_id.as_ref().map_or(true, &keep)); } @@ -114,12 +1879,69 @@ impl TypeEngine { self.clear_items(|id| id != source_id); } - pub fn replace(&self, engines: &Engines, id: TypeId, new_value: TypeSourceInfo) { - if !(*self.slab.get(id.index())).eq(&new_value, &PartialEqWithEnginesContext::new(engines)) - { + /// Replaces the replaceable type behind the `type_id` with the `new_value`. + /// The existing source id will be preserved. + /// + /// Note that, if the `new_value` represents a shareable built-in type, + /// the existing source id will be removed (replaced by `None`). + /// + /// Panics if the type behind the `type_id` is not a replaceable type. + pub fn replace(&self, engines: &Engines, type_id: TypeId, new_value: TypeInfo) { + // We keep the existing source id. `replace_with_new_source_id` is treated just as a common implementation. + let source_id = self.slab.get(type_id.index()).source_id; + self.replace_with_new_source_id(engines, type_id, new_value, source_id); + } + + /// Replaces the replaceable type behind the `type_id` with the `new_value`. + /// The existing source id will also be replaced with the `new_source_id`. + /// + /// Note that, if the `new_value` represents a shareable built-in type, + /// the existing source id will be removed (replaced by `None`). + /// + /// Panics if the type behind the `type_id` is not a replaceable type. + // TODO: Once https://github.com/FuelLabs/sway/issues/6603 gets implemented and we further optimize + // the `TypeEngine` for garbage collection, this variant of `replace` will actually not be + // needed any more. The version of `replace` that uses the initially provided `source_id` will + // be sufficient. + pub fn replace_with_new_source_id( + &self, + engines: &Engines, + id: TypeId, + new_value: TypeInfo, + new_source_id: Option, + ) { + let type_source_info = self.slab.get(id.index()); + assert!( + Self::is_replaceable_type(&type_source_info.type_info), + "The type requested to be replaced is not a replaceable type. The type was: {:#?}.", + &type_source_info.type_info + ); + + if !type_source_info.equals( + &new_value, + &new_source_id, + &PartialEqWithEnginesContext::new(engines), + ) { self.touch_last_replace(); } - self.slab.replace(id.index(), new_value); + let is_shareable_type = self.is_type_shareable(engines, &new_value); + // Shareable built-in types like, e.g., `u64`, should "live forever" and never be + // garbage-collected. When replacing types, like e.g., unknown generics, that + // might be bound to a source id, we will still remove that source id, if the + // replaced type is replaced by a shareable built-in type. This maximizes the + // reuse of sharable built-in types, and also ensures that they are never GCed. + let source_id = if self.is_shareable_built_in_type(&new_value) { + None + } else { + new_source_id + }; + self.insert_or_replace_type_source_info( + engines, + new_value, + source_id, + is_shareable_type, + Some(id), + ); } /// Performs a lookup of `id` into the [TypeEngine]. @@ -386,7 +2208,6 @@ impl TypeEngine { | TypeInfo::B256 | TypeInfo::Contract | TypeInfo::ErrorRecovery(..) - | TypeInfo::Storage { .. } | TypeInfo::RawUntypedPtr | TypeInfo::RawUntypedSlice | TypeInfo::Alias { .. } @@ -453,25 +2274,12 @@ impl TypeEngine { | TypeInfo::B256 | TypeInfo::Contract | TypeInfo::ErrorRecovery(..) - | TypeInfo::Storage { .. } | TypeInfo::RawUntypedPtr | TypeInfo::RawUntypedSlice | TypeInfo::Alias { .. } | TypeInfo::TraitType { .. } => {} TypeInfo::Numeric => { - self.unify( - handler, - engines, - type_id, - self.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - span.source_id(), - ), - span, - "", - None, - ); + self.unify(handler, engines, type_id, self.id_of_u64(), span, "", None); } } Ok(()) @@ -491,23 +2299,3 @@ impl TypeEngine { builder } } - -/// Maps specific [TypeInfo] variants to a reserved [SourceId], returning `None` for non-mapped types. -fn info_to_source_id(ty: &TypeInfo) -> Option { - match ty { - TypeInfo::Unknown - | TypeInfo::UnsignedInteger(_) - | TypeInfo::Numeric - | TypeInfo::Boolean - | TypeInfo::B256 - | TypeInfo::RawUntypedPtr - | TypeInfo::RawUntypedSlice - | TypeInfo::StringSlice - | TypeInfo::Contract - | TypeInfo::StringArray(_) - | TypeInfo::Array(_, _) - | TypeInfo::Ref { .. } => Some(SourceId::reserved()), - TypeInfo::Tuple(v) if v.is_empty() => Some(SourceId::reserved()), - _ => None, - } -} diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index 7a7480fe838..090ed6b370a 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -80,7 +80,7 @@ impl CollectTypesMetadata for TypeId { } TypeInfo::Placeholder(type_param) => { res.push(TypeMetadata::UnresolvedType( - type_param.name_ident.clone(), + type_param.name.clone(), ctx.call_site_get(self), )); } @@ -108,7 +108,7 @@ impl SubstTypes for TypeId { } impl TypeId { - pub(super) fn new(index: usize) -> TypeId { + pub(super) const fn new(index: usize) -> TypeId { TypeId(index) } @@ -383,19 +383,6 @@ impl TypeId { .extract_any_including_self(engines, filter_fn, vec![], depth + 1), ); } - TypeInfo::Storage { fields } => { - for field in fields { - extend( - &mut found, - field.type_argument.type_id.extract_any_including_self( - engines, - filter_fn, - vec![], - depth + 1, - ), - ); - } - } TypeInfo::Alias { name: _, ty } => { extend( &mut found, @@ -697,13 +684,7 @@ impl TypeId { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| { - engines.te().insert( - engines, - TypeInfo::ErrorRecovery(err), - None, - ) - }), + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)), ctx.resolve_type( handler, t2.type_id, @@ -711,13 +692,7 @@ impl TypeId { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| { - engines.te().insert( - engines, - TypeInfo::ErrorRecovery(err), - None, - ) - }), + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)), ) }) }, diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index 29767d81fc0..dc089c9c25f 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -16,13 +16,12 @@ use sway_error::{ error::{CompileError, InvalidImplementingForType}, handler::{ErrorEmitted, Handler}, }; -use sway_types::{integer_bits::IntegerBits, span::Span, SourceId}; +use sway_types::{integer_bits::IntegerBits, span::Span}; use std::{ cmp::Ordering, fmt, hash::{Hash, Hasher}, - sync::Arc, }; #[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)] @@ -71,28 +70,6 @@ impl PartialEqWithEngines for VecSet { } } -/// Encapsulates type information and its optional source identifier. -#[derive(Debug, Default, Clone)] -pub struct TypeSourceInfo { - pub(crate) type_info: Arc, - /// The source id that created this type. - pub(crate) source_id: Option, -} - -impl HashWithEngines for TypeSourceInfo { - fn hash(&self, state: &mut H, engines: &Engines) { - self.type_info.hash(state, engines); - self.source_id.hash(state); - } -} - -impl EqWithEngines for TypeSourceInfo {} -impl PartialEqWithEngines for TypeSourceInfo { - fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool { - self.type_info.eq(&other.type_info, ctx) && self.source_id == other.source_id - } -} - /// Type information without an associated value, used for type inferencing and definition. #[derive(Debug, Clone, Default)] pub enum TypeInfo { @@ -162,12 +139,6 @@ pub enum TypeInfo { ErrorRecovery(ErrorEmitted), // Static, constant size arrays. Array(TypeArgument, Length), - /// Represents the entire storage declaration struct - /// Stored without initializers here, as typed struct fields, - /// so type checking is able to treat it as a struct with fields. - Storage { - fields: Vec, - }, /// Pointers. /// These are represented in memory as u64 but are a different type since pointers only make /// sense in the context they were created in. Users can obtain pointers via standard library @@ -178,8 +149,12 @@ pub enum TypeInfo { RawUntypedSlice, Ptr(TypeArgument), Slice(TypeArgument), - /// Type Alias. This type and the type `ty` it encapsulates always coerce. They are effectively - /// interchangeable + /// Type aliases. + /// This type and the type `ty` it encapsulates always coerce. They are effectively + /// interchangeable. + /// Currently, we support only non-generic type aliases. + // TODO: (GENERIC-TYPE-ALIASES) If we ever introduce generic type aliases, update the logic + // in the `TypeEngine` accordingly, e.g., the `is_type_changeable`. Alias { name: Ident, ty: TypeArgument, @@ -242,9 +217,6 @@ impl HashWithEngines for TypeInfo { call_path.hash(state, engines); type_arguments.as_deref().hash(state, engines); } - TypeInfo::Storage { fields } => { - fields.hash(state, engines); - } TypeInfo::Array(elem_ty, count) => { elem_ty.hash(state, engines); count.hash(state); @@ -355,16 +327,7 @@ impl PartialEqWithEngines for TypeInfo { && l_decl.fields.eq(&r_decl.fields, ctx) && l_decl.type_parameters.eq(&r_decl.type_parameters, ctx) } - (Self::Tuple(l), Self::Tuple(r)) => l - .iter() - .zip(r.iter()) - .map(|(l, r)| { - (l.type_id == r.type_id) - || type_engine - .get(l.type_id) - .eq(&type_engine.get(r.type_id), ctx) - }) - .all(|x| x), + (Self::Tuple(l), Self::Tuple(r)) => l.eq(r, ctx), ( Self::ContractCaller { abi_name: l_abi_name, @@ -386,9 +349,6 @@ impl PartialEqWithEngines for TypeInfo { .eq(&type_engine.get(r0.type_id), ctx)) && l1.val() == r1.val() } - (Self::Storage { fields: l_fields }, Self::Storage { fields: r_fields }) => { - l_fields.eq(r_fields, ctx) - } ( Self::Alias { name: l_name, @@ -522,9 +482,6 @@ impl OrdWithEngines for TypeInfo { .get(l0.type_id) .cmp(&type_engine.get(r0.type_id), ctx) .then_with(|| l1.val().cmp(&r1.val())), - (TypeInfo::Storage { fields: l_fields }, TypeInfo::Storage { fields: r_fields }) => { - l_fields.cmp(r_fields, ctx) - } ( Self::Alias { name: l_name, @@ -576,7 +533,7 @@ impl DisplayWithEngines for TypeInfo { Unknown => "{unknown}".into(), Never => "!".into(), UnknownGeneric { name, .. } => name.to_string(), - Placeholder(type_param) => type_param.name_ident.to_string(), + Placeholder(type_param) => type_param.name.to_string(), TypeParam(n) => format!("{n}"), StringSlice => "str".into(), StringArray(x) => format!("str[{}]", x.val()), @@ -640,7 +597,6 @@ impl DisplayWithEngines for TypeInfo { Array(elem_ty, count) => { format!("[{}; {}]", engines.help_out(elem_ty), count.val()) } - Storage { .. } => "storage".into(), RawUntypedPtr => "pointer".into(), RawUntypedSlice => "slice".into(), Ptr(ty) => { @@ -780,7 +736,6 @@ impl DebugWithEngines for TypeInfo { Array(elem_ty, count) => { format!("[{:?}; {}]", engines.help_out(elem_ty), count.val()) } - Storage { .. } => "contract storage".into(), RawUntypedPtr => "raw untyped ptr".into(), RawUntypedSlice => "raw untyped slice".into(), Ptr(ty) => { @@ -834,23 +789,31 @@ impl TypeInfo { TypeInfo::Contract => 13, TypeInfo::ErrorRecovery(_) => 14, TypeInfo::Array(_, _) => 15, - TypeInfo::Storage { .. } => 16, - TypeInfo::RawUntypedPtr => 17, - TypeInfo::RawUntypedSlice => 18, - TypeInfo::TypeParam(_) => 19, - TypeInfo::Alias { .. } => 20, - TypeInfo::Ptr(..) => 21, - TypeInfo::Slice(..) => 22, - TypeInfo::StringSlice => 23, - TypeInfo::TraitType { .. } => 24, - TypeInfo::Ref { .. } => 25, - TypeInfo::Never => 26, - TypeInfo::UntypedEnum(_) => 27, - TypeInfo::UntypedStruct(_) => 28, + TypeInfo::RawUntypedPtr => 16, + TypeInfo::RawUntypedSlice => 17, + TypeInfo::TypeParam(_) => 18, + TypeInfo::Alias { .. } => 19, + TypeInfo::Ptr(..) => 20, + TypeInfo::Slice(..) => 21, + TypeInfo::StringSlice => 22, + TypeInfo::TraitType { .. } => 23, + TypeInfo::Ref { .. } => 24, + TypeInfo::Never => 25, + TypeInfo::UntypedEnum(_) => 26, + TypeInfo::UntypedStruct(_) => 27, } } + /// Creates a new [TypeInfo::Custom] that represents a Self type. + /// + /// The `span` must either be a [Span::dummy] or a span pointing + /// to text "Self" or "self", otherwise the method panics. pub(crate) fn new_self_type(span: Span) -> TypeInfo { + assert!( + span.is_dummy() || span.as_str() == "Self" || span.as_str() == "self", + "The Self type span must either be a dummy span, or a span pointing to text \"Self\" or \"self\". The span was pointing to text: \"{}\".", + span.as_str() + ); TypeInfo::Custom { qualified_call_path: QualifiedCallPath { call_path: CallPath { @@ -1302,7 +1265,6 @@ impl TypeInfo { | TypeInfo::Contract | TypeInfo::ErrorRecovery(_) | TypeInfo::Array(_, _) - | TypeInfo::Storage { .. } | TypeInfo::Placeholder(_) | TypeInfo::TypeParam(_) | TypeInfo::Alias { .. } @@ -1380,7 +1342,6 @@ impl TypeInfo { | TypeInfo::ContractCaller { .. } | TypeInfo::Custom { .. } | TypeInfo::Contract - | TypeInfo::Storage { .. } | TypeInfo::Placeholder(_) | TypeInfo::TypeParam(_) | TypeInfo::TraitType { .. } => { @@ -1444,7 +1405,6 @@ impl TypeInfo { )), TypeInfo::Unknown | TypeInfo::ContractCaller { .. } - | TypeInfo::Storage { .. } | TypeInfo::Placeholder(_) | TypeInfo::TypeParam(_) => Err(handler.emit_err( CompileError::TypeIsNotValidAsImplementingFor { @@ -1457,54 +1417,6 @@ impl TypeInfo { } } - pub(crate) fn can_change(&self, engines: &Engines) -> bool { - // TODO: there might be an optimization here that if the type params hold - // only non-dynamic types, then it doesn't matter that there are type params - match self { - TypeInfo::UntypedEnum(decl_id) => { - let decl = engines.pe().get_enum(decl_id); - !decl.type_parameters.is_empty() - } - TypeInfo::UntypedStruct(decl_id) => { - let decl = engines.pe().get_struct(decl_id); - !decl.type_parameters.is_empty() - } - TypeInfo::Enum(decl_ref) => { - let decl = engines.de().get_enum(decl_ref); - !decl.type_parameters.is_empty() - } - TypeInfo::Struct(decl_ref) => { - let decl = engines.de().get_struct(decl_ref); - !decl.type_parameters.is_empty() - } - TypeInfo::StringArray(_) - | TypeInfo::StringSlice - | TypeInfo::UnsignedInteger(_) - | TypeInfo::Boolean - | TypeInfo::B256 - | TypeInfo::RawUntypedPtr - | TypeInfo::RawUntypedSlice - | TypeInfo::Ptr(_) - | TypeInfo::ErrorRecovery(_) - | TypeInfo::TraitType { .. } - | TypeInfo::Never => false, - TypeInfo::Unknown - | TypeInfo::UnknownGeneric { .. } - | TypeInfo::ContractCaller { .. } - | TypeInfo::Custom { .. } - | TypeInfo::Tuple(_) - | TypeInfo::Array(_, _) - | TypeInfo::Slice(_) - | TypeInfo::Contract - | TypeInfo::Storage { .. } - | TypeInfo::Numeric - | TypeInfo::Placeholder(_) - | TypeInfo::TypeParam(_) - | TypeInfo::Alias { .. } - | TypeInfo::Ref { .. } => true, - } - } - /// Checks if a given [TypeInfo] has a valid constructor. pub(crate) fn has_valid_constructor(&self, decl_engine: &DeclEngine) -> bool { match self { @@ -1807,7 +1719,6 @@ impl TypeInfo { length.val() ) } - Storage { .. } => "contract storage".into(), RawUntypedPtr => "raw untyped ptr".into(), RawUntypedSlice => "raw untyped slice".into(), Ptr(ty) => { diff --git a/sway-core/src/type_system/mod.rs b/sway-core/src/type_system/mod.rs index 37446b5843c..fedf09bb480 100644 --- a/sway-core/src/type_system/mod.rs +++ b/sway-core/src/type_system/mod.rs @@ -77,32 +77,22 @@ fn generic_enum_resolution() { a: _ } */ - let generic_type = engines.te().insert( - &engines, - TypeInfo::UnknownGeneric { - name: generic_name.clone(), - trait_constraints: VecSet(Vec::new()), - parent: None, - is_from_type_parameter: false, - }, - None, - ); - let placeholder_type = engines.te().insert( - &engines, - TypeInfo::Placeholder(TypeParameter { - type_id: generic_type, - initial_type_id: generic_type, - name_ident: generic_name.clone(), - trait_constraints: vec![], - trait_constraints_span: sp.clone(), - is_from_parent: false, - }), - None, - ); + let generic_type = + engines + .te() + .new_unknown_generic(generic_name.clone(), VecSet(vec![]), None, false); + let placeholder_type = engines.te().new_placeholder(TypeParameter { + type_id: generic_type, + initial_type_id: generic_type, + name: generic_name.clone(), + trait_constraints: vec![], + trait_constraints_span: sp.clone(), + is_from_parent: false, + }); let placeholder_type_param = TypeParameter { type_id: placeholder_type, initial_type_id: placeholder_type, - name_ident: generic_name.clone(), + name: generic_name.clone(), trait_constraints: vec![], trait_constraints_span: sp.clone(), is_from_parent: false, @@ -133,16 +123,14 @@ fn generic_enum_resolution() { }, None, ); - let ty_1 = engines - .te() - .insert(&engines, TypeInfo::Enum(*decl_ref_1.id()), None); + let ty_1 = engines.te().insert_enum(&engines, *decl_ref_1.id()); /* Result { a: bool } */ - let boolean_type = engines.te().insert(&engines, TypeInfo::Boolean, None); + let boolean_type = engines.te().id_of_bool(); let variant_types = vec![ty::TyEnumVariant { name: a_name, tag: 0, @@ -158,7 +146,7 @@ fn generic_enum_resolution() { let type_param = TypeParameter { type_id: boolean_type, initial_type_id: boolean_type, - name_ident: generic_name, + name: generic_name, trait_constraints: vec![], trait_constraints_span: sp.clone(), is_from_parent: false, @@ -177,9 +165,7 @@ fn generic_enum_resolution() { }, None, ); - let ty_2 = engines - .te() - .insert(&engines, TypeInfo::Enum(*decl_ref_2.id()), None); + let ty_2 = engines.te().insert_enum(&engines, *decl_ref_2.id()); // Unify them together... let h = Handler::default(); @@ -206,12 +192,8 @@ fn basic_numeric_unknown() { let sp = Span::dummy(); // numerics - let id = engines.te().insert(&engines, TypeInfo::Numeric, None); - let id2 = engines.te().insert( - &engines, - TypeInfo::UnsignedInteger(IntegerBits::Eight), - None, - ); + let id = engines.te().new_numeric(); + let id2 = engines.te().id_of_u8(); // Unify them together... let h = Handler::default(); @@ -232,12 +214,8 @@ fn unify_numerics() { let sp = Span::dummy(); // numerics - let id = engines.te().insert(&engines, TypeInfo::Numeric, None); - let id2 = engines.te().insert( - &engines, - TypeInfo::UnsignedInteger(IntegerBits::Eight), - None, - ); + let id = engines.te().new_numeric(); + let id2 = engines.te().id_of_u8(); // Unify them together... let h = Handler::default(); @@ -259,12 +237,8 @@ fn unify_numerics_2() { let sp = Span::dummy(); // numerics - let id = type_engine.insert(&engines, TypeInfo::Numeric, None); - let id2 = type_engine.insert( - &engines, - TypeInfo::UnsignedInteger(IntegerBits::Eight), - None, - ); + let id = engines.te().new_numeric(); + let id2 = engines.te().id_of_u8(); // Unify them together... let h = Handler::default(); diff --git a/sway-core/src/type_system/monomorphization.rs b/sway-core/src/type_system/monomorphization.rs index 674650896db..ffe432f2292 100644 --- a/sway-core/src/type_system/monomorphization.rs +++ b/sway-core/src/type_system/monomorphization.rs @@ -14,7 +14,7 @@ use crate::{ semantic_analysis::type_resolve::resolve_type, type_system::ast_elements::create_type_id::CreateTypeId, EnforceTypeArguments, Engines, Namespace, SubstTypes, SubstTypesContext, TypeArgument, TypeId, - TypeInfo, TypeParameter, TypeSubstMap, + TypeParameter, TypeSubstMap, }; pub(crate) trait MonomorphizeHelper { @@ -130,11 +130,7 @@ where self_type, subst_ctx, ) - .unwrap_or_else(|err| { - engines - .te() - .insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); } let type_mapping = TypeSubstMap::from_type_parameters_and_type_arguments( value @@ -259,11 +255,7 @@ pub(crate) fn type_decl_opt_to_type_id( ); // create the type id from the copy - type_engine.insert( - engines, - TypeInfo::Struct(*new_decl_ref.id()), - new_decl_ref.span().source_id(), - ) + type_engine.insert_struct(engines, *new_decl_ref.id()) } Some(ResolvedDeclaration::Typed(ty::TyDecl::EnumDecl(ty::EnumDecl { decl_id: original_id, @@ -293,11 +285,7 @@ pub(crate) fn type_decl_opt_to_type_id( ); // create the type id from the copy - type_engine.insert( - engines, - TypeInfo::Enum(*new_decl_ref.id()), - new_decl_ref.span().source_id(), - ) + type_engine.insert_enum(engines, *new_decl_ref.id()) } Some(ResolvedDeclaration::Typed(ty::TyDecl::TypeAliasDecl(ty::TypeAliasDecl { decl_id: original_id, @@ -305,8 +293,8 @@ pub(crate) fn type_decl_opt_to_type_id( }))) => { let new_copy = decl_engine.get_type_alias(&original_id); - // TODO: monomorphize the copy, in place, when generic type aliases are - // supported + // TODO: (GENERIC-TYPE-ALIASES) Monomorphize the copy, in place, once generic type aliases are + // supported. new_copy.create_type_id(engines) } @@ -321,14 +309,7 @@ pub(crate) fn type_decl_opt_to_type_id( if let Some(ty) = &decl_type.ty { ty.type_id } else if let Some(implementing_type) = self_type { - type_engine.insert( - engines, - TypeInfo::TraitType { - name: decl_type.name.clone(), - trait_type_id: implementing_type, - }, - decl_type.name.span().source_id(), - ) + type_engine.insert_trait_type(engines, decl_type.name.clone(), implementing_type) } else { return Err(handler.emit_err(CompileError::Internal( "Self type not provided.", @@ -341,7 +322,7 @@ pub(crate) fn type_decl_opt_to_type_id( name: call_path.to_string(), span: call_path.span(), }); - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) + type_engine.id_of_error_recovery(err) } }) } diff --git a/sway-core/src/type_system/priv_prelude.rs b/sway-core/src/type_system/priv_prelude.rs index fdf2a4138a9..477cf76f169 100644 --- a/sway-core/src/type_system/priv_prelude.rs +++ b/sway-core/src/type_system/priv_prelude.rs @@ -22,5 +22,5 @@ pub use super::{ engine::IsConcrete, engine::TypeEngine, id::{IncludeSelf, TreatNumericAs, TypeId}, - info::{AbiEncodeSizeHint, AbiName, TypeInfo, TypeSourceInfo}, + info::{AbiEncodeSizeHint, AbiName, TypeInfo}, }; diff --git a/sway-core/src/type_system/substitute/subst_map.rs b/sway-core/src/type_system/substitute/subst_map.rs index 4b1a9fa93c7..36de9b4846a 100644 --- a/sway-core/src/type_system/substitute/subst_map.rs +++ b/sway-core/src/type_system/substitute/subst_map.rs @@ -8,7 +8,6 @@ use crate::{ type_system::priv_prelude::*, }; use std::{collections::BTreeMap, fmt}; -use sway_types::Spanned; type SourceType = TypeId; type DestinationType = TypeId; @@ -94,11 +93,7 @@ impl TypeSubstMap { .map(|type_param| { ( type_param.type_id, - type_engine.insert( - engines, - TypeInfo::Placeholder(type_param.clone()), - type_param.name_ident.span().source_id(), - ), + type_engine.new_placeholder(type_param.clone()), ) }) .collect(); @@ -256,29 +251,6 @@ impl TypeSubstMap { vec![type_argument.type_id], ) } - ( - TypeInfo::Storage { - fields: type_parameters, - }, - TypeInfo::Storage { - fields: type_arguments, - }, - ) => { - let type_parameters = type_parameters - .iter() - .map(|x| x.type_argument.type_id) - .collect::>(); - let type_arguments = type_arguments - .iter() - .map(|x| x.type_argument.type_id) - .collect::>(); - TypeSubstMap::from_superset_and_subset_helper( - type_engine, - decl_engine, - type_parameters, - type_arguments, - ) - } (TypeInfo::Unknown, TypeInfo::Unknown) | (TypeInfo::Boolean, TypeInfo::Boolean) | (TypeInfo::B256, TypeInfo::B256) @@ -350,10 +322,10 @@ impl TypeSubstMap { /// A match is potentially created (i.e. a new [TypeId] is created) in these /// circumstances: /// - `type_id` is one of the following: [TypeInfo::Struct], [TypeInfo::Enum], - /// [TypeInfo::Array], [TypeInfo::Tuple], [TypeInfo::Storage], [TypeInfo::Alias], - /// [TypeInfo::Alias], [TypeInfo::Ptr], [TypeInfo::Slice], or [TypeInfo::Ref], - /// and one of the contained types (e.g. a struct field, or a referenced type) - /// finds a match in a recursive call to `find_match`. + /// [TypeInfo::Array], [TypeInfo::Tuple], [TypeInfo::Alias], [TypeInfo::Ptr], + /// [TypeInfo::Slice], or [TypeInfo::Ref], + /// - and one of the contained types (e.g. a struct field, or a referenced type) + /// finds a match in a recursive call to `find_match`. /// /// A match cannot be found in any other circumstance. pub(crate) fn find_match(&self, type_id: TypeId, engines: &Engines) -> Option { @@ -440,11 +412,7 @@ impl TypeSubstMap { if need_to_create_new { let new_decl_ref = decl_engine.insert(decl, decl_engine.get_parsed_decl_id(&decl_id).as_ref()); - Some(type_engine.insert( - engines, - TypeInfo::Struct(*new_decl_ref.id()), - new_decl_ref.decl_span().source_id(), - )) + Some(type_engine.insert_struct(engines, *new_decl_ref.id())) } else { None } @@ -469,75 +437,37 @@ impl TypeSubstMap { if need_to_create_new { let new_decl_ref = decl_engine.insert(decl, decl_engine.get_parsed_decl_id(&decl_id).as_ref()); - Some(type_engine.insert( - engines, - TypeInfo::Enum(*new_decl_ref.id()), - new_decl_ref.decl_span().source_id(), - )) + Some(type_engine.insert_enum(engines, *new_decl_ref.id())) } else { None } } - TypeInfo::Array(mut elem_ty, count) => { - self.find_match(elem_ty.type_id, engines).map(|type_id| { - elem_ty.type_id = type_id; - type_engine.insert( - engines, - TypeInfo::Array(elem_ty.clone(), count.clone()), - elem_ty.span.source_id(), - ) + TypeInfo::Array(mut elem_type, length) => { + self.find_match(elem_type.type_id, engines).map(|type_id| { + elem_type.type_id = type_id; + type_engine.insert_array(engines, elem_type, length) }) } - TypeInfo::Slice(mut elem_ty) => { - let type_id = self.find_match(elem_ty.type_id, engines)?; - elem_ty.type_id = type_id; - Some(type_engine.insert( - engines, - TypeInfo::Slice(elem_ty.clone()), - elem_ty.span.source_id(), - )) + TypeInfo::Slice(mut elem_type) => { + self.find_match(elem_type.type_id, engines).map(|type_id| { + elem_type.type_id = type_id; + type_engine.insert_slice(engines, elem_type) + }) } TypeInfo::Tuple(fields) => { let mut need_to_create_new = false; - let mut source_id = None; let fields = fields .into_iter() .map(|mut field| { if let Some(type_id) = self.find_match(field.type_id, engines) { need_to_create_new = true; - source_id = field.span.source_id().cloned(); field.type_id = type_id; } field.clone() }) .collect::>(); if need_to_create_new { - Some(type_engine.insert(engines, TypeInfo::Tuple(fields), source_id.as_ref())) - } else { - None - } - } - TypeInfo::Storage { fields } => { - let mut need_to_create_new = false; - let mut source_id = None; - let fields = fields - .into_iter() - .map(|mut field| { - if let Some(type_id) = self.find_match(field.type_argument.type_id, engines) - { - need_to_create_new = true; - source_id = field.span.source_id().copied(); - field.type_argument.type_id = type_id; - } - field.clone() - }) - .collect::>(); - if need_to_create_new { - Some(type_engine.insert( - engines, - TypeInfo::Storage { fields }, - source_id.as_ref(), - )) + Some(type_engine.insert_tuple(engines, fields)) } else { None } @@ -545,19 +475,12 @@ impl TypeSubstMap { TypeInfo::Alias { name, mut ty } => { self.find_match(ty.type_id, engines).map(|type_id| { ty.type_id = type_id; - type_engine.insert( - engines, - TypeInfo::Alias { - name: name.clone(), - ty: ty.clone(), - }, - ty.span.source_id(), - ) + type_engine.new_alias(engines, name, ty) }) } TypeInfo::Ptr(mut ty) => self.find_match(ty.type_id, engines).map(|type_id| { ty.type_id = type_id; - type_engine.insert(engines, TypeInfo::Ptr(ty.clone()), ty.span.source_id()) + type_engine.insert_ptr(engines, ty) }), TypeInfo::TraitType { .. } => iter_for_match(engines, self, &type_info), TypeInfo::Ref { @@ -565,14 +488,7 @@ impl TypeSubstMap { referenced_type: mut ty, } => self.find_match(ty.type_id, engines).map(|type_id| { ty.type_id = type_id; - type_engine.insert( - engines, - TypeInfo::Ref { - to_mutable_value, - referenced_type: ty.clone(), - }, - ty.span.source_id(), - ) + type_engine.insert_ref(engines, to_mutable_value, ty) }), TypeInfo::Unknown | TypeInfo::Never @@ -607,7 +523,7 @@ fn iter_for_match( TypeInfo::Placeholder(current_type_param), ) = ((*source_type_info).clone(), type_info) { - if source_type_param.name_ident.as_str() == current_type_param.name_ident.as_str() + if source_type_param.name.as_str() == current_type_param.name.as_str() && current_type_param .trait_constraints .iter() diff --git a/sway-core/src/type_system/unify/unifier.rs b/sway-core/src/type_system/unify/unifier.rs index 41b72802602..b77bd83fe9a 100644 --- a/sway-core/src/type_system/unify/unifier.rs +++ b/sway-core/src/type_system/unify/unifier.rs @@ -61,15 +61,11 @@ impl<'a> Unifier<'a> { expected_type_info: &TypeInfo, span: &Span, ) { - let type_engine = self.engines.te(); - let source_id = span.source_id().copied(); - type_engine.replace( + self.engines.te().replace_with_new_source_id( self.engines, received, - TypeSourceInfo { - type_info: expected_type_info.clone().into(), - source_id, - }, + expected_type_info.clone(), + span.source_id().copied(), ); } @@ -80,15 +76,11 @@ impl<'a> Unifier<'a> { received_type_info: &TypeInfo, span: &Span, ) { - let type_engine = self.engines.te(); - let source_id = span.source_id().copied(); - type_engine.replace( + self.engines.te().replace_with_new_source_id( self.engines, expected, - TypeSourceInfo { - type_info: received_type_info.clone().into(), - source_id, - }, + received_type_info.clone(), + span.source_id().copied(), ); } diff --git a/sway-core/src/type_system/unify/unify_check.rs b/sway-core/src/type_system/unify/unify_check.rs index 9adb491678c..ed8cdbbbb2b 100644 --- a/sway-core/src/type_system/unify/unify_check.rs +++ b/sway-core/src/type_system/unify/unify_check.rs @@ -527,7 +527,6 @@ impl<'a> UnifyCheck<'a> { // engine (TypeInfo::Unknown, TypeInfo::Unknown) => false, (TypeInfo::Numeric, TypeInfo::Numeric) => false, - (TypeInfo::Storage { .. }, TypeInfo::Storage { .. }) => false, // these cases are able to be directly compared (TypeInfo::Contract, TypeInfo::Contract) => true, diff --git a/sway-lsp/README.md b/sway-lsp/README.md index 940ec11a269..ffae83b3f0c 100644 --- a/sway-lsp/README.md +++ b/sway-lsp/README.md @@ -27,3 +27,13 @@ _Coming Soon_ 1. Install the [Fuel toolchain](https://fuellabs.github.io/fuelup/master/installation/index.html). 1. Ensure `forc-lsp` is installed correctly by entering `forc-lsp --version` into your terminal. 1. Install the [Sway VSCode plugin](https://marketplace.visualstudio.com/items?itemName=FuelLabs.sway-vscode-plugin). + +## Trying out the local version + +To try out the local LSP version: + +1. Install the local version of the server: `cargo install --path ./forc-plugins/forc-lsp`. +1. Open VSCode settings and set the `Sway-lsp › Diagnostic: Bin Path` to the installed `forc-lsp` binary. The path to the binary will be listed at the end of the `cargo install` command and is usually: `/home//.cargo/bin/forc-lsp`. +1. Open an arbitrary Sway project. E.g., `./examples/arrays`. +1. Open the _Output_ window in VSCode and select _Sway Language Server_ from the drop down menu. +1. Start coding and observe the LSP output in the _Output_ window. This window will also show any `dbg!` or `eprintln!` lines. \ No newline at end of file diff --git a/sway-lsp/src/capabilities/code_actions/common/generate_impl.rs b/sway-lsp/src/capabilities/code_actions/common/generate_impl.rs index 8b64838e1c3..d12bbd402b1 100644 --- a/sway-lsp/src/capabilities/code_actions/common/generate_impl.rs +++ b/sway-lsp/src/capabilities/code_actions/common/generate_impl.rs @@ -21,7 +21,7 @@ pub(crate) trait GenerateImplCodeAction<'a, T: Spanned>: CodeAction<'a, T> { Some( type_params .iter() - .map(|param| param.name_ident.to_string()) + .map(|param| param.name.to_string()) .collect::>() .join(", "), ) diff --git a/sway-lsp/src/server_state.rs b/sway-lsp/src/server_state.rs index 5e2a227f3f5..cafb4bb5fe6 100644 --- a/sway-lsp/src/server_state.rs +++ b/sway-lsp/src/server_state.rs @@ -130,13 +130,9 @@ impl ServerState { while let Ok(msg) = rx.recv() { match msg { TaskMessage::CompilationContext(ctx) => { - dbg!(); let uri = ctx.uri.as_ref().unwrap().clone(); - dbg!(); let session = ctx.session.as_ref().unwrap().clone(); - dbg!(); let mut engines_clone = session.engines.read().clone(); - dbg!(); // Perform garbage collection if enabled to manage memory usage. if ctx.gc_options.gc_enabled { @@ -151,16 +147,13 @@ impl ServerState { ); } } - dbg!(); let lsp_mode = Some(LspConfig { optimized_build: ctx.optimized_build, file_versions: ctx.file_versions, }); - dbg!(); // Set the is_compiling flag to true so that the wait_for_parsing function knows that we are compiling is_compiling.store(true, Ordering::SeqCst); - dbg!(); match session::parse_project( &uri, &engines_clone, @@ -170,10 +163,10 @@ impl ServerState { ) { Ok(()) => { let path = uri.to_file_path().unwrap(); - // Find the module id from the path + // Find the program id from the path match session::program_id_from_path(&path, &engines_clone) { Ok(program_id) => { - // Use the module id to get the metrics for the module + // Use the program id to get the metrics for the program if let Some(metrics) = session.metrics.get(&program_id) { // It's very important to check if the workspace AST was reused to determine if we need to overwrite the engines. // Because the engines_clone has garbage collection applied. If the workspace AST was reused, we need to keep the old engines @@ -202,26 +195,21 @@ impl ServerState { } } Err(_err) => { - dbg!(_err); *last_compilation_state.write() = LastCompilationState::Failed; } } - dbg!(); // Reset the flags to false is_compiling.store(false, Ordering::SeqCst); retrigger_compilation.store(false, Ordering::SeqCst); - dbg!(); // Make sure there isn't any pending compilation work if rx.is_empty() { // finished compilation, notify waiters finished_compilation.notify_waiters(); } - dbg!(); } TaskMessage::Terminate => { - dbg!(); // If we receive a terminate message, we need to exit the thread return; } @@ -305,7 +293,6 @@ impl ServerState { session: Arc, ) { let diagnostics = self.diagnostics(&uri, session.clone()); - dbg!(&diagnostics); // Note: Even if the computed diagnostics vec is empty, we still have to push the empty Vec // in order to clear former diagnostics. Newly pushed diagnostics always replace previously pushed diagnostics. if let Some(client) = self.client.as_ref() { diff --git a/sway-lsp/src/traverse/parsed_tree.rs b/sway-lsp/src/traverse/parsed_tree.rs index 87f30cd8017..1578975143e 100644 --- a/sway-lsp/src/traverse/parsed_tree.rs +++ b/sway-lsp/src/traverse/parsed_tree.rs @@ -1059,7 +1059,7 @@ impl Parse for EnumVariant { impl Parse for TypeParameter { fn parse(&self, ctx: &ParseContext) { ctx.tokens.insert( - ctx.ident(&self.name_ident), + ctx.ident(&self.name), Token::from_parsed( ParsedAstToken::TypeParameter(self.clone()), SymbolKind::TypeParameter, diff --git a/sway-lsp/src/traverse/typed_tree.rs b/sway-lsp/src/traverse/typed_tree.rs index 9d23bae7316..7fc3461abca 100644 --- a/sway-lsp/src/traverse/typed_tree.rs +++ b/sway-lsp/src/traverse/typed_tree.rs @@ -659,7 +659,7 @@ impl Parse for ty::FunctionDecl { ctx, type_param.type_id, &typed_token, - type_param.name_ident.span(), + type_param.name.span(), ); }); collect_type_argument(ctx, &func_decl.return_type); @@ -672,8 +672,8 @@ impl Parse for ty::FunctionDecl { if let Some(param_decl_ident) = func_decl .type_parameters .par_iter() - .find_any(|type_param| type_param.name_ident.as_str() == ident.as_str()) - .map(|type_param| type_param.name_ident.clone()) + .find_any(|type_param| type_param.name.as_str() == ident.as_str()) + .map(|type_param| type_param.name.clone()) { token.type_def = Some(TypeDefinition::Ident(param_decl_ident)); } @@ -732,7 +732,7 @@ impl Parse for ty::StructDecl { adaptive_iter(&struct_decl.type_parameters, |type_param| { if let Some(mut token) = ctx .tokens - .try_get_mut_with_retry(&ctx.ident(&type_param.name_ident)) + .try_get_mut_with_retry(&ctx.ident(&type_param.name)) { token.ast_node = TokenAstNode::Typed(TypedAstToken::TypedParameter(type_param.clone())); @@ -759,7 +759,7 @@ impl Parse for ty::ImplSelfOrTrait { ctx, param.type_id, &TypedAstToken::TypedParameter(param.clone()), - param.name_ident.span(), + param.name.span(), ); }); adaptive_iter(&trait_name.prefixes, |ident| { @@ -958,7 +958,7 @@ impl Parse for ty::TyFunctionDecl { ctx, type_param.type_id, &typed_token, - type_param.name_ident.span(), + type_param.name.span(), ); }); collect_type_argument(ctx, &self.return_type); @@ -971,8 +971,8 @@ impl Parse for ty::TyFunctionDecl { if let Some(param_decl_ident) = self .type_parameters .par_iter() - .find_any(|type_param| type_param.name_ident.as_str() == ident.as_str()) - .map(|type_param| type_param.name_ident.clone()) + .find_any(|type_param| type_param.name.as_str() == ident.as_str()) + .map(|type_param| type_param.name.clone()) { token.type_def = Some(TypeDefinition::Ident(param_decl_ident)); } @@ -1329,7 +1329,7 @@ fn collect_type_id( ctx, param.type_id, &TypedAstToken::TypedParameter(param.clone()), - param.name_ident.span(), + param.name.span(), ); }); adaptive_iter(&decl.variants, |variant| { @@ -1349,7 +1349,7 @@ fn collect_type_id( ctx, param.type_id, &TypedAstToken::TypedParameter(param.clone()), - param.name_ident.span(), + param.name.span(), ); }); adaptive_iter(&decl.fields, |field| { @@ -1373,11 +1373,6 @@ fn collect_type_id( }); } } - TypeInfo::Storage { fields } => { - adaptive_iter(fields, |field| { - field.parse(ctx); - }); - } _ => { if let Some(token) = ctx .tokens @@ -1458,7 +1453,7 @@ fn collect_enum(ctx: &ParseContext, decl_id: &DeclId, declaratio adaptive_iter(&enum_decl.type_parameters, |type_param| { if let Some(mut token) = ctx .tokens - .try_get_mut_with_retry(&ctx.ident(&type_param.name_ident)) + .try_get_mut_with_retry(&ctx.ident(&type_param.name)) { token.ast_node = TokenAstNode::Typed(TypedAstToken::TypedParameter(type_param.clone())); token.type_def = Some(TypeDefinition::TypeId(type_param.type_id)); diff --git a/sway-lsp/tests/lib.rs b/sway-lsp/tests/lib.rs index c377db53bf5..39e9174a96f 100644 --- a/sway-lsp/tests/lib.rs +++ b/sway-lsp/tests/lib.rs @@ -5,18 +5,18 @@ pub mod integration; use crate::integration::{code_actions, lsp}; use lsp_types::*; use rayon::prelude::*; -use std::{fs, panic, path::PathBuf, process::Command, sync::Mutex}; +use std::{ + fs, panic, + path::PathBuf, + process::{Command, Stdio}, + sync::Mutex, +}; use sway_lsp::{ config::LspClient, handlers::{notification, request}, server_state::ServerState, }; -use sway_lsp_test_utils::{ - assert_server_requests, dir_contains_forc_manifest, doc_comments_dir, e2e_language_dir, - e2e_test_dir, generic_impl_self_dir, get_fixture, load_sway_example, random_delay, - runnables_test_dir, self_impl_reassignment_dir, setup_panic_hook, sway_workspace_dir, - test_fixtures_dir, -}; +use sway_lsp_test_utils::*; use tower_lsp::LspService; /// Holds the information needed to check the response of a goto definition request. @@ -2161,35 +2161,75 @@ async fn garbage_collection_runner(path: PathBuf) { shutdown_and_exit(&mut service).await; } +/// Contains representable individual projects suitable for GC tests, +/// as well as projects in which GC was failing, and that are not +/// included in [garbage_collection_all_language_tests]. #[test] -fn garbage_collection_storage() { - let p = sway_workspace_dir() - .join("sway-lsp/tests/fixtures/garbage_collection/storage_contract") - .join("src/main.sw"); - run_async!({ - garbage_collection_runner(p).await; - }); +fn garbage_collection_tests() -> Result<(), String> { + let mut tests = vec![ + // TODO: Enable this test once https://github.com/FuelLabs/sway/issues/6687 is fixed. + // ( + // "option_eq".into(), + // sway_workspace_dir() + // .join(e2e_stdlib_dir()) + // .join("option_eq") + // .join("src/main.sw"), + // ), + ( + "arrays".into(), + sway_workspace_dir() + .join("examples/arrays") + .join("src/main.sw"), + ), + ( + "minimal_script".into(), + sway_workspace_dir() + .join("sway-lsp/tests/fixtures/garbage_collection/minimal_script") + .join("src/main.sw"), + ), + ( + "paths".into(), + test_fixtures_dir().join("tokens/paths/src/main.sw"), + ), + ( + "storage_contract".into(), + sway_workspace_dir() + .join("sway-lsp/tests/fixtures/garbage_collection/storage_contract") + .join("src/main.sw"), + ), + ]; + + tests.sort(); + + run_garbage_collection_tests(&tests, None) } #[test] -fn garbage_collection_paths() { - let p = test_fixtures_dir().join("tokens/paths/src/main.sw"); - run_async!({ - garbage_collection_runner(p).await; - }); +fn garbage_collection_all_language_tests() -> Result<(), String> { + run_garbage_collection_tests_from_projects_dir(e2e_language_dir()) } #[test] -fn garbage_collection_minimal_script() { - let p = sway_workspace_dir() - .join("sway-lsp/tests/fixtures/garbage_collection/minimal_script") - .join("src/main.sw"); - run_async!({ - garbage_collection_runner(p).await; - }); +#[ignore = "Additional stress test for GC. Run it locally when working on code that affects GC."] +fn garbage_collection_all_should_pass_tests() -> Result<(), String> { + run_garbage_collection_tests_from_projects_dir(e2e_should_pass_dir()) } -/// Tests garbage collection across all language test examples in parallel. +#[test] +#[ignore = "Additional stress test for GC. Run it locally when working on code that affects GC."] +fn garbage_collection_all_should_fail_tests() -> Result<(), String> { + run_garbage_collection_tests_from_projects_dir(e2e_should_fail_dir()) +} + +#[test] +#[ignore = "Additional stress test for GC. Run it locally when working on code that affects GC."] +fn garbage_collection_all_stdlib_tests() -> Result<(), String> { + run_garbage_collection_tests_from_projects_dir(e2e_stdlib_dir()) +} + +/// Parallel test runner for garbage collection tests across Sway projects defined by `tests`. +/// Each test in `tests` consists of a project name and the path to the file that will +/// be changed during the test (keystroke simulation will be in that file). /// /// # Overview /// This test suite takes a unique approach to handling test isolation and error reporting: @@ -2206,76 +2246,130 @@ fn garbage_collection_minimal_script() { /// examples need garbage collection fixes. /// /// # Implementation Details -/// - Uses std::process::Command to spawn each test in isolation -/// - Collects results through a thread-safe Mutex +/// - Uses [std::process::Command] to spawn each test in isolation +/// - Collects results through a thread-safe [Mutex] /// - Provides detailed error reporting for failed tests /// - Categorizes different types of failures (exit codes vs signals) -// #[test] -#[allow(dead_code)] -fn run_all_garbage_collection_tests() { - let base_dir = sway_workspace_dir().join(e2e_language_dir()); - let entries: Vec<_> = std::fs::read_dir(base_dir) - .unwrap() - .filter_map(|e| e.ok()) - .filter(|e| e.file_type().map(|ft| ft.is_dir()).unwrap_or(false)) - .collect(); - - let results = Mutex::new(Vec::new()); - +fn run_garbage_collection_tests( + tests: &[(String, PathBuf)], + base_dir: Option, +) -> Result<(), String> { println!("\n=== Starting Garbage Collection Tests ===\n"); - entries.par_iter().for_each(|entry| { - let project_dir = entry.path(); - let project_name = project_dir - .file_name() - .unwrap() - .to_string_lossy() - .to_string(); - let main_file = project_dir.join("src/main.sw"); + match base_dir { + Some(base_dir) => { + println!("▶ Testing {} project(s) in '{base_dir}'\n", tests.len()); + } + None => { + println!("▶ Testing {} project(s):", tests.len()); + let max_project_name_len = tests + .iter() + .map(|(project_name, _)| project_name.len()) + .max() + .unwrap_or_default(); + tests.iter().for_each(|(project_name, test_file)| { + println!( + "- {project_name: 0 { - println!("\nFailed Projects:"); - for (name, _, error) in results.iter().filter(|r| !r.1) { - println!("- {} (Error: {})", name, error.as_ref().unwrap()); + println!("Failed projects:"); + for (project_name, test_file, _, error) in results.iter().filter(|r| !r.2) { + println!("- Project: {project_name}"); + println!(" Path: {test_file}"); + println!(" Error: {}", error.as_ref().unwrap()); } - panic!("{} projects failed garbage collection testing", failed); + println!(); + + Err(format!( + "{} project(s) failed garbage collection testing", + failed + )) + } else { + Ok(()) } } +/// Test runner for garbage collection tests across all Sway projects found in the `projects_dir`. +/// Tests run in parallel and include only the projects that have `src/main.sw` file. +fn run_garbage_collection_tests_from_projects_dir(projects_dir: PathBuf) -> Result<(), String> { + let base_dir = sway_workspace_dir().join(projects_dir); + let mut tests: Vec<_> = std::fs::read_dir(base_dir.clone()) + .unwrap() + .filter_map(|e| e.ok()) + .filter(|e| e.file_type().map(|ft| ft.is_dir()).unwrap_or(false)) + .map(|dir_entry| { + let project_dir = dir_entry.path(); + let project_name = project_dir + .file_name() + .unwrap() + .to_string_lossy() + .to_string(); + let main_file = project_dir.join("src/main.sw"); + (project_name, main_file) + }) + .filter(|(_, main_file)| main_file.exists()) + .collect(); + + tests.sort(); + + run_garbage_collection_tests(&tests, Some(base_dir.to_string_lossy().to_string())) +} + /// Individual test runner executed in a separate process for each test. /// /// This function is called by the main test runner through a new process invocation @@ -2287,12 +2381,11 @@ fn run_all_garbage_collection_tests() { /// 1. Tests are completely isolated from each other /// 2. Panics in one test don't affect others /// 3. Resource cleanup happens automatically on process exit -// #[tokio::test] -#[allow(dead_code)] -async fn test_single_project() { - if let Ok(file) = std::env::var("TEST_FILE") { - println!("Running single test for file: {}", file); - let path = PathBuf::from(file); +#[tokio::test] +#[ignore = "This test is meant to be run only indirectly through the tests that run GC in parallel."] +async fn test_single_garbage_collection_project() { + if let Ok(test_file) = std::env::var("TEST_FILE") { + let path = PathBuf::from(test_file); garbage_collection_runner(path).await; } else { panic!("TEST_FILE environment variable not set"); diff --git a/sway-lsp/tests/utils/src/lib.rs b/sway-lsp/tests/utils/src/lib.rs index be741f8798b..6f42b4d3f08 100644 --- a/sway-lsp/tests/utils/src/lib.rs +++ b/sway-lsp/tests/utils/src/lib.rs @@ -28,6 +28,18 @@ pub fn e2e_language_dir() -> PathBuf { PathBuf::from("test/src/e2e_vm_tests/test_programs/should_pass/language") } +pub fn e2e_should_pass_dir() -> PathBuf { + PathBuf::from("test/src/e2e_vm_tests/test_programs/should_pass") +} + +pub fn e2e_should_fail_dir() -> PathBuf { + PathBuf::from("test/src/e2e_vm_tests/test_programs/should_fail") +} + +pub fn e2e_stdlib_dir() -> PathBuf { + PathBuf::from("test/src/e2e_vm_tests/test_programs/should_pass/stdlib") +} + pub fn e2e_unit_dir() -> PathBuf { PathBuf::from("test/src/e2e_vm_tests/test_programs/should_pass/unit_tests") } diff --git a/sway-types/src/lib.rs b/sway-types/src/lib.rs index 5d8e1cf95c1..b45471dcba2 100644 --- a/sway-types/src/lib.rs +++ b/sway-types/src/lib.rs @@ -88,47 +88,34 @@ impl Instruction { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] -pub struct ProgramId { - id: u16, -} +pub struct ProgramId(u16); impl ProgramId { pub fn new(id: u16) -> Self { - Self { id } + Self(id) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] -pub struct SourceId { - id: u32, -} +pub struct SourceId(u32); impl SourceId { - const RESERVED: u16 = 0; const SOURCE_ID_BITS: u32 = 20; const SOURCE_ID_MASK: u32 = (1 << Self::SOURCE_ID_BITS) - 1; - /// Create a combined ID from module and source IDs. + /// Create a combined ID from program and source IDs. pub fn new(program_id: u16, source_id: u32) -> Self { - SourceId { - id: ((program_id as u32) << Self::SOURCE_ID_BITS) | source_id, - } - } - - /// Create a reserved source_id. This is assigned to internal types - /// that should not be cleared during garbage collection. - pub fn reserved() -> Self { - Self::new(Self::RESERVED, Self::RESERVED as u32) + SourceId(((program_id as u32) << Self::SOURCE_ID_BITS) | source_id) } - /// The program_id that this source_id was created from. + /// The [ProgramId] that this [SourceId] was created from. pub fn program_id(&self) -> ProgramId { - ProgramId::new((self.id >> Self::SOURCE_ID_BITS) as u16) + ProgramId::new((self.0 >> Self::SOURCE_ID_BITS) as u16) } - /// Id of the source file without the program_id component. + /// ID of the source file without the [ProgramId] component. pub fn source_id(&self) -> u32 { - self.id & Self::SOURCE_ID_MASK + self.0 & Self::SOURCE_ID_MASK } } diff --git a/sway-types/src/source_engine.rs b/sway-types/src/source_engine.rs index 95ea5d94775..7a3124a3de2 100644 --- a/sway-types/src/source_engine.rs +++ b/sway-types/src/source_engine.rs @@ -81,7 +81,7 @@ impl SourceEngine { } } - let source_id = SourceId::new(program_id.id, *self.next_source_id.read()); + let source_id = SourceId::new(program_id.0, *self.next_source_id.read()); { let mut next_id = self.next_source_id.write(); *next_id += 1; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/abi_cast_nested_method/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/abi_cast_nested_method/src/main.sw index 6f08f7204de..2058833a235 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/abi_cast_nested_method/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/abi_cast_nested_method/src/main.sw @@ -3,6 +3,7 @@ script; abi AMM { fn pool() -> Option; } + abi Exchange { fn swap_exact_output(); } @@ -12,9 +13,6 @@ fn main() { let exchange_contract_id = amm_contract.pool(); - // let a = exchange_contract_id.unwrap().into(); - // let exchange_contract = abi(Exchange, a); - let exchange_contract = abi(Exchange, exchange_contract_id.unwrap().into()); exchange_contract.swap_exact_output(); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_or/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_or/test.toml index 2a24c489834..1d19796346b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_or/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_or/test.toml @@ -2,4 +2,4 @@ category = "run" expected_result = { action = "return", value = 42 } expected_result_new_encoding = { action = "return_data", value = "000000000000002A" } validate_abi = true -expected_warnings = 7 #TODO: Set number of warnings to minimum once TODOs in tests are solved. +expected_warnings = 7 #TODO: Set number of warnings to minimum once TODOs in tests are solved. From 9c4a339dfff53af6c130c2f7a069c0b904550101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaya=20G=C3=B6kalp?= Date: Wed, 6 Nov 2024 01:42:25 -0800 Subject: [PATCH 02/52] chore: remove unmaintained `ansi_term` in favor of `ansiterm` (#6696) ## Description related to #2601. Removes ansi_term dependency from sway crates. To remove the dependency completely from dep tree we need a release of sway repo to get a new version of forc_util and use it in forc_wallet as forc_wallet is depending on `forc-util v0.47.0` which uses `ansi_term`. Once that is done we can close #2601 --- Cargo.lock | 72 +++++++++------------------------- Cargo.toml | 2 +- forc-pkg/Cargo.toml | 2 +- forc-pkg/src/lock.rs | 4 +- forc-pkg/src/pkg.rs | 6 +-- forc-pkg/src/source/git/mod.rs | 6 +-- forc-pkg/src/source/ipfs.rs | 6 +-- forc-tracing/Cargo.toml | 4 +- forc-tracing/src/lib.rs | 2 +- forc-util/Cargo.toml | 2 +- forc-util/src/cli.rs | 2 +- forc-util/src/lib.rs | 4 +- forc/Cargo.toml | 2 +- forc/src/cli/commands/test.rs | 2 +- swayfmt/Cargo.toml | 2 +- swayfmt/test_macros/Cargo.toml | 2 +- 16 files changed, 38 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07c201f8f60..b28a9aacc7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,6 +190,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "ansiterm" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ab587f5395da16dd2e6939adf53dede583221b320cadfb94e02b5b7b9bf24cc" +dependencies = [ + "winapi", +] + [[package]] name = "anstream" version = "0.6.15" @@ -2672,7 +2681,7 @@ name = "forc" version = "0.66.4" dependencies = [ "annotate-snippets", - "ansi_term", + "ansiterm", "anyhow", "clap 4.5.20", "clap_complete", @@ -2845,7 +2854,7 @@ dependencies = [ "forc-pkg", "forc-tracing 0.66.4", "forc-util", - "prettydiff 0.7.0", + "prettydiff", "sway-core", "sway-utils", "swayfmt", @@ -2868,7 +2877,7 @@ dependencies = [ name = "forc-pkg" version = "0.66.4" dependencies = [ - "ansi_term", + "ansiterm", "anyhow", "byte-unit", "cid", @@ -2934,7 +2943,7 @@ dependencies = [ name = "forc-tracing" version = "0.66.4" dependencies = [ - "ansi_term", + "ansiterm", "tracing", "tracing-subscriber", "tracing-test", @@ -2960,7 +2969,7 @@ name = "forc-util" version = "0.66.4" dependencies = [ "annotate-snippets", - "ansi_term", + "ansiterm", "anyhow", "clap 4.5.20", "dirs 5.0.1", @@ -3906,15 +3915,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "heck" version = "0.4.1" @@ -5881,18 +5881,6 @@ dependencies = [ "yansi 1.0.1", ] -[[package]] -name = "prettydiff" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff1fec61082821f8236cf6c0c14e8172b62ce8a72a0eedc30d3b247bb68dc11" -dependencies = [ - "ansi_term", - "pad", - "prettytable-rs", - "structopt", -] - [[package]] name = "prettydiff" version = "0.7.0" @@ -7470,30 +7458,6 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "structopt" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" -dependencies = [ - "clap 2.34.0", - "lazy_static", - "structopt-derive", -] - -[[package]] -name = "structopt-derive" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" -dependencies = [ - "heck 0.3.3", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "strum" version = "0.24.1" @@ -7667,7 +7631,7 @@ dependencies = [ "itertools 0.13.0", "once_cell", "peg", - "prettydiff 0.7.0", + "prettydiff", "rustc-hash 1.1.0", "slotmap", "sway-features", @@ -7805,7 +7769,7 @@ dependencies = [ "forc-tracing 0.66.4", "indoc", "paste", - "prettydiff 0.6.4", + "prettydiff", "ropey", "serde", "serde_ignored", @@ -8121,7 +8085,7 @@ dependencies = [ "insta", "libtest-mimic", "normalize-path", - "prettydiff 0.7.0", + "prettydiff", "rand", "regex", "revm", @@ -8144,7 +8108,7 @@ name = "test-macros" version = "0.0.0" dependencies = [ "paste", - "prettydiff 0.6.4", + "prettydiff", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index cc4f22bd5c7..dea5fb29407 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,7 +108,7 @@ forc-wallet = "0.11" # annotate-snippets = "0.10" -ansi_term = "0.12" +ansiterm = "0.12" anyhow = "1.0" assert-json-diff = "2.0" async-trait = "0.1" diff --git a/forc-pkg/Cargo.toml b/forc-pkg/Cargo.toml index 7b1bc68587b..20dcf7436cc 100644 --- a/forc-pkg/Cargo.toml +++ b/forc-pkg/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true repository.workspace = true [dependencies] -ansi_term.workspace = true +ansiterm.workspace = true anyhow.workspace = true byte-unit.workspace = true cid.workspace = true diff --git a/forc-pkg/src/lock.rs b/forc-pkg/src/lock.rs index 594c107bc09..f5db529cc7b 100644 --- a/forc-pkg/src/lock.rs +++ b/forc-pkg/src/lock.rs @@ -354,7 +354,7 @@ where }; println_action_red( "Removing", - &format!("{}{src}", ansi_term::Style::new().bold().paint(&pkg.name)), + &format!("{}{src}", ansiterm::Style::new().bold().paint(&pkg.name)), ); } } @@ -372,7 +372,7 @@ where }; println_action_green( "Adding", - &format!("{}{src}", ansi_term::Style::new().bold().paint(&pkg.name)), + &format!("{}{src}", ansiterm::Style::new().bold().paint(&pkg.name)), ); } } diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index 19291e0d0ce..4a798f01f48 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -2244,13 +2244,13 @@ pub fn build_with_options(build_options: &BuildOpts) -> Result { fn print_pkg_summary_header(built_pkg: &BuiltPackage) { let prog_ty_str = forc_util::program_type_str(&built_pkg.tree_type); - // The ansi_term formatters ignore the `std::fmt` right-align + // The ansiterm formatters ignore the `std::fmt` right-align // formatter, so we manually calculate the padding to align the program // type and name around the 10th column ourselves. let padded_ty_str = format!("{prog_ty_str:>10}"); let padding = &padded_ty_str[..padded_ty_str.len() - prog_ty_str.len()]; - let ty_ansi = ansi_term::Colour::Green.bold().paint(prog_ty_str); - let name_ansi = ansi_term::Style::new() + let ty_ansi = ansiterm::Colour::Green.bold().paint(prog_ty_str); + let name_ansi = ansiterm::Style::new() .bold() .paint(&built_pkg.descriptor.name); debug!("{padding}{ty_ansi} {name_ansi}"); diff --git a/forc-pkg/src/source/git/mod.rs b/forc-pkg/src/source/git/mod.rs index a89e77f3128..d1a74c13f34 100644 --- a/forc-pkg/src/source/git/mod.rs +++ b/forc-pkg/src/source/git/mod.rs @@ -206,11 +206,7 @@ impl source::Fetch for Pinned { if !repo_path.exists() { println_action_green( "Fetching", - &format!( - "{} {}", - ansi_term::Style::new().bold().paint(ctx.name), - self - ), + &format!("{} {}", ansiterm::Style::new().bold().paint(ctx.name), self), ); fetch(ctx.fetch_id(), ctx.name(), self)?; } diff --git a/forc-pkg/src/source/ipfs.rs b/forc-pkg/src/source/ipfs.rs index 1391348834c..4d465ff23f6 100644 --- a/forc-pkg/src/source/ipfs.rs +++ b/forc-pkg/src/source/ipfs.rs @@ -69,11 +69,7 @@ impl source::Fetch for Pinned { if !repo_path.exists() { println_action_green( "Fetching", - &format!( - "{} {}", - ansi_term::Style::new().bold().paint(ctx.name), - self - ), + &format!("{} {}", ansiterm::Style::new().bold().paint(ctx.name), self), ); let cid = &self.0; let ipfs_client = ipfs_client(); diff --git a/forc-tracing/Cargo.toml b/forc-tracing/Cargo.toml index 85240eec345..871e04df5a0 100644 --- a/forc-tracing/Cargo.toml +++ b/forc-tracing/Cargo.toml @@ -9,9 +9,9 @@ license.workspace = true repository.workspace = true [dependencies] -ansi_term.workspace = true +ansiterm.workspace = true tracing.workspace = true tracing-subscriber = { workspace = true, features = ["ansi", "env-filter", "json"] } [dev-dependencies] -tracing-test = "0.2" \ No newline at end of file +tracing-test = "0.2" diff --git a/forc-tracing/src/lib.rs b/forc-tracing/src/lib.rs index 656cb14ca14..c331b0a8a71 100644 --- a/forc-tracing/src/lib.rs +++ b/forc-tracing/src/lib.rs @@ -1,6 +1,6 @@ //! Utility items shared between forc crates. -use ansi_term::Colour; +use ansiterm::Colour; use std::str; use std::{env, io}; use tracing::{Level, Metadata}; diff --git a/forc-util/Cargo.toml b/forc-util/Cargo.toml index f224c3028cb..b2b5cdded43 100644 --- a/forc-util/Cargo.toml +++ b/forc-util/Cargo.toml @@ -10,7 +10,7 @@ repository.workspace = true [dependencies] annotate-snippets.workspace = true -ansi_term.workspace = true +ansiterm.workspace = true anyhow.workspace = true clap = { workspace = true, features = ["cargo", "derive", "env"] } dirs.workspace = true diff --git a/forc-util/src/cli.rs b/forc-util/src/cli.rs index f8f6ed5662e..d5dc863ddcd 100644 --- a/forc-util/src/cli.rs +++ b/forc-util/src/cli.rs @@ -103,7 +103,7 @@ macro_rules! cli_examples { fn help() -> &'static str { - Box::leak(format!("{}\n{}", forc_util::ansi_term::Colour::Yellow.paint("EXAMPLES:"), examples()).into_boxed_str()) + Box::leak(format!("{}\n{}", forc_util::ansiterm::Colour::Yellow.paint("EXAMPLES:"), examples()).into_boxed_str()) } pub fn examples() -> &'static str { diff --git a/forc-util/src/lib.rs b/forc-util/src/lib.rs index 7cf7f45b2b4..970b30aed5a 100644 --- a/forc-util/src/lib.rs +++ b/forc-util/src/lib.rs @@ -29,7 +29,7 @@ pub mod restricted; #[macro_use] pub mod cli; -pub use ansi_term; +pub use ansiterm; pub use paste; pub use regex::Regex; pub use serial_test; @@ -347,7 +347,7 @@ pub fn print_compiling(ty: Option<&TreeType>, name: &str, src: &dyn std::fmt::Di }; println_action_green( "Compiling", - &format!("{ty}{} ({src})", ansi_term::Style::new().bold().paint(name)), + &format!("{ty}{} ({src})", ansiterm::Style::new().bold().paint(name)), ); } diff --git a/forc/Cargo.toml b/forc/Cargo.toml index 578e427cee8..7c83e28884f 100644 --- a/forc/Cargo.toml +++ b/forc/Cargo.toml @@ -18,7 +18,7 @@ path = "src/main.rs" [dependencies] annotate-snippets.workspace = true -ansi_term.workspace = true +ansiterm.workspace = true anyhow.workspace = true clap = { workspace = true, features = ["cargo", "derive", "env"] } clap_complete.workspace = true diff --git a/forc/src/cli/commands/test.rs b/forc/src/cli/commands/test.rs index d556af6b790..c67e9140b81 100644 --- a/forc/src/cli/commands/test.rs +++ b/forc/src/cli/commands/test.rs @@ -1,5 +1,5 @@ use crate::cli; -use ansi_term::Colour; +use ansiterm::Colour; use clap::Parser; use forc_pkg as pkg; use forc_test::{decode_log_data, TestFilter, TestRunnerCount, TestedPackage}; diff --git a/swayfmt/Cargo.toml b/swayfmt/Cargo.toml index 475cbe5d1b2..85749c30ab2 100644 --- a/swayfmt/Cargo.toml +++ b/swayfmt/Cargo.toml @@ -26,6 +26,6 @@ toml = { workspace = true, features = ["parse"] } [dev-dependencies] paste = "1.0" -prettydiff = "0.6" +prettydiff = "0.7" similar = "2.0" test-macros = { path = "test_macros" } diff --git a/swayfmt/test_macros/Cargo.toml b/swayfmt/test_macros/Cargo.toml index 89e0debe297..f08138e89dc 100644 --- a/swayfmt/test_macros/Cargo.toml +++ b/swayfmt/test_macros/Cargo.toml @@ -15,7 +15,7 @@ repository.workspace = true [dev-dependencies] paste = "1.0" -prettydiff = "0.6" +prettydiff = "0.7" [package.metadata.cargo-udeps.ignore] development = ["paste", "prettydiff"] From 5330d3c16dc0a3dadf19586e160beaf8c4a6267d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Matos?= Date: Wed, 6 Nov 2024 10:24:21 +0000 Subject: [PATCH 03/52] Remove `forc` help test. (#6682) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This test has shown itself to apparently not be deterministic, so remove it as it is causing issues when merging https://github.com/FuelLabs/sway/pull/6565. @xunilrj I think you added this test originally, so cc'ing you to make sure there is no issue with this. ## 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). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. Co-authored-by: Kaya Gökalp --- .../should_pass/forc/help/snapshot.toml | 16 - .../should_pass/forc/help/stdout.snap | 597 ------------------ 2 files changed, 613 deletions(-) delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/forc/help/snapshot.toml delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/forc/help/stdout.snap diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/forc/help/snapshot.toml b/test/src/e2e_vm_tests/test_programs/should_pass/forc/help/snapshot.toml deleted file mode 100644 index b9151f7a736..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/forc/help/snapshot.toml +++ /dev/null @@ -1,16 +0,0 @@ -cmds = [ - "forc addr2line -h", - "forc build -h", - "forc check -h", - "forc clean -h", - "forc completions -h", - "forc new -h", - "forc init -h", - "forc parse-bytecode -h", - "forc test -h", - "forc update -h", - "forc plugins -h", - "forc template -h", - "forc contract-id -h", - "forc predicate-root -h", -] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/forc/help/stdout.snap b/test/src/e2e_vm_tests/test_programs/should_pass/forc/help/stdout.snap deleted file mode 100644 index 8dd4a804aae..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/forc/help/stdout.snap +++ /dev/null @@ -1,597 +0,0 @@ ---- -source: test/tests/tests.rs ---- -> forc addr2line -h -exit status: 0 -output: -Show location and context of an opcode address in its source file - -Usage: forc addr2line [OPTIONS] --sourcemap-path --opcode-index - -Options: - -S, --search-dir Where to search for the project root [default: .] - -g, --sourcemap-path Source file mapping in JSON format - -c, --context How many lines of context to show [default: 2] - -i, --opcode-index Opcode index - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help - -> forc build -h -exit status: 0 -output: -Compile the current or target project - -Usage: forc build [OPTIONS] - -Options: - -p, --path - Path to the project - --offline - Offline mode - -t, --terse - Terse mode - --output-directory - The directory in which Forc output artifacts are placed - --locked - Requires that the Forc.lock file is up-to-date - --ipfs-node - The IPFS node to use for fetching IPFS sources - --ast - Print the generated Sway AST (Abstract Syntax Tree) - --dca-graph - Print the computed Sway DCA (Dead Code Analysis) graph - --dca-graph-url-format - URL format to be used in the generated DCA graph .dot file. - --asm ... - Print the generated ASM (assembler). [possible values: virtual, allocated, abstract, final, all] - --bytecode - Print the bytecode - --ir ... - Print the generated Sway IR (Intermediate Representation). [possible values: initial, final, all, modified, inline, simplify-cfg, sroa, dce, fn-dce, fn-dedup-release, fn-dedup-debug, mem2reg, memcpyopt, const-folding, arg-demotion, const-demotion, ret-demotion, misc-demotion] - --time-phases - Output the time elapsed over each part of the compilation process - --reverse-order - Output build errors and warnings in reverse order - --metrics-outfile - Output compilation metrics into the specified file - -v, --verbose... - Use verbose output - --json-abi - Minify JSON ABI files - -s, --silent - Silence all output - --json-storage-slots - Minify JSON storage slot files - -L, --log-level - Set the log level - -o, --output-bin - Create a binary file at the provided path representing the final bytecode - -g, --output-debug - Create a file at the provided path containing debug information - --build-profile - The name of the build profile to use [default: debug] - --release - Use the release build profile - --error-on-warnings - Treat warnings as errors - --build-target - Build target to use for code generation [default: fuel] [possible values: fuel, evm] - --tests - Also build all tests within the project - --experimental - Comma separated list of all experimental features that will be enabled [possible values: new_encoding] - --no-experimental - Comma separated list of all experimental features that will be disabled [possible values: new_encoding] - -h, --help - Print help (see more with '--help') - -V, --version - Print version - -EXAMPLES: - # Compile the current projectx - forc build - - # Compile the current project from a different path - forc build --path - - # Compile the current project without updating dependencies - forc build --path --locked - -> forc check -h -exit status: 0 -output: -Check the current or target project and all of its dependencies for errors - -Usage: forc check [OPTIONS] [BUILD_TARGET] - -Arguments: - [BUILD_TARGET] Build target to use for code generation [default: fuel] [possible values: fuel, evm] - -Options: - -p, --path - Path to the project, if not specified, current working directory will be used - --offline - Offline mode, prevents Forc from using the network when managing dependencies. Meaning it will only try to use previously downloaded dependencies - --locked - Requires that the Forc.lock file is up-to-date. If the lock file is missing, or it needs to be updated, Forc will exit with an error - -t, --terse - Terse mode. Limited warning and error output - --disable-tests - Disable checking unit tests - --ipfs-node - The IPFS Node to use for fetching IPFS sources - --experimental - Comma separated list of all experimental features that will be enabled [possible values: new_encoding] - --no-experimental - Comma separated list of all experimental features that will be disabled [possible values: new_encoding] - -v, --verbose... - Use verbose output - -s, --silent - Silence all output - -L, --log-level - Set the log level - -h, --help - Print help (see more with '--help') - -V, --version - Print version - -EXAMPLES: - # Check the current project - forc check - - # Check the current project with a different path - forc check --path - - # Check the current project without updating dependencies - forc check --locked - -> forc clean -h -exit status: 0 -output: -Removes the default forc compiler output artifact directory, i.e. `/out` - -Usage: forc clean [OPTIONS] - -Options: - -p, --path Path to the project, if not specified, current working directory will be used - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help - -V, --version Print version - -EXAMPLES: - # Clean project - forc clean - - # Clean project with a custom path - forc clean --path - -> forc completions -h -exit status: 0 -output: -Generate tab-completion scripts for your shell - -Usage: forc completions [OPTIONS] --target - -Options: - -T, --target Specify shell to enable tab-completion for [possible values: bash, elvish, fish, power-shell, zsh, fig] - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help (see more with '--help') - -> forc new -h -exit status: 0 -output: -Create a new Forc project at `` - -Usage: forc new [OPTIONS] - -Arguments: - The path at which the project directory will be created - -Options: - --contract The default program type. Excluding all flags or adding this flag creates a basic contract program - --script Adding this flag creates an empty script program - --predicate Adding this flag creates an empty predicate program - --library Adding this flag creates an empty library program - --workspace Adding this flag creates an empty workspace - --name Set the package name. Defaults to the directory name - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help - -V, --version Print version - -EXAMPLES: - # Create a new project - forc new --contract --name my_project - - # Create a new workspace - forc new --workspace --name my_workspace - - # Create a new Forc project with a predicate - forc new --predicate - - # Create a new Forc library project - forc new --library - -> forc init -h -exit status: 0 -output: -Create a new Forc project in an existing directory - -Usage: forc init [OPTIONS] - -Options: - --path The directory in which the forc project will be initialized - --contract The default program type, excluding all flags or adding this flag creates a basic contract program - --script Create a package with a script target (src/main.sw) - --predicate Create a package with a predicate target (src/predicate.rs) - --library Create a package with a library target (src/lib.sw) - --workspace Adding this flag creates an empty workspace - --name Set the package name. Defaults to the directory name - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help - -V, --version Print version - -EXAMPLES: - # Initialize a new Forc project - forc init --path - - # Initialize a new Forc project as workspace - forc init --path --workspace - - # Initialize a new Forc project with a predicate - forc init --path --predicate - - # Initialize a new Forc library project - forc init --path --library - -> forc parse-bytecode -h -exit status: 0 -output: -Parse bytecode file into a debug format - -Usage: forc parse-bytecode [OPTIONS] - -Arguments: - - -Options: - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help - -V, --version Print version - -EXAMPLES: - # Parse bytecode - forc parse-bytecode - -> forc test -h -exit status: 0 -output: -Run the Sway unit tests for the current project - -Usage: forc test [OPTIONS] [FILTER] - -Arguments: - [FILTER] When specified, only tests containing the given string will be executed - -Options: - -p, --path - Path to the project - --offline - Offline mode - -t, --terse - Terse mode - --output-directory - The directory in which Forc output artifacts are placed - --locked - Requires that the Forc.lock file is up-to-date - --ipfs-node - The IPFS node to use for fetching IPFS sources - --ast - Print the generated Sway AST (Abstract Syntax Tree) - --dca-graph - Print the computed Sway DCA (Dead Code Analysis) graph - --dca-graph-url-format - URL format to be used in the generated DCA graph .dot file. - --asm ... - Print the generated ASM (assembler). [possible values: virtual, allocated, abstract, final, all] - --bytecode - Print the bytecode - --ir ... - Print the generated Sway IR (Intermediate Representation). [possible values: initial, final, all, modified, inline, simplify-cfg, sroa, dce, fn-dce, fn-dedup-release, fn-dedup-debug, mem2reg, memcpyopt, const-folding, arg-demotion, const-demotion, ret-demotion, misc-demotion] - --time-phases - Output the time elapsed over each part of the compilation process - --reverse-order - Output build errors and warnings in reverse order - --metrics-outfile - Output compilation metrics into the specified file - -v, --verbose... - Use verbose output - --json-abi - Minify JSON ABI files - -s, --silent - Silence all output - --json-storage-slots - Minify JSON storage slot files - -L, --log-level - Set the log level - -o, --output-bin - Create a binary file at the provided path representing the final bytecode - -g, --output-debug - Create a file at the provided path containing debug information - --build-profile - The name of the build profile to use [default: debug] - --release - Use the release build profile - --error-on-warnings - Treat warnings as errors - --build-target - Build target to use for code generation [default: fuel] [possible values: fuel, evm] - --pretty - Pretty-print the logs emitted from tests - -l, --logs - Print `Log` and `LogData` receipts for tests - --raw-logs - Print the raw logs for tests - --filter-exact - When specified, only the test exactly matching the given string will be executed - --test-threads - Number of threads to utilize when running the tests. By default, this is the number of threads available in your system - --experimental - Comma separated list of all experimental features that will be enabled [possible values: new_encoding] - --no-experimental - Comma separated list of all experimental features that will be disabled [possible values: new_encoding] - -h, --help - Print help (see more with '--help') - -V, --version - Print version - -EXAMPLES: - # Run test - forc test - - # Run test with a filter - forc test $filter - - # Run test without any output - forc test --silent - - # Run test without creating or update the lock file - forc test --locked - -> forc update -h -exit status: 0 -output: -Update dependencies in the Forc dependencies directory - -Usage: forc update [OPTIONS] - -Options: - -p, --path Path to the project, if not specified, current working directory will be used - -d Dependency to be updated. If not set, all dependencies will be updated - -c, --check Checks if the dependencies have newer versions. Won't actually perform the update, will output which ones are up-to-date and outdated - --ipfs-node The IPFS Node to use for fetching IPFS sources - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help (see more with '--help') - -V, --version Print version - -EXAMPLES: - # Update dependencies - forc update - - # Update a specific dependency - forc update -d std - - # Check if dependencies have newer versions - forc update --check - -> forc plugins -h -exit status: 0 -output: -List all forc plugins - -Usage: forc plugins [OPTIONS] - -Options: - -p, --paths Prints the absolute path to each discovered plugin - -d, --describe Prints the long description associated with each listed plugin - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help (see more with '--help') - -V, --version Print version - -EXAMPLES: - # List all plugins - forc plugins - - # List all plugins with their paths - forc plugins --paths - - # List all plugins with their descriptions - forc plugins --describe - - # List all plugins with their paths and descriptions - forc plugins --paths --describe - -> forc template -h -exit status: 0 -output: -Create a new Forc project from a git template - -Usage: forc template [OPTIONS] - -Arguments: - The name of the project that will be created - -Options: - -u, --url The template url, should be a git repo [default: https://github.com/fuellabs/sway] - -t, --template-name The name of the template that needs to be fetched and used from git repo provided - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help - -V, --version Print version - -EXAMPLES: - # Create a new Forc project from an option template - forc template new-path --template-name option - -> forc contract-id -h -exit status: 0 -output: -Determine contract-id for a contract. For workspaces outputs all contract ids in the workspace - -Usage: forc contract-id [OPTIONS] - -Options: - -p, --path - Path to the project - --offline - Offline mode - -t, --terse - Terse mode - --output-directory - The directory in which Forc output artifacts are placed - --locked - Requires that the Forc.lock file is up-to-date - --ipfs-node - The IPFS node to use for fetching IPFS sources - --json-abi - Minify JSON ABI files - --json-storage-slots - Minify JSON storage slot files - --ast - Print the generated Sway AST (Abstract Syntax Tree) - --dca-graph - Print the computed Sway DCA (Dead Code Analysis) graph - --dca-graph-url-format - URL format to be used in the generated DCA graph .dot file. - --asm ... - Print the generated ASM (assembler). [possible values: virtual, allocated, abstract, final, all] - --bytecode - Print the bytecode - --ir ... - Print the generated Sway IR (Intermediate Representation). [possible values: initial, final, all, modified, inline, simplify-cfg, sroa, dce, fn-dce, fn-dedup-release, fn-dedup-debug, mem2reg, memcpyopt, const-folding, arg-demotion, const-demotion, ret-demotion, misc-demotion] - --time-phases - Output the time elapsed over each part of the compilation process - -v, --verbose... - Use verbose output - --reverse-order - Output build errors and warnings in reverse order - -s, --silent - Silence all output - -L, --log-level - Set the log level - --metrics-outfile - Output compilation metrics into the specified file - -o, --output-bin - Create a binary file at the provided path representing the final bytecode - -g, --output-debug - Create a file at the provided path containing debug information - --build-profile - The name of the build profile to use [default: debug] - --release - Use the release build profile - --error-on-warnings - Treat warnings as errors - --salt - Added salt used to derive the contract ID - --experimental - Comma separated list of all experimental features that will be enabled [possible values: new_encoding] - --no-experimental - Comma separated list of all experimental features that will be disabled [possible values: new_encoding] - -h, --help - Print help (see more with '--help') - -V, --version - Print version - -EXAMPLES: - # Get contract id - forc contract-id - - # Get contract id from a different path - forc contract-id --path - -> forc predicate-root -h -exit status: 0 -output: -Determine predicate-root for a predicate. For workspaces outputs all predicate roots in the workspace - -Usage: forc predicate-root [OPTIONS] - -Options: - -p, --path - Path to the project - --offline - Offline mode - -t, --terse - Terse mode - --output-directory - The directory in which Forc output artifacts are placed - --locked - Requires that the Forc.lock file is up-to-date - --ipfs-node - The IPFS node to use for fetching IPFS sources - --json-abi - Minify JSON ABI files - --json-storage-slots - Minify JSON storage slot files - --ast - Print the generated Sway AST (Abstract Syntax Tree) - --dca-graph - Print the computed Sway DCA (Dead Code Analysis) graph - --dca-graph-url-format - URL format to be used in the generated DCA graph .dot file. - --asm ... - Print the generated ASM (assembler). [possible values: virtual, allocated, abstract, final, all] - --bytecode - Print the bytecode - --ir ... - Print the generated Sway IR (Intermediate Representation). [possible values: initial, final, all, modified, inline, simplify-cfg, sroa, dce, fn-dce, fn-dedup-release, fn-dedup-debug, mem2reg, memcpyopt, const-folding, arg-demotion, const-demotion, ret-demotion, misc-demotion] - --time-phases - Output the time elapsed over each part of the compilation process - -v, --verbose... - Use verbose output - --reverse-order - Output build errors and warnings in reverse order - -s, --silent - Silence all output - -L, --log-level - Set the log level - --metrics-outfile - Output compilation metrics into the specified file - -o, --output-bin - Create a binary file at the provided path representing the final bytecode - -g, --output-debug - Create a file at the provided path containing debug information - --build-profile - The name of the build profile to use [default: debug] - --release - Use the release build profile - --error-on-warnings - Treat warnings as errors - --experimental - Comma separated list of all experimental features that will be enabled [possible values: new_encoding] - --no-experimental - Comma separated list of all experimental features that will be disabled [possible values: new_encoding] - -h, --help - Print help (see more with '--help') - -V, --version - Print version - -EXAMPLES: - # Get predicate root - forc predicate-root From ccd86925f99658f2dd72fedfe05b68a71e4acba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaya=20G=C3=B6kalp?= Date: Wed, 6 Nov 2024 05:46:40 -0800 Subject: [PATCH 04/52] chore: remove `uwuify` feature (#6698) --- Cargo.lock | 187 +++++++---------------------------- Cargo.toml | 1 - forc-util/src/lib.rs | 6 +- forc/Cargo.toml | 2 - sway-error/Cargo.toml | 2 - sway-error/src/diagnostic.rs | 25 ----- 6 files changed, 37 insertions(+), 186 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b28a9aacc7b..45b88125184 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -450,17 +450,6 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "aurora-engine-modexp" version = "1.1.0" @@ -1216,21 +1205,6 @@ dependencies = [ "inout", ] -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags 1.3.2", - "strsim 0.8.0", - "textwrap 0.11.0", - "unicode-width", - "vec_map", -] - [[package]] name = "clap" version = "4.5.20" @@ -1260,7 +1234,7 @@ version = "4.5.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9646e2e245bf62f45d39a0f3f36f1171ad1ea0d6967fd114bca72cb02a8fcdfb" dependencies = [ - "clap 4.5.20", + "clap", ] [[package]] @@ -1269,7 +1243,7 @@ version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d494102c8ff3951810c72baf96910b980fb065ca5d3101243e6a8dc19747c86b" dependencies = [ - "clap 4.5.20", + "clap", "clap_complete", ] @@ -1455,7 +1429,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c93ab3577cca16b4a1d80a88c2e0cd8b6e969e51696f0bbb0d1dcb0157109832" dependencies = [ "caseless", - "clap 4.5.20", + "clap", "derive_builder", "entities", "memchr", @@ -1602,7 +1576,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.20", + "clap", "criterion-plot", "is-terminal", "itertools 0.10.5", @@ -1894,7 +1868,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.10", + "parking_lot_core", ] [[package]] @@ -1908,7 +1882,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.10", + "parking_lot_core", ] [[package]] @@ -2683,7 +2657,7 @@ dependencies = [ "annotate-snippets", "ansiterm", "anyhow", - "clap 4.5.20", + "clap", "clap_complete", "clap_complete_fig", "completest-pty", @@ -2709,7 +2683,6 @@ dependencies = [ "toml_edit", "tracing", "url", - "uwuify", "walkdir", "whoami", ] @@ -2723,7 +2696,7 @@ dependencies = [ "aws-config", "aws-sdk-kms", "chrono", - "clap 4.5.20", + "clap", "devault", "dialoguer", "forc", @@ -2768,7 +2741,7 @@ version = "0.66.4" dependencies = [ "anyhow", "async-trait", - "clap 4.5.20", + "clap", "criterion", "forc-tracing 0.66.4", "forc-util", @@ -2797,7 +2770,7 @@ name = "forc-debug" version = "0.66.4" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "dap", "escargot", "forc-pkg", @@ -2824,7 +2797,7 @@ name = "forc-doc" version = "0.66.4" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "comrak", "dir_indexer", "expect-test", @@ -2850,7 +2823,7 @@ name = "forc-fmt" version = "0.66.4" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "forc-pkg", "forc-tracing 0.66.4", "forc-util", @@ -2867,7 +2840,7 @@ name = "forc-lsp" version = "0.66.4" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "sway-lsp", "tikv-jemallocator", "tokio", @@ -2954,7 +2927,7 @@ name = "forc-tx" version = "0.66.4" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "devault", "forc-util", "fuel-tx", @@ -2971,7 +2944,7 @@ dependencies = [ "annotate-snippets", "ansiterm", "anyhow", - "clap 4.5.20", + "clap", "dirs 5.0.1", "fd-lock", "forc-tracing 0.66.4", @@ -2998,7 +2971,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e6ad4498ecab72fa7c5e134ade0137279d1b8f4a6df50963bb3803fdeb69dac" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "eth-keystore", "forc-tracing 0.47.0", "fuel-crypto", @@ -3137,7 +3110,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94a1c3eb92040d95d27f7c658801bb5c04ad4aaf67de380cececbeed5aab6e61" dependencies = [ "once_cell", - "parking_lot 0.12.3", + "parking_lot", "pin-project-lite", "prometheus-client", "regex", @@ -3175,7 +3148,7 @@ dependencies = [ "async-trait", "fuel-core-metrics", "futures", - "parking_lot 0.12.3", + "parking_lot", "pin-project-lite", "tokio", "tracing", @@ -3927,15 +3900,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.9" @@ -4451,15 +4415,6 @@ dependencies = [ "similar", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "ipfs-api-backend-hyper" version = "0.6.0" @@ -4792,7 +4747,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc0bda45ed5b3a2904262c1bb91e526127aa70e7ef3758aba2ef93cf896b9b58" dependencies = [ - "clap 4.5.20", + "clap", "escape8259", "termcolor", "threadpool", @@ -4891,7 +4846,7 @@ checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5" dependencies = [ "anyhow", "chrono", - "clap 4.5.20", + "clap", "clap_complete", "env_logger", "handlebars", @@ -4914,7 +4869,7 @@ name = "mdbook-forc-documenter" version = "0.0.0" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "mdbook", "semver 1.0.23", "serde", @@ -4967,7 +4922,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aa3f302fe0f8de065d4a2d1ed64f60204623cac58b80cd3c2a83a25d5a7d437" dependencies = [ - "clap 4.5.20", + "clap", ] [[package]] @@ -5481,12 +5436,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" -[[package]] -name = "owo-colors" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2386b4ebe91c2f7f51082d4cefa145d030e33a1842a96b12e4885cc3c01f7a55" - [[package]] name = "owo-colors" version = "3.5.0" @@ -5540,17 +5489,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.3" @@ -5558,21 +5496,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -5887,7 +5811,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abec3fb083c10660b3854367697da94c674e9e82aa7511014dc958beeb7215e9" dependencies = [ - "owo-colors 3.5.0", + "owo-colors", "pad", "prettytable-rs", ] @@ -5988,7 +5912,7 @@ checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", - "parking_lot 0.12.3", + "parking_lot", "prometheus-client-derive-encode", ] @@ -6214,15 +6138,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -7177,7 +7092,7 @@ dependencies = [ "futures", "log", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "scc", "serial_test_derive", ] @@ -7440,12 +7355,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c" -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - [[package]] name = "strsim" version = "0.10.0" @@ -7556,7 +7465,7 @@ dependencies = [ name = "sway-core" version = "0.66.4" dependencies = [ - "clap 4.5.20", + "clap", "derivative", "dirs 5.0.1", "either", @@ -7574,7 +7483,7 @@ dependencies = [ "itertools 0.13.0", "lazy_static", "object", - "parking_lot 0.12.3", + "parking_lot", "paste", "pest", "pest_derive", @@ -7609,14 +7518,13 @@ dependencies = [ "strsim 0.11.1", "sway-types", "thiserror", - "uwuify", ] [[package]] name = "sway-features" version = "0.66.4" dependencies = [ - "clap 4.5.20", + "clap", "paste", ] @@ -7670,7 +7578,7 @@ dependencies = [ "lsp-types", "notify", "notify-debouncer-mini", - "parking_lot 0.12.3", + "parking_lot", "pretty_assertions", "proc-macro2", "quote", @@ -7746,7 +7654,7 @@ dependencies = [ "lazy_static", "num-bigint", "num-traits", - "parking_lot 0.12.3", + "parking_lot", "rustc-hash 1.1.0", "serde", "sway-utils", @@ -8068,7 +7976,7 @@ version = "0.0.0" dependencies = [ "anyhow", "bytes", - "clap 4.5.20", + "clap", "colored", "duct", "filecheck", @@ -8096,7 +8004,7 @@ dependencies = [ "sway-ir", "sway-types", "sway-utils", - "textwrap 0.16.1", + "textwrap", "tokio", "toml 0.8.19", "tracing", @@ -8117,15 +8025,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "textwrap" version = "0.16.1" @@ -8290,7 +8189,7 @@ dependencies = [ "bytes", "libc", "mio 1.0.2", - "parking_lot 0.12.3", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -8794,18 +8693,6 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" -[[package]] -name = "uwuify" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db6840b7adcfd2e866c79157cc890ecdbbc1f739607134039ae64eaa6c07e24" -dependencies = [ - "clap 2.34.0", - "owo-colors 1.3.0", - "parking_lot 0.11.2", - "thiserror", -] - [[package]] name = "valuable" version = "0.1.0" @@ -8824,12 +8711,6 @@ version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eab68b56840f69efb0fefbe3ab6661499217ffdc58e2eef7c3f6f69835386322" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index dea5fb29407..15363bd5c55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -228,7 +228,6 @@ unicode-bidi = "0.3" unicode-xid = "0.2" url = "2.2" urlencoding = "2.1" -uwuify = "^0.2" vec1 = "1.8" vte = "0.13" walkdir = "2.3" diff --git a/forc-util/src/lib.rs b/forc-util/src/lib.rs index 970b30aed5a..003d50898ad 100644 --- a/forc-util/src/lib.rs +++ b/forc-util/src/lib.rs @@ -510,7 +510,7 @@ fn format_diagnostic(diagnostic: &Diagnostic) { label: if issue.is_in_source() { None } else { - Some(issue.friendly_text()) + Some(issue.text()) }, id: None, annotation_type, @@ -532,7 +532,7 @@ fn format_diagnostic(diagnostic: &Diagnostic) { origin: Some(issue.source_path().unwrap().as_str()), fold: false, annotations: vec![SourceAnnotation { - label: issue.friendly_text(), + label: issue.text(), annotation_type, range: (start_pos, end_pos), }], @@ -594,7 +594,7 @@ fn construct_slice(labels: Vec<&Label>) -> Slice { for message in labels { annotations.push(SourceAnnotation { - label: message.friendly_text(), + label: message.text(), annotation_type: label_type_to_annotation_type(message.label_type()), range: get_annotation_range(message.span(), source_code, shift_in_bytes), }); diff --git a/forc/Cargo.toml b/forc/Cargo.toml index 7c83e28884f..b94be79b3cc 100644 --- a/forc/Cargo.toml +++ b/forc/Cargo.toml @@ -44,7 +44,6 @@ toml = { workspace = true, features = ["parse"] } toml_edit.workspace = true tracing.workspace = true url.workspace = true -uwuify = { workspace = true, optional = true } walkdir.workspace = true whoami.workspace = true @@ -52,7 +51,6 @@ whoami.workspace = true default = [] test = [] util = [] -uwu = ["uwuify"] [dev-dependencies] completest-pty = "0.5.0" diff --git a/sway-error/Cargo.toml b/sway-error/Cargo.toml index c8810d96b91..9a9744a5d7c 100644 --- a/sway-error/Cargo.toml +++ b/sway-error/Cargo.toml @@ -16,11 +16,9 @@ smallvec.workspace = true strsim.workspace = true sway-types.workspace = true thiserror.workspace = true -uwuify = { workspace = true, optional = true } [features] default = [] -uwu = ["uwuify"] [lints.clippy] iter_over_hash_type = "deny" diff --git a/sway-error/src/diagnostic.rs b/sway-error/src/diagnostic.rs index ddfe86bfb92..504734309e8 100644 --- a/sway-error/src/diagnostic.rs +++ b/sway-error/src/diagnostic.rs @@ -154,7 +154,6 @@ pub struct Label { label_type: LabelType, span: Span, text: String, - friendly_text: String, source_path: Option, } @@ -176,13 +175,11 @@ impl Label { } fn new(source_engine: &SourceEngine, label_type: LabelType, span: Span, text: String) -> Label { - let friendly_text = Self::maybe_uwuify(text.as_str()); let source_path = Self::get_source_path(source_engine, &span); Label { label_type, span, text, - friendly_text, source_path, } } @@ -204,10 +201,6 @@ impl Label { self.text.as_ref() } - pub fn friendly_text(&self) -> &str { - self.friendly_text.as_ref() - } - pub fn source_path(&self) -> Option<&SourcePath> { self.source_path.as_ref() } @@ -227,23 +220,6 @@ impl Label { _ => None, } } - - #[cfg(all(feature = "uwu", any(target_arch = "x86", target_arch = "x86_64")))] - fn maybe_uwuify(raw: &str) -> String { - use uwuifier::uwuify_str_sse; - uwuify_str_sse(raw) - } - - #[cfg(all(feature = "uwu", not(any(target_arch = "x86", target_arch = "x86_64"))))] - fn maybe_uwuify(raw: &str) -> String { - compile_error!("The `uwu` feature only works on x86 or x86_64 processors."); - Default::default() - } - - #[cfg(not(feature = "uwu"))] - fn maybe_uwuify(raw: &str) -> String { - raw.to_string() - } } impl Default for Label { @@ -252,7 +228,6 @@ impl Default for Label { label_type: LabelType::Info, span: Span::dummy(), text: "".to_string(), - friendly_text: "".to_string(), source_path: None, } } From efa4aab3ce99190fab2e8e76dee1e5b236013017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaya=20G=C3=B6kalp?= Date: Fri, 8 Nov 2024 18:37:57 -0800 Subject: [PATCH 05/52] fix: forc-deploy asks for password before checking if the wallet exists (#6704) --- forc-plugins/forc-client/src/op/deploy.rs | 9 +++++++-- forc-plugins/forc-client/src/util/tx.rs | 3 --- forc-plugins/forc-client/tests/deploy.rs | 7 +++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/forc-plugins/forc-client/src/op/deploy.rs b/forc-plugins/forc-client/src/op/deploy.rs index ace89c3ddae..8f86c333672 100644 --- a/forc-plugins/forc-client/src/op/deploy.rs +++ b/forc-plugins/forc-client/src/op/deploy.rs @@ -7,8 +7,8 @@ use crate::{ pkg::{built_pkgs, create_proxy_contract, update_proxy_address_in_manifest}, target::Target, tx::{ - prompt_forc_wallet_password, select_account, update_proxy_contract_target, - SignerSelectionMode, + check_and_create_wallet_at_default_path, prompt_forc_wallet_password, select_account, + update_proxy_contract_target, SignerSelectionMode, }, }, }; @@ -1002,6 +1002,11 @@ async fn setup_deployment_account( } else if let Some(arn) = &command.aws_kms_signer { SignerSelectionMode::AwsSigner(arn.clone()) } else { + // Check if we have a wallet in the default path + // If there is one we will ask for the password + // If not we will ask the user to either create a new one or import one + let wallet_path = default_wallet_path(); + check_and_create_wallet_at_default_path(&wallet_path)?; println_action_green("", &format!("Wallet: {}", default_wallet_path().display())); let password = prompt_forc_wallet_password()?; SignerSelectionMode::ForcWallet(password) diff --git a/forc-plugins/forc-client/src/util/tx.rs b/forc-plugins/forc-client/src/util/tx.rs index e9f8b220121..dd9002a8055 100644 --- a/forc-plugins/forc-client/src/util/tx.rs +++ b/forc-plugins/forc-client/src/util/tx.rs @@ -170,9 +170,6 @@ pub(crate) async fn select_account( match wallet_mode { SignerSelectionMode::ForcWallet(password) => { let wallet_path = default_wallet_path(); - check_and_create_wallet_at_default_path(&wallet_path)?; - // TODO: This is a very simple TUI, we should consider adding a nice TUI - // capabilities for selections and answer collection. let accounts = collect_user_accounts(&wallet_path, password)?; let account_balances = collect_account_balances(&accounts, provider).await?; let base_asset_id = provider.base_asset_id(); diff --git a/forc-plugins/forc-client/tests/deploy.rs b/forc-plugins/forc-client/tests/deploy.rs index afabb238e82..b06d6aa96ed 100644 --- a/forc-plugins/forc-client/tests/deploy.rs +++ b/forc-plugins/forc-client/tests/deploy.rs @@ -693,7 +693,7 @@ async fn test_non_owner_fails_to_set_target() { // It would also require overriding `default_wallet_path` function for tests, so as not to interfere with the user's wallet. #[test] -fn test_deploy_interactive_wrong_password() -> Result<(), rexpect::error::Error> { +fn test_deploy_interactive_missing_wallet() -> Result<(), rexpect::error::Error> { let (mut node, port) = run_node(); let node_url = format!("http://127.0.0.1:{}/v1/graphql", port); @@ -711,9 +711,8 @@ fn test_deploy_interactive_wrong_password() -> Result<(), rexpect::error::Error> process .exp_string("\u{1b}[1;32mConfirming\u{1b}[0m transactions [deploy standalone_contract]")?; process.exp_string(&format!("Network: {node_url}"))?; - process.exp_string("Wallet: ")?; - process.exp_string("Wallet password")?; - process.send_line("mock_password")?; + process.exp_regex("Could not find a wallet at")?; + process.send_line("n")?; process.process.exit()?; node.kill().unwrap(); From f933f557e432e00b8ed89a96539da4894a701dc8 Mon Sep 17 00:00:00 2001 From: zees-dev Date: Sun, 10 Nov 2024 09:32:37 +1300 Subject: [PATCH 06/52] Forc-deploy import wallet support if non-existent wallet (#6680) ## Description - Adds support for importing a wallet on `forc-deploy` - Resolves https://github.com/FuelLabs/forc-wallet/issues/139 --- Cargo.lock | 8 ++--- forc-plugins/forc-client/src/util/tx.rs | 44 +++++++++++++++++-------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45b88125184..f29c1ad4299 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2966,9 +2966,9 @@ dependencies = [ [[package]] name = "forc-wallet" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e6ad4498ecab72fa7c5e134ade0137279d1b8f4a6df50963bb3803fdeb69dac" +checksum = "6ed94e0de4d8265fe744704544932bf1285ffa16ee5feb18062194904d299f9f" dependencies = [ "anyhow", "clap", @@ -5270,7 +5270,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn 2.0.79", @@ -8503,7 +8503,7 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "static_assertions", ] diff --git a/forc-plugins/forc-client/src/util/tx.rs b/forc-plugins/forc-client/src/util/tx.rs index dd9002a8055..a1dad6a3fcd 100644 --- a/forc-plugins/forc-client/src/util/tx.rs +++ b/forc-plugins/forc-client/src/util/tx.rs @@ -10,6 +10,7 @@ use forc_wallet::{ balance::{ collect_accounts_with_verification, AccountBalances, AccountVerification, AccountsMap, }, + import::{import_wallet_cli, Import}, new::{new_wallet_cli, New}, utils::default_wallet_path, }; @@ -45,6 +46,15 @@ fn ask_user_yes_no_question(question: &str) -> Result { Ok(answer) } +fn ask_user_with_options(question: &str, options: &[&str], default: usize) -> Result { + let selection = Select::with_theme(&ColorfulTheme::default()) + .with_prompt(question) + .items(options) + .default(default) + .interact()?; + Ok(selection) +} + fn collect_user_accounts( wallet_path: &Path, password: &str, @@ -71,21 +81,27 @@ pub(crate) fn prompt_forc_wallet_password() -> Result { pub(crate) fn check_and_create_wallet_at_default_path(wallet_path: &Path) -> Result<()> { if !wallet_path.exists() { - let question = format!("Could not find a wallet at {wallet_path:?}, would you like to create a new one? [y/N]: "); - let accepted = ask_user_yes_no_question(&question)?; - let new_options = New { - force: false, - cache_accounts: None, - }; - if accepted { - new_wallet_cli(wallet_path, new_options)?; - println!("Wallet created successfully."); - // Derive first account for the fresh wallet we created. - new_at_index_cli(wallet_path, 0)?; - println!("Account derived successfully."); - } else { - anyhow::bail!("Refused to create a new wallet. If you don't want to use forc-wallet, you can sign this transaction manually with --manual-signing flag.") + let question = + format!("Could not find a wallet at {wallet_path:?}, please select an option: "); + let wallet_options = ask_user_with_options( + &question, + &["Create new wallet", "Import existing wallet"], + 0, + )?; + match wallet_options { + 0 => { + new_wallet_cli(wallet_path, New { force: false, cache_accounts: None })?; + println!("Wallet created successfully."); + } + 1 => { + import_wallet_cli(wallet_path, Import { force: false, cache_accounts: None })?; + println!("Wallet imported successfully."); + }, + _ => anyhow::bail!("Refused to create or import a new wallet. If you don't want to use forc-wallet, you can sign this transaction manually with --manual-signing flag."), } + // Derive first account for the fresh wallet we created. + new_at_index_cli(wallet_path, 0)?; + println!("Account derived successfully."); } Ok(()) } From cbf0c6229da7ba23f79b9b17274d68f70a2a85f7 Mon Sep 17 00:00:00 2001 From: Sophie Dankel <47993817+sdankel@users.noreply.github.com> Date: Mon, 11 Nov 2024 21:34:31 -0800 Subject: [PATCH 07/52] chore: upgrade fuels sdk to 66.10 (#6715) ## Description This latest version of the fuels sdk should unblock the CI pipeline. ## Checklist - [ ] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] 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). - [ ] I have requested a review from the relevant team or maintainers. --- Cargo.lock | 752 ++++++++++----- Cargo.toml | 6 +- test/src/sdk-harness/Cargo.lock | 1555 ++++++++++++++++++------------- test/src/sdk-harness/Cargo.toml | 2 +- 4 files changed, 1441 insertions(+), 874 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f29c1ad4299..d0e9ea139dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,9 +73,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "alloy-eip2930" @@ -102,9 +102,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f35429a652765189c1c5092870d8360ee7b7769b09b06d89ebaefd34676446" +checksum = "fd58d377699e6cfeab52c4a9d28bdc4ef37e2bd235ff2db525071fe37a2e9af5" dependencies = [ "alloy-rlp", "bytes", @@ -112,7 +112,7 @@ dependencies = [ "const-hex", "derive_more 1.0.0", "foldhash", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "hex-literal", "indexmap 2.6.0", "itoa", @@ -130,9 +130,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" +checksum = "da0822426598f95e45dd1ea32a738dac057529a709ee645fcc516ffa4cbde08f" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -141,13 +141,13 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" +checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -201,9 +201,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -216,43 +216,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "arc-swap" @@ -432,7 +432,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -468,7 +468,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -479,9 +479,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-config" -version = "1.5.8" +version = "1.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7198e6f03240fdceba36656d8be440297b6b82270325908c7381f37d826a74f6" +checksum = "9b49afaa341e8dd8577e1a2200468f98956d6eda50bcf4a53246cc00174ba924" dependencies = [ "aws-credential-types", "aws-runtime", @@ -546,9 +546,9 @@ dependencies = [ [[package]] name = "aws-sdk-kms" -version = "1.47.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564a597a3c71a957d60a2e4c62c93d78ee5a0d636531e15b760acad983a5c18e" +checksum = "bfd059dacda4dfd5b57f2bd453fc6555f9acb496cb77508d517da24cf5d73167" dependencies = [ "aws-credential-types", "aws-runtime", @@ -568,9 +568,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.46.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc2faec3205d496c7e57eff685dd944203df7ce16a4116d0281c44021788a7b" +checksum = "09677244a9da92172c8dc60109b4a9658597d4d298b188dd0018b6a66b410ca4" dependencies = [ "aws-credential-types", "aws-runtime", @@ -590,9 +590,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.47.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c93c241f52bc5e0476e259c953234dab7e2a35ee207ee202e86c0095ec4951dc" +checksum = "81fea2f3a8bb3bd10932ae7ad59cc59f65f270fc9183a7e91f501dc5efbef7ee" dependencies = [ "aws-credential-types", "aws-runtime", @@ -612,9 +612,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.46.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b259429be94a3459fa1b00c5684faee118d74f9577cc50aebadc36e507c63b5f" +checksum = "53dcf5e7d9bd1517b8b998e170e650047cea8a2b85fe1835abe3210713e541b7" dependencies = [ "aws-credential-types", "aws-runtime", @@ -635,9 +635,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.2.4" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8db6904450bafe7473c6ca9123f88cc11089e41a025408f992db4e22d3be68" +checksum = "5619742a0d8f253be760bfbb8e8e8368c69e3587e4637af5754e488a611499b1" dependencies = [ "aws-credential-types", "aws-smithy-http", @@ -708,9 +708,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.7.2" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a065c0fe6fdbdf9f11817eb68582b2ab4aff9e9c39e986ae48f7ec576c6322db" +checksum = "be28bd063fa91fd871d131fc8b68d7cd4c5fa0869bea68daca50dcb1cbd76be2" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -735,9 +735,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.7.2" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e086682a53d3aa241192aa110fa8dfce98f2f5ac2ead0de84d41582c7e8fdb96" +checksum = "92165296a47a812b267b4f41032ff8069ab7ff783696d217f0994a0d7ab585cd" dependencies = [ "aws-smithy-async", "aws-smithy-types", @@ -752,9 +752,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.2.7" +version = "1.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147100a7bea70fa20ef224a6bad700358305f5dc0f84649c53769761395b355b" +checksum = "4fbd94a32b3a7d55d3806fe27d98d3ad393050439dd05eb53ece36ec5e3d3510" dependencies = [ "base64-simd", "bytes", @@ -965,9 +965,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +checksum = "f5327f6c99920069d1fe374aa743be1af0031dea9f250852cdf1ae6a0861ee24" dependencies = [ "borsh-derive", "cfg_aliases", @@ -975,16 +975,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +checksum = "10aedd8f1a81a8aafbfde924b0e3061cd6fedd6f6bbcfc6a76e6fd426d7bfe26" dependencies = [ "once_cell", "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.79", - "syn_derive", + "syn 2.0.87", ] [[package]] @@ -1004,7 +1003,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "serde", ] @@ -1022,9 +1021,9 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "byte-unit" -version = "5.1.4" +version = "5.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ac19bdf0b2665407c39d82dbc937e951e7e2001609f0fb32edd0af45a2d63e" +checksum = "e1cd29c3c585209b0cbc7309bfe3ed7efd8c84c21b7af29c8bfae908f8777174" dependencies = [ "rust_decimal", "serde", @@ -1067,9 +1066,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "bytes-utils" @@ -1114,9 +1113,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.30" +version = "1.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" dependencies = [ "jobserver", "libc", @@ -1191,7 +1190,7 @@ checksum = "3147d8272e8fa0ccd29ce51194dd98f79ddfb8191ba9e3409884e751798acf3a" dependencies = [ "core2", "multibase", - "multihash 0.19.1", + "multihash 0.19.2", "unsigned-varint 0.8.0", ] @@ -1230,9 +1229,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.33" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9646e2e245bf62f45d39a0f3f36f1171ad1ea0d6967fd114bca72cb02a8fcdfb" +checksum = "11611dca53440593f38e6b25ec629de50b14cdfa63adc0fb856115a2c6d97595" dependencies = [ "clap", ] @@ -1256,7 +1255,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1356,9 +1355,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" @@ -1551,9 +1550,9 @@ checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" dependencies = [ "libc", ] @@ -1683,9 +1682,9 @@ dependencies = [ [[package]] name = "csv" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" dependencies = [ "csv-core", "itoa", @@ -1734,7 +1733,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1833,7 +1832,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1855,7 +1854,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1971,7 +1970,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1981,7 +1980,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1994,7 +1993,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2014,7 +2013,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "unicode-xid", ] @@ -2143,6 +2142,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "dissimilar" version = "1.0.9" @@ -2283,9 +2293,9 @@ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if 1.0.0", ] @@ -2319,7 +2329,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2332,7 +2342,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2343,7 +2353,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2409,9 +2419,9 @@ checksum = "5692dd7b5a1978a5aeb0ce83b7655c58ca8efdcb79d21036ea249da95afec2c6" [[package]] name = "escargot" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c000f23e9d459aef148b7267e02b03b94a0aaacf4ec64c65612f67e02f525fb6" +checksum = "05a3ac187a16b5382fef8c69fd1bad123c67b7cf3932240a2d43dcdd32cded88" dependencies = [ "log", "once_cell", @@ -2508,7 +2518,7 @@ checksum = "dd65f1b59dd22d680c7a626cc4a000c1e03d241c51c3e034d2bc9f1e90734f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2535,9 +2545,9 @@ checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fastrlp" @@ -2864,7 +2874,7 @@ dependencies = [ "ipfs-api-backend-hyper", "petgraph", "regex", - "reqwest 0.12.8", + "reqwest 0.12.9", "semver 1.0.23", "serde", "serde_ignored", @@ -3042,7 +3052,7 @@ dependencies = [ "regex", "serde", "serde_json", - "syn 2.0.79", + "syn 2.0.87", "thiserror", ] @@ -3223,7 +3233,7 @@ checksum = "ab0bc46a3552964bae5169e79b383761a54bd115ea66951a1a7a229edcefa55a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "synstructure 0.13.1", ] @@ -3365,9 +3375,9 @@ dependencies = [ [[package]] name = "fuels" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed08053e72bdb285d5a167c27a7a0d10f1dc4e27d1e6e5296dd2a67813bd13f" +checksum = "25bf359dceffcbab4163bca473a03658b912686c3aa81a223f828260729dd474" dependencies = [ "fuel-core-client", "fuel-crypto", @@ -3381,9 +3391,9 @@ dependencies = [ [[package]] name = "fuels-accounts" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fee90e8f3a4fc9392a6cde3010c561fa50da0f805d66fdb659eaa4d5d8a504" +checksum = "4b0b09d6ce3a12196f6944c74bdd795c39950d32ebaaf56b2943741a5e4308a1" dependencies = [ "async-trait", "chrono", @@ -3407,9 +3417,9 @@ dependencies = [ [[package]] name = "fuels-code-gen" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f857b7ff658400506ca6be57bb84fedda44b566e78f5f0a8d0782242f41615c0" +checksum = "78bf5f7b37ec598514fb3767abdae5372a9fa0919d350703f5d627ec2eb33456" dependencies = [ "Inflector", "fuel-abi-types", @@ -3418,14 +3428,14 @@ dependencies = [ "quote", "regex", "serde_json", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "fuels-core" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baccbdd81e624f57950dcb136b32b853c520dd954badf26b9f58de33f3d71c7e" +checksum = "ab66cdf52fa6ef98dbc9cc7b4ce19c6a340b2a4710c5d5f87eae39ffb868bad7" dependencies = [ "async-trait", "bech32", @@ -3452,22 +3462,22 @@ dependencies = [ [[package]] name = "fuels-macros" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da75294c5e9da312bdc49239736699ee84ea9c5bfbc19a61a8ee588a1247aa1" +checksum = "1471d221453d13d4643c9a698212781f0e8ac40f515a8566538db87409e30752" dependencies = [ "fuels-code-gen", "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "fuels-programs" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32675ed1c08edd28ddb648dfae0c60a1946d4368a69ddfa6434f2316e33f0520" +checksum = "7a854561a68ef4088972119cf31023d2d1afd58584da203bcb7dfbd1e84dd8fc" dependencies = [ "async-trait", "fuel-abi-types", @@ -3484,9 +3494,9 @@ dependencies = [ [[package]] name = "fuels-test-helpers" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02176c0fb1bf8cf58b8a9e5372efb650324740abcd4847b45bd0b041a0f133a2" +checksum = "5a7b428c35a54e4d667343b4051f07a7397e6039bd110411c37647db4478086e" dependencies = [ "fuel-core-chain-config", "fuel-core-client", @@ -3568,7 +3578,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3682,9 +3692,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.11" +version = "0.10.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebfc4febd088abdcbc9f1246896e57e37b7a34f6909840045a1767c6dafac7af" +checksum = "c04e5a94fdb56b1e91eb7df2658ad16832428b8eeda24ff1a0f0288de2bce554" dependencies = [ "bstr", "gix-trace", @@ -3695,9 +3705,9 @@ dependencies = [ [[package]] name = "gix-trace" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cae0e8661c3ff92688ce1c8b8058b3efb312aba9492bbe93661a21705ab431b" +checksum = "04bdde120c29f1fc23a24d3e115aeeea3d60d8e65bab92cc5f9d90d9302eb952" [[package]] name = "gix-url" @@ -3729,7 +3739,7 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -3815,11 +3825,12 @@ dependencies = [ [[package]] name = "handlebars" -version = "5.1.2" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315" dependencies = [ "log", + "num-order", "pest", "pest_derive", "serde", @@ -3867,9 +3878,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" dependencies = [ "foldhash", ] @@ -4139,7 +4150,7 @@ dependencies = [ "http 1.1.0", "hyper 1.5.0", "hyper-util", - "rustls 0.23.15", + "rustls 0.23.16", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -4176,9 +4187,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", @@ -4216,6 +4227,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -4234,12 +4363,23 @@ dependencies = [ [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -4285,26 +4425,26 @@ dependencies = [ [[package]] name = "impl-tools" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82c305b1081f1a99fda262883c788e50ab57d36c00830bdd7e0a82894ad965c" +checksum = "8a84bc8d2baf8da56e93b4247067d918e1a44829bbbe3e4b875aaf8d7d3c7bc9" dependencies = [ "autocfg", "impl-tools-lib", - "proc-macro-error", - "syn 2.0.79", + "proc-macro-error2", + "syn 2.0.87", ] [[package]] name = "impl-tools-lib" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85d3946d886eaab0702fa0c6585adcced581513223fa9df7ccfabbd9fa331a88" +checksum = "a795a1e201125947a063b967c79de6ae152143ab522f481d4f493c44835ba37a" dependencies = [ - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -4361,7 +4501,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "rayon", "serde", ] @@ -4403,9 +4543,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.40.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6593a41c7a73841868772495db7dc1e8ecab43bb5c0b6da2059246c4b506ab60" +checksum = "7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8" dependencies = [ "console", "lazy_static", @@ -4605,9 +4745,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.161" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libdbus-sys" @@ -4635,9 +4775,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libp2p-identity" @@ -4649,7 +4789,7 @@ dependencies = [ "bs58", "hkdf", "libsecp256k1", - "multihash 0.19.1", + "multihash 0.19.2", "quick-protobuf", "sha2 0.10.8", "thiserror", @@ -4777,6 +4917,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + [[package]] name = "lock_api" version = "0.4.12" @@ -4840,9 +4986,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.40" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5" +checksum = "7624879735513024d323e7267a0b3a7176aceb0db537939beb4ee31d9e8945e3" dependencies = [ "anyhow", "chrono", @@ -4918,9 +5064,9 @@ dependencies = [ [[package]] name = "minifier" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa3f302fe0f8de065d4a2d1ed64f60204623cac58b80cd3c2a83a25d5a7d437" +checksum = "bd559bbf5d350ac7f2c1cf92ed71a869b847a92bce0c1318b47932a5b5f65cdd" dependencies = [ "clap", ] @@ -5001,12 +5147,12 @@ dependencies = [ [[package]] name = "multihash" -version = "0.19.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +checksum = "cc41f430805af9d1cf4adae4ed2149c759b877b01d909a1f40256188d09345d2" dependencies = [ "core2", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", ] [[package]] @@ -5224,6 +5370,21 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -5270,10 +5431,10 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5296,7 +5457,7 @@ checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "crc32fast", "flate2", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "indexmap 2.6.0", "memchr", "ruzstd", @@ -5377,7 +5538,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5388,9 +5549,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.3.2+3.3.2" +version = "300.4.0+3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b" +checksum = "a709e02f2b4aca747929cca5ed248880847c650233cf8b8cdc48f40aaf4898a6" dependencies = [ "cc", ] @@ -5601,7 +5762,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5657,7 +5818,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5671,29 +5832,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -5895,11 +6056,32 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", +] + [[package]] name = "proc-macro2" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -5924,7 +6106,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -6175,13 +6357,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -6196,9 +6378,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -6277,9 +6459,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.8" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", "bytes", @@ -6624,9 +6806,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" dependencies = [ "bitflags 2.6.0", "errno", @@ -6649,9 +6831,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.15" +version = "0.23.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" dependencies = [ "once_cell", "rustls-pki-types", @@ -6792,9 +6974,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.2.2" +version = "2.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c1f7fc6deb21665a9060dfc7d271be784669295a31babdcd4dd2c79ae8cbfb" +checksum = "d8d25269dd3a12467afe2e510f69fb0b46b698e5afb296b59f2145259deaf8e8" dependencies = [ "sdd", ] @@ -6931,9 +7113,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -6968,22 +7150,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -6997,9 +7179,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.129" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbcf9b78a125ee667ae19388837dd12294b858d101fdd393cb9d5501ef09eb2" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "indexmap 2.6.0", "itoa", @@ -7016,7 +7198,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7067,7 +7249,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7085,9 +7267,9 @@ dependencies = [ [[package]] name = "serial_test" -version = "3.1.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b4b487fe2acf240a021cf57c6b2b4903b1e78ca0ecd862a71b71d2a51fed77d" +checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" dependencies = [ "futures", "log", @@ -7099,13 +7281,13 @@ dependencies = [ [[package]] name = "serial_test_derive" -version = "3.1.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" +checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7351,9 +7533,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "str_indices" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c" +checksum = "d08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6" [[package]] name = "strsim" @@ -7414,7 +7596,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7427,7 +7609,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7555,7 +7737,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7597,7 +7779,7 @@ dependencies = [ "sway-types", "sway-utils", "swayfmt", - "syn 2.0.79", + "syn 2.0.87", "tempfile", "thiserror", "tikv-jemallocator", @@ -7706,27 +7888,15 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "syn_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.79", -] - [[package]] name = "sync_wrapper" version = "0.1.2" @@ -7762,7 +7932,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7847,9 +8017,9 @@ dependencies = [ [[package]] name = "tai64" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7401421025f4132e6c1f7af5e7f8287383969f36e6628016cd509b8d3da9dc" +checksum = "014639506e4f425c78e823eabf56e71c093f940ae55b43e58f682e7bc2f5887a" dependencies = [ "serde", ] @@ -7883,9 +8053,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" +checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" dependencies = [ "filetime", "libc", @@ -7894,9 +8064,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if 1.0.0", "fastrand", @@ -8038,22 +8208,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8154,6 +8324,16 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -8181,9 +8361,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -8215,7 +8395,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8244,7 +8424,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.15", + "rustls 0.23.16", "rustls-pki-types", "tokio", ] @@ -8387,7 +8567,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8415,7 +8595,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8488,7 +8668,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8503,7 +8683,7 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "static_assertions", ] @@ -8556,12 +8736,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" @@ -8649,12 +8826,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna 1.0.3", "percent-encoding", "serde", ] @@ -8665,12 +8842,24 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + [[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -8835,7 +9024,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-shared", ] @@ -8869,7 +9058,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -9162,6 +9351,18 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "wyz" version = "0.5.1" @@ -9215,6 +9416,30 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure 0.13.1", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -9233,7 +9458,28 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure 0.13.1", ] [[package]] @@ -9253,5 +9499,27 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] diff --git a/Cargo.toml b/Cargo.toml index 15363bd5c55..31bc6386951 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,9 +89,9 @@ fuel-core-types = { version = "0.40", default-features = false } # Dependencies from the `fuels-rs` repository: -fuels = "0.66.9" -fuels-core = "0.66.9" -fuels-accounts = "0.66.9" +fuels = "0.66.10" +fuels-core = "0.66.10" +fuels-accounts = "0.66.10" # Dependencies from the `fuel-vm` repository: fuel-asm = "0.58" diff --git a/test/src/sdk-harness/Cargo.lock b/test/src/sdk-harness/Cargo.lock index dad11fa0e14..54d09476c97 100644 --- a/test/src/sdk-harness/Cargo.lock +++ b/test/src/sdk-harness/Cargo.lock @@ -14,18 +14,18 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ - "gimli", + "gimli 0.31.1", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aead" @@ -85,9 +85,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "android-tzdata" @@ -106,9 +106,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -121,61 +121,61 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ascii" @@ -185,9 +185,9 @@ checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" [[package]] name = "asn1-rs" -version = "0.5.2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -201,25 +201,25 @@ dependencies = [ [[package]] name = "asn1-rs-derive" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", - "synstructure 0.12.6", + "syn 2.0.87", + "synstructure", ] [[package]] name = "asn1-rs-impl" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] @@ -251,7 +251,7 @@ dependencies = [ "futures-timer", "futures-util", "http 1.1.0", - "indexmap 2.2.6", + "indexmap 2.6.0", "mime", "multer", "num-traits", @@ -280,7 +280,7 @@ dependencies = [ "proc-macro2", "quote", "strum 0.26.3", - "syn 2.0.63", + "syn 2.0.87", "thiserror", ] @@ -303,16 +303,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef5ec94176a12a8cbe985cd73f2e54dc9c702c88c766bdef12f1f3a67cedbee1" dependencies = [ "bytes", - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_json", ] [[package]] name = "async-io" -version = "2.3.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ "async-lock", "cfg-if", @@ -324,14 +324,14 @@ dependencies = [ "rustix", "slab", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "async-lock" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener", "event-listener-strategy", @@ -340,9 +340,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -351,24 +351,24 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -419,9 +419,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" @@ -472,18 +472,18 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", - "object 0.32.2", + "object", "rustc-demangle", "serde", + "windows-targets 0.52.6", ] [[package]] @@ -536,9 +536,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -606,22 +606,22 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" dependencies = [ "serde", ] [[package]] name = "cc" -version = "1.0.97" +version = "1.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" dependencies = [ "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] @@ -630,6 +630,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chacha20" version = "0.9.1" @@ -666,7 +672,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -682,9 +688,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -692,9 +698,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -704,21 +710,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "cobs" @@ -780,9 +786,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "combine" @@ -871,9 +877,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core2" @@ -895,27 +901,27 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" dependencies = [ "libc", ] [[package]] name = "cranelift-bforest" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305d51c180ebdc46ef61bc60c54ae6512db3bc9a05842a1f1e762e45977019ab" +checksum = "4a41b85213deedf877555a7878ca9fb680ccba8183611c4bb8030ed281b2ad83" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3247afacd9b13d620033f3190d9e49d1beefc1acb33d5604a249956c9c13709" +checksum = "690d8ae6c73748e5ce3d8fe59034dceadb8823e6c8994ba324141c5eae909b0e" dependencies = [ "serde", "serde_derive", @@ -923,9 +929,9 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7ca95e831c18d1356da783765c344207cbdffea91e13e47fa9327dbb2e0719" +checksum = "0ce027a7b16f8b86f60ff6819615273635186d607a0c225ee6ac340d7d18f978" dependencies = [ "bumpalo", "cranelift-bforest", @@ -935,44 +941,44 @@ dependencies = [ "cranelift-control", "cranelift-entity", "cranelift-isle", - "gimli", + "gimli 0.28.1", "hashbrown 0.14.5", "log", "regalloc2", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "450c105fa1e51bfba4e95a86e926504a867ad5639d63f31d43fe3b7ec1f1c9ef" +checksum = "f0a2d2ab65e6cbf91f81781d8da65ec2005510f18300eff21a99526ed6785863" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5479117cd1266881479908d383086561cee37e49affbea9b1e6b594cc21cc220" +checksum = "efcff860573cf3db9ae98fbd949240d78b319df686cc306872e7fab60e9c84d7" [[package]] name = "cranelift-control" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34378804f0abfdd22c068a741cfeed86938b92375b2a96fb0b42c878e0141bfb" +checksum = "69d70e5b75c2d5541ef80a99966ccd97aaa54d2a6af19ea31759a28538e1685a" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a48cb0a194c9ba82fec35a1e492055388d89b2e3c03dee9dcf2488892be8004d" +checksum = "d21d3089714278920030321829090d9482c91e5ff2339f2f697f8425bffdcba3" dependencies = [ "cranelift-bitset", "serde", @@ -981,9 +987,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8327afc6c1c05f4be62fefce5b439fa83521c65363a322e86ea32c85e7ceaf64" +checksum = "7308482930f2a2fad4fe25a06054f6f9a4ee1ab97264308c661b037cb60001a3" dependencies = [ "cranelift-codegen", "log", @@ -993,15 +999,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56b08621c00321efcfa3eee6a3179adc009e21ea8d24ca7adc3c326184bc3f48" +checksum = "ab4c59e259dab0e6958dabcc536b30845574f027ba6e5000498cdaf7e7ed2d30" [[package]] name = "cranelift-native" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51180b147c8557c1196c77b098f04140c91962e135ea152cd2fcabf40cf365c" +checksum = "d77ac3dfb61ef3159998105116acdfeaec75e4296c43ee2dcc4ea39838c0080e" dependencies = [ "cranelift-codegen", "libc", @@ -1010,9 +1016,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "019e3dccb7f15e0bc14f0ddc034ec608a66df8e05c9e1e16f75a7716f8461799" +checksum = "1d883f1b8d3d1dab4797407117bc8a1824f4a1fe86654aee2ee3205613f77d3e" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -1035,9 +1041,9 @@ dependencies = [ [[package]] name = "critical-section" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "crossbeam-deque" @@ -1060,9 +1066,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1114,16 +1120,15 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.1.2" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "platforms", "rustc_version", "subtle", "zeroize", @@ -1137,7 +1142,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -1225,7 +1230,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -1247,7 +1252,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -1288,9 +1293,9 @@ dependencies = [ [[package]] name = "der-parser" -version = "8.2.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" dependencies = [ "asn1-rs", "displaydoc", @@ -1323,15 +1328,15 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] @@ -1390,13 +1395,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -1452,9 +1457,9 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elliptic-curve" @@ -1481,6 +1486,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "encode_unicode" version = "0.3.6" @@ -1489,23 +1500,23 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -1525,7 +1536,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -1574,9 +1585,9 @@ checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" [[package]] name = "event-listener" -version = "4.0.3" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", @@ -1585,9 +1596,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ "event-listener", "pin-project-lite", @@ -1617,9 +1628,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "ff" @@ -1667,6 +1678,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1695,7 +1712,7 @@ dependencies = [ "regex", "serde", "serde_json", - "syn 2.0.63", + "syn 2.0.87", "thiserror", ] @@ -1705,7 +1722,7 @@ version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "122c27ab46707017063bf1c6e0b4f3de881e22e81b4059750a0dc95033d9cc26" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "fuel-types 0.56.0", "serde", "strum 0.24.1", @@ -1717,7 +1734,7 @@ version = "0.58.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f325971bf9047ec70004f80a989e03456316bc19cbef3ff3a39a38b192ab56e" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "fuel-types 0.58.2", "serde", "strum 0.24.1", @@ -1783,7 +1800,7 @@ dependencies = [ "tower", "tower-http 0.4.4", "tracing", - "uuid 1.8.0", + "uuid 1.11.0", ] [[package]] @@ -2189,8 +2206,8 @@ checksum = "3f49fdbfc1615d88d2849650afc2b0ac2fecd69661ebadd31a073d8416747764" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", - "synstructure 0.13.1", + "syn 2.0.87", + "synstructure", ] [[package]] @@ -2201,8 +2218,8 @@ checksum = "ab0bc46a3552964bae5169e79b383761a54bd115ea66951a1a7a229edcefa55a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", - "synstructure 0.13.1", + "syn 2.0.87", + "synstructure", ] [[package]] @@ -2263,7 +2280,7 @@ version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13aae44611588d199dd119e4a0ebd8eb7ae4cde6bf8b4d12715610b1f5e5b731" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "derivative", "derive_more", "fuel-asm 0.56.0", @@ -2285,7 +2302,7 @@ version = "0.58.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6723bb8710ba2b70516ac94d34459593225870c937670fb3afaf82e0354667ac" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "derivative", "derive_more", "fuel-asm 0.58.2", @@ -2333,7 +2350,7 @@ checksum = "64fc4695efac9207276f6229f2dd9811848b328a13604a698f7bce1d452bd986" dependencies = [ "async-trait", "backtrace", - "bitflags 2.5.0", + "bitflags 2.6.0", "derivative", "derive_more", "ethnum", @@ -2365,7 +2382,7 @@ dependencies = [ "anyhow", "async-trait", "backtrace", - "bitflags 2.5.0", + "bitflags 2.6.0", "derivative", "derive_more", "ethnum", @@ -2393,9 +2410,9 @@ dependencies = [ [[package]] name = "fuels" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed08053e72bdb285d5a167c27a7a0d10f1dc4e27d1e6e5296dd2a67813bd13f" +checksum = "25bf359dceffcbab4163bca473a03658b912686c3aa81a223f828260729dd474" dependencies = [ "fuel-core-client", "fuel-crypto 0.58.2", @@ -2409,9 +2426,9 @@ dependencies = [ [[package]] name = "fuels-accounts" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fee90e8f3a4fc9392a6cde3010c561fa50da0f805d66fdb659eaa4d5d8a504" +checksum = "4b0b09d6ce3a12196f6944c74bdd795c39950d32ebaaf56b2943741a5e4308a1" dependencies = [ "async-trait", "chrono", @@ -2435,9 +2452,9 @@ dependencies = [ [[package]] name = "fuels-code-gen" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f857b7ff658400506ca6be57bb84fedda44b566e78f5f0a8d0782242f41615c0" +checksum = "78bf5f7b37ec598514fb3767abdae5372a9fa0919d350703f5d627ec2eb33456" dependencies = [ "Inflector", "fuel-abi-types", @@ -2446,14 +2463,14 @@ dependencies = [ "quote", "regex", "serde_json", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "fuels-core" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baccbdd81e624f57950dcb136b32b853c520dd954badf26b9f58de33f3d71c7e" +checksum = "ab66cdf52fa6ef98dbc9cc7b4ce19c6a340b2a4710c5d5f87eae39ffb868bad7" dependencies = [ "async-trait", "bech32", @@ -2480,22 +2497,22 @@ dependencies = [ [[package]] name = "fuels-macros" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da75294c5e9da312bdc49239736699ee84ea9c5bfbc19a61a8ee588a1247aa1" +checksum = "1471d221453d13d4643c9a698212781f0e8ac40f515a8566538db87409e30752" dependencies = [ "fuels-code-gen", "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "fuels-programs" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32675ed1c08edd28ddb648dfae0c60a1946d4368a69ddfa6434f2316e33f0520" +checksum = "7a854561a68ef4088972119cf31023d2d1afd58584da203bcb7dfbd1e84dd8fc" dependencies = [ "async-trait", "fuel-abi-types", @@ -2512,9 +2529,9 @@ dependencies = [ [[package]] name = "fuels-test-helpers" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02176c0fb1bf8cf58b8a9e5372efb650324740abcd4847b45bd0b041a0f133a2" +checksum = "5a7b428c35a54e4d667343b4051f07a7397e6039bd110411c37647db4478086e" dependencies = [ "fuel-core", "fuel-core-chain-config", @@ -2543,9 +2560,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -2558,9 +2575,9 @@ dependencies = [ [[package]] name = "futures-bounded" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e2774cc104e198ef3d3e1ff4ab40f86fa3245d6cb6a3a46174f21463cee173" +checksum = "91f328e7fb845fc832912fb6a34f40cf6d1888c92f974d1893a54e97b5ff542e" dependencies = [ "futures-timer", "futures-util", @@ -2568,9 +2585,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -2578,15 +2595,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -2596,15 +2613,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ "futures-core", "pin-project-lite", @@ -2612,36 +2629,37 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "futures-rustls" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd3cf68c183738046838e300353e4716c674dc5e56890de4826801a6622a28" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls", + "rustls 0.23.16", + "rustls-pki-types", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-ticker" @@ -2662,9 +2680,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -2717,10 +2735,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ "fallible-iterator", - "indexmap 2.2.6", + "indexmap 2.6.0", "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + [[package]] name = "graphql-parser" version = "0.4.0" @@ -2754,7 +2778,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -2796,6 +2820,17 @@ dependencies = [ "serde", ] +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "heapless" version = "0.7.17" @@ -2828,6 +2863,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -2989,9 +3030,9 @@ checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -3001,9 +3042,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -3033,7 +3074,7 @@ dependencies = [ "http 0.2.12", "hyper", "log", - "rustls", + "rustls 0.21.12", "rustls-native-certs", "tokio", "tokio-rustls", @@ -3054,9 +3095,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -3075,6 +3116,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "id-arena" version = "2.2.1" @@ -3109,12 +3268,23 @@ dependencies = [ [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -3167,26 +3337,26 @@ dependencies = [ [[package]] name = "impl-tools" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82c305b1081f1a99fda262883c788e50ab57d36c00830bdd7e0a82894ad965c" +checksum = "8a84bc8d2baf8da56e93b4247067d918e1a44829bbbe3e4b875aaf8d7d3c7bc9" dependencies = [ "autocfg", "impl-tools-lib", - "proc-macro-error", - "syn 2.0.63", + "proc-macro-error2", + "syn 2.0.87", ] [[package]] name = "impl-tools-lib" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85d3946d886eaab0702fa0c6585adcced581513223fa9df7ccfabbd9fa331a88" +checksum = "a795a1e201125947a063b967c79de6ae152143ab522f481d4f493c44835ba37a" dependencies = [ - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -3202,12 +3372,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.1", "serde", ] @@ -3235,9 +3405,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] @@ -3262,15 +3432,15 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -3307,18 +3477,18 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] [[package]] name = "k256" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", "ecdsa", @@ -3339,9 +3509,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "leb128" @@ -3351,15 +3521,15 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libp2p" @@ -3423,15 +3593,14 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.41.2" +version = "0.41.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8130a8269e65a2554d55131c770bdf4bcd94d2b8d4efb24ca23699be65066c05" +checksum = "a5a8920cbd8540059a01950c1e5c96ea8d89eb50c51cd366fc18bdf540a6e48f" dependencies = [ "either", "fnv", "futures", "futures-timer", - "instant", "libp2p-identity", "multiaddr", "multihash", @@ -3447,6 +3616,7 @@ dependencies = [ "tracing", "unsigned-varint 0.8.0", "void", + "web-time", ] [[package]] @@ -3521,9 +3691,9 @@ dependencies = [ [[package]] name = "libp2p-identity" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999ec70441b2fb35355076726a6bc466c932e9bdc66f6a11c6c0aa17c7ab9be0" +checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" dependencies = [ "asn1_der", "bs58", @@ -3654,9 +3824,9 @@ dependencies = [ [[package]] name = "libp2p-quic" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0375cdfee57b47b313ef1f0fdb625b78aed770d33a40cf1c294a371ff5e6666" +checksum = "c67296ad4e092e23f92aea3d2bdb6f24eab79c0929ed816dfb460ea2f4567d2b" dependencies = [ "bytes", "futures", @@ -3668,8 +3838,8 @@ dependencies = [ "parking_lot", "quinn", "rand", - "ring 0.16.20", - "rustls", + "ring 0.17.8", + "rustls 0.23.16", "socket2", "thiserror", "tokio", @@ -3678,9 +3848,9 @@ dependencies = [ [[package]] name = "libp2p-request-response" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6946e5456240b3173187cc37a17cb40c3cd1f7138c76e2c773e0d792a42a8de1" +checksum = "c314fe28368da5e3a262553fb0ad575c1c8934c461e10de10265551478163836" dependencies = [ "async-trait", "futures", @@ -3729,7 +3899,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -3751,18 +3921,18 @@ dependencies = [ [[package]] name = "libp2p-tls" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ce7e3c2e7569d685d08ec795157981722ff96e9e9f9eae75df3c29d02b07a5" +checksum = "72b7b831e55ce2aa6c354e6861a85fdd4dd0a2b97d5e276fabac0e4810a71776" dependencies = [ "futures", "futures-rustls", "libp2p-core", "libp2p-identity", "rcgen", - "ring 0.16.20", - "rustls", - "rustls-webpki", + "ring 0.17.8", + "rustls 0.23.16", + "rustls-webpki 0.101.7", "thiserror", "x509-parser", "yasna", @@ -3786,9 +3956,9 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.43.0" +version = "0.43.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4846d51afd08180e164291c3754ba30dd4fbac6fac65571be56403c16431a5e" +checksum = "85b953b6803a1f3161a989538974d72511c4e48a4af355337b6fb90723c56c05" dependencies = [ "either", "futures", @@ -3799,6 +3969,7 @@ dependencies = [ "pin-project-lite", "rw-stream-sink", "soketto", + "thiserror", "tracing", "url", "webpki-roots", @@ -3806,9 +3977,9 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.45.1" +version = "0.45.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200cbe50349a44760927d50b431d77bed79b9c0a3959de1af8d24a63434b71e5" +checksum = "ddd5265f6b80f94d48a3963541aad183cc598a645755d2f1805a373e41e0716b" dependencies = [ "either", "futures", @@ -3816,7 +3987,7 @@ dependencies = [ "thiserror", "tracing", "yamux 0.12.1", - "yamux 0.13.2", + "yamux 0.13.3", ] [[package]] @@ -3825,7 +3996,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", ] @@ -3885,9 +4056,15 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" [[package]] name = "lock_api" @@ -3901,17 +4078,17 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.1", ] [[package]] @@ -3946,9 +4123,9 @@ checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memfd" @@ -3973,22 +4150,23 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi 0.3.9", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -4037,9 +4215,9 @@ dependencies = [ [[package]] name = "multiaddr" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" +checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" dependencies = [ "arrayref", "byteorder", @@ -4050,7 +4228,7 @@ dependencies = [ "percent-encoding", "serde", "static_assertions", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", "url", ] @@ -4067,12 +4245,12 @@ dependencies = [ [[package]] name = "multihash" -version = "0.19.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +checksum = "cc41f430805af9d1cf4adae4ed2149c759b877b01d909a1f40256188d09345d2" dependencies = [ "core2", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", ] [[package]] @@ -4190,9 +4368,9 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -4239,29 +4417,29 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] [[package]] name = "num_enum" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -4272,39 +4450,30 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "crc32fast", - "hashbrown 0.14.5", - "indexmap 2.2.6", + "hashbrown 0.15.1", + "indexmap 2.6.0", "memchr", ] [[package]] name = "oid-registry" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" dependencies = [ "asn1-rs", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opaque-debug" @@ -4332,15 +4501,15 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -4356,7 +4525,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -4402,9 +4571,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", "thiserror", @@ -4418,34 +4587,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.2.6", + "indexmap 2.6.0", ] [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -4465,29 +4634,23 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "platforms" -version = "3.4.0" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polling" -version = "3.7.0" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi", + "hermit-abi 0.4.0", "pin-project-lite", "rustix", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4515,9 +4678,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "portpicker" @@ -4530,12 +4693,13 @@ dependencies = [ [[package]] name = "postcard" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" dependencies = [ "cobs", - "embedded-io", + "embedded-io 0.4.0", + "embedded-io 0.6.1", "heapless", "serde", ] @@ -4548,9 +4712,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "predicates" @@ -4568,15 +4735,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" dependencies = [ "predicates-core", "termtree", @@ -4584,9 +4751,9 @@ dependencies = [ [[package]] name = "pretty_assertions" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", @@ -4613,50 +4780,48 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.1", + "toml_edit", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "proc-macro-error-attr2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" dependencies = [ - "proc-macro-error-attr", "proc-macro2", "quote", - "version_check", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "proc-macro-error2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" dependencies = [ + "proc-macro-error-attr2", "proc-macro2", "quote", - "version_check", ] [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] [[package]] name = "prometheus-client" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ca959da22a332509f2a73ae9e5f23f9dcfc31fd3a54d71f159495bd5909baa" +checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", @@ -4672,7 +4837,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -4730,17 +4895,18 @@ dependencies = [ [[package]] name = "quinn" -version = "0.10.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", "futures-io", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", - "rustls", + "rustc-hash 2.0.0", + "rustls 0.23.16", + "socket2", "thiserror", "tokio", "tracing", @@ -4748,15 +4914,15 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.10.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand", - "ring 0.16.20", - "rustc-hash", - "rustls", + "ring 0.17.8", + "rustc-hash 2.0.0", + "rustls 0.23.16", "slab", "thiserror", "tinyvec", @@ -4765,22 +4931,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.4.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" dependencies = [ - "bytes", + "cfg_aliases", "libc", + "once_cell", "socket2", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -4855,11 +5022,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -4881,16 +5048,16 @@ checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" dependencies = [ "hashbrown 0.13.2", "log", - "rustc-hash", + "rustc-hash 1.1.0", "slice-group-by", "smallvec", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -4900,9 +5067,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -4911,9 +5078,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" @@ -4940,7 +5107,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", + "rustls 0.21.12", "rustls-pemfile", "serde", "serde_json", @@ -5044,11 +5211,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] @@ -5064,11 +5237,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -5083,10 +5256,24 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring 0.17.8", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" +dependencies = [ + "once_cell", + "ring 0.17.8", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -5108,6 +5295,12 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -5118,11 +5311,22 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "rw-stream-sink" @@ -5152,11 +5356,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5257,11 +5461,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -5270,9 +5474,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -5286,40 +5490,41 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.201" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -5338,15 +5543,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.1" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_derive", "serde_json", @@ -5356,27 +5561,25 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.1" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] -name = "sha-1" -version = "0.9.8" +name = "sha1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "block-buffer 0.9.0", "cfg-if", "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "digest 0.10.7", ] [[package]] @@ -5413,6 +5616,12 @@ dependencies = [ "keccak", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -5485,17 +5694,17 @@ dependencies = [ [[package]] name = "soketto" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" +checksum = "37468c595637c10857701c990f93a40ce0e357cedb0953d1c26c8d8027f9bb53" dependencies = [ - "base64 0.13.1", + "base64 0.22.1", "bytes", "futures", "httparse", "log", "rand", - "sha-1", + "sha1", ] [[package]] @@ -5609,7 +5818,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -5622,14 +5831,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -5644,9 +5853,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.63" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -5659,18 +5868,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", -] - [[package]] name = "synstructure" version = "0.13.1" @@ -5679,7 +5876,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -5705,9 +5902,9 @@ dependencies = [ [[package]] name = "tai64" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7401421025f4132e6c1f7af5e7f8287383969f36e6628016cd509b8d3da9dc" +checksum = "014639506e4f425c78e823eabf56e71c093f940ae55b43e58f682e7bc2f5887a" dependencies = [ "serde", ] @@ -5726,14 +5923,15 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5772,22 +5970,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.60" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.60" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -5821,11 +6019,21 @@ dependencies = [ "time-core", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -5838,21 +6046,20 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -5867,13 +6074,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -5892,15 +6099,15 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -5910,9 +6117,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -5923,47 +6130,36 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.12", + "toml_edit", ] [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.2.6", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" -dependencies = [ - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow", ] [[package]] @@ -6008,7 +6204,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "bytes", "futures-core", "futures-util", @@ -6024,15 +6220,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -6054,7 +6250,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -6092,9 +6288,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "uint" @@ -6110,36 +6306,36 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" @@ -6190,20 +6386,32 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna 1.0.3", "percent-encoding", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" @@ -6217,18 +6425,18 @@ dependencies = [ [[package]] name = "uuid" -version = "1.8.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", ] [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "void" @@ -6253,34 +6461,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -6290,9 +6499,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6300,22 +6509,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-encoder" @@ -6333,9 +6542,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d28bc49ba1e5c5b61ffa7a2eace10820443c4b7d1c0b144109261d14570fdf8" dependencies = [ "ahash", - "bitflags 2.5.0", + "bitflags 2.6.0", "hashbrown 0.14.5", - "indexmap 2.2.6", + "indexmap 2.6.0", "semver", "serde", ] @@ -6353,23 +6562,23 @@ dependencies = [ [[package]] name = "wasmtime" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07232e0b473af36112da7348f51e73fa8b11047a6cb546096da3812930b7c93a" +checksum = "fe501caefeb9f7b15360bdd7e47ad96e20223846f1c7db485ae5820ba5acc3d2" dependencies = [ "anyhow", - "bitflags 2.5.0", + "bitflags 2.6.0", "bumpalo", "cc", "cfg-if", "hashbrown 0.14.5", - "indexmap 2.2.6", + "indexmap 2.6.0", "libc", "libm", "log", "mach2", "memfd", - "object 0.36.4", + "object", "once_cell", "paste", "postcard", @@ -6395,18 +6604,18 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a9c42562d879c749288d9a26acc0d95d2ca069e30c2ec2efce84461c4d62b3" +checksum = "c904a057d74bfa0ad9369a3fd99231d81ba0345f059d03c9148c3bb2abbf310f" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d5d5aac98c8ae87cf5244495da7722e3fa022aa6f3f4fcd5e3d6e5699ce422" +checksum = "8dff4d467d6b5bd0d137f5426f45178222e40b59e49ab3a7361420262b9f00df" dependencies = [ "anyhow", "base64 0.21.7", @@ -6424,14 +6633,14 @@ dependencies = [ [[package]] name = "wasmtime-component-macro" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0c3f57c4bc96f9b4a6ff4d6cb6e837913eff32e98d09e2b6d79b5c4647b415b" +checksum = "3a96185dab1c14ffb986ff2b3a2185d15acf2b801ca7895aa35ee80328e2ce38" dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", "wasmtime-component-util", "wasmtime-wit-bindgen", "wit-parser", @@ -6439,15 +6648,15 @@ dependencies = [ [[package]] name = "wasmtime-component-util" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1da707969bc31a565da9b32d087eb2370c95c6f2087c5539a15f2e3b27e77203" +checksum = "71a40200d42a8985edadb4007a0ed320756cbe28065b83e0027e39524c1b1b22" [[package]] name = "wasmtime-cranelift" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62cb6135ec46994299be711b78b03acaa9480de3715f827d450f0c947a84977c" +checksum = "b099ef9b7808fa8d18cad32243e78e9c07a4a8aacfa913d88dc08704b1643c49" dependencies = [ "anyhow", "cfg-if", @@ -6457,9 +6666,9 @@ dependencies = [ "cranelift-frontend", "cranelift-native", "cranelift-wasm", - "gimli", + "gimli 0.28.1", "log", - "object 0.36.4", + "object", "target-lexicon", "thiserror", "wasmparser", @@ -6469,17 +6678,17 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bcaa3b42a0718e9123da7fb75e8e13fc95df7db2a7e32e2f2f4f0d3333b7d6f" +checksum = "e2f1765f6ca1a166927bee13ad4aed7bf18269f34c0cd7d6d523889a0b52e6ee" dependencies = [ "anyhow", "cranelift-bitset", "cranelift-entity", - "gimli", - "indexmap 2.2.6", + "gimli 0.28.1", + "indexmap 2.6.0", "log", - "object 0.36.4", + "object", "postcard", "serde", "serde_derive", @@ -6492,9 +6701,9 @@ dependencies = [ [[package]] name = "wasmtime-jit-icache-coherence" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfee42dac5148fc2664ab1f5cb8d7fa77a28d1a2cf1d9483abc2c3d751a58b9" +checksum = "1e1a826e4ccd0803b2f7463289cad104f40d09d06bc8acf1a614230a47b4d96f" dependencies = [ "anyhow", "cfg-if", @@ -6504,15 +6713,15 @@ dependencies = [ [[package]] name = "wasmtime-slab" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42eb8f6515708ec67974998c3e644101db4186308985f5ef7c2ef324ff33c948" +checksum = "f92a137c17c992eb5eaacfa0f0590353471e49dbb4bdbdf9cf7536d66109e63a" [[package]] name = "wasmtime-types" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046873fb8fb3e9652f3fd76fe99c8c8129007695c3d73b2e307fdae40f6e324c" +checksum = "a6072ac3267866d99ca726b6a4f157df9b733aac8082e902d527368f07c303ba" dependencies = [ "anyhow", "cranelift-entity", @@ -6524,32 +6733,42 @@ dependencies = [ [[package]] name = "wasmtime-versioned-export-macros" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c02af2e9dbeb427304d1a08787d70ed0dbfec1af2236616f84c9f1f03e7969" +checksum = "a2bde986038b819bc43a21fef0610aeb47aabfe3ea09ca3533a7b81023b84ec6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "wasmtime-wit-bindgen" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f528f8b8a2376a3dacaf497d960216dd466d324425361e1e00e26de0a7705c" +checksum = "8f88e49a9b81746ec0cede5505e40a4012c92cb5054cd7ef4300dc57c36f26b1" dependencies = [ "anyhow", "heck 0.4.1", - "indexmap 2.2.6", + "indexmap 2.6.0", "wit-parser", ] [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -6563,9 +6782,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "which" -version = "6.0.1" +version = "6.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7" +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" dependencies = [ "either", "home", @@ -6601,7 +6820,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -6635,7 +6854,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -6653,7 +6872,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -6673,18 +6901,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -6695,9 +6923,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -6707,9 +6935,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -6719,15 +6947,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -6737,9 +6965,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -6749,9 +6977,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -6761,9 +6989,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -6773,24 +7001,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" - -[[package]] -name = "winnow" -version = "0.5.40" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -6819,7 +7038,7 @@ checksum = "ceeb0424aa8679f3fcf2d6e3cfa381f3d6fa6179976a2c05a6249dd2bb426716" dependencies = [ "anyhow", "id-arena", - "indexmap 2.2.6", + "indexmap 2.6.0", "log", "semver", "serde", @@ -6829,6 +7048,18 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "wyz" version = "0.5.1" @@ -6852,9 +7083,9 @@ dependencies = [ [[package]] name = "x509-parser" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" dependencies = [ "asn1-rs", "data-encoding", @@ -6869,9 +7100,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.20" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" +checksum = "af310deaae937e48a26602b730250b4949e125f468f11e6990be3e5304ddd96f" [[package]] name = "xmltree" @@ -6899,25 +7130,25 @@ dependencies = [ [[package]] name = "yamux" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f97202f6b125031b95d83e01dc57292b529384f80bfae4677e4bbc10178cf72" +checksum = "a31b5e376a8b012bee9c423acdbb835fc34d45001cfa3106236a624e4b738028" dependencies = [ "futures", - "instant", "log", "nohash-hasher", "parking_lot", "pin-project", "rand", "static_assertions", + "web-time", ] [[package]] name = "yansi" -version = "0.5.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yasna" @@ -6928,31 +7159,77 @@ dependencies = [ "time", ] +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure", +] + [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", + "synstructure", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] @@ -6965,7 +7242,29 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] diff --git a/test/src/sdk-harness/Cargo.toml b/test/src/sdk-harness/Cargo.toml index 3d28c7b1506..7a2a74da1f1 100644 --- a/test/src/sdk-harness/Cargo.toml +++ b/test/src/sdk-harness/Cargo.toml @@ -18,7 +18,7 @@ fuel-core-client = { version = "0.40.0", default-features = false } fuel-vm = { version = "0.58", features = ["random"] } # Dependencies from the `fuels-rs` repository: -fuels = { version = "0.66.9", features = ["fuel-core-lib"] } +fuels = { version = "0.66.10", features = ["fuel-core-lib"] } hex = "0.4" paste = "1.0" From ae9f17200502dd8552b27ba55de3929e3a6a20ff Mon Sep 17 00:00:00 2001 From: Daniel Frederico Lins Leite Date: Tue, 12 Nov 2024 07:48:14 -0300 Subject: [PATCH 08/52] Send method arguments with numerics to the second pass (#6700) ## Description This PR brings back encode/decode buffer ownership tests and closes https://github.com/FuelLabs/sway/issues/6567. The original issue was that an error in the CI file was hiding that these tests were not compiling anymore. IR generation now also tests the expression and the variant type match, giving a better error than before. ## Checklist - [x] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] 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. --- sway-core/src/ir_generation/function.rs | 17 ++++++- .../typed_expression/method_application.rs | 12 ++++- sway-lib-std/src/bytes.sw | 47 +++++++++---------- sway-lib-std/src/vec.sw | 47 +++++++++---------- 4 files changed, 73 insertions(+), 50 deletions(-) diff --git a/sway-core/src/ir_generation/function.rs b/sway-core/src/ir_generation/function.rs index c97ad7a94ff..54fd1d31f75 100644 --- a/sway-core/src/ir_generation/function.rs +++ b/sway-core/src/ir_generation/function.rs @@ -3975,8 +3975,9 @@ impl<'eng> FnCompiler<'eng> { if field_tys.len() != 1 && contents.is_some() { // Insert the value too. // Only store if the value does not diverge. + let contents_expr = contents.unwrap(); let contents_value = return_on_termination_or_extract!( - self.compile_expression_to_value(context, md_mgr, contents.unwrap())? + self.compile_expression_to_value(context, md_mgr, contents_expr)? ); let contents_type = contents_value.get_type(context).ok_or_else(|| { CompileError::Internal( @@ -3984,6 +3985,20 @@ impl<'eng> FnCompiler<'eng> { enum_decl.span.clone(), ) })?; + + let variant_type = field_tys[1].get_field_type(context, tag as u64).unwrap(); + if contents_type != variant_type { + return Err(CompileError::Internal( + format!( + "Expression type \"{}\" and Variant type \"{}\" do not match", + contents_type.as_string(context), + variant_type.as_string(context) + ) + .leak(), + contents_expr.span.clone(), + )); + } + let gep_val = self .current_block .append(context) diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs index d7d724caea1..6a836f56f3c 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs @@ -52,7 +52,17 @@ pub(crate) fn type_check_method_application( let arg_handler = Handler::default(); let arg_opt = ty::TyExpression::type_check(&arg_handler, ctx, arg).ok(); - let needs_second_pass = arg_handler.has_errors(); + let has_errors = arg_handler.has_errors(); + let has_numerics = arg_opt + .as_ref() + .map(|x| { + x.return_type + .extract_inner_types(engines, IncludeSelf::Yes) + .iter() + .any(|x| matches!(&*engines.te().get(*x), TypeInfo::Numeric)) + }) + .unwrap_or_default(); + let needs_second_pass = has_errors || has_numerics; if index == 0 { // We want to emit errors in the self parameter and ignore TraitConstraintNotSatisfied with Placeholder diff --git a/sway-lib-std/src/bytes.sw b/sway-lib-std/src/bytes.sw index 1296e940826..b1fd11327ad 100644 --- a/sway-lib-std/src/bytes.sw +++ b/sway-lib-std/src/bytes.sw @@ -927,27 +927,26 @@ impl AbiDecode for Bytes { } } -// TODO: Uncomment when fixed. https://github.com/FuelLabs/sway/issues/6567 -// #[test] -// fn ok_bytes_buffer_ownership() { -// let mut original_array = [1u8, 2u8, 3u8, 4u8]; -// let slice = raw_slice::from_parts::(__addr_of(original_array), 4); - -// // Check Bytes duplicates the original slice -// let mut bytes = Bytes::from(slice); -// bytes.set(0, 5); -// assert(original_array[0] == 1); - -// // At this point, slice equals [5, 2, 3, 4] -// let encoded_slice = encode(bytes); - -// // `Bytes` should duplicate the underlying buffer, -// // so when we write to it, it should not change -// // `encoded_slice` -// let mut bytes = abi_decode::(encoded_slice); -// bytes.set(0, 6); -// assert(bytes.get(0) == Some(6)); - -// let mut bytes = abi_decode::(encoded_slice); -// assert(bytes.get(0) == Some(5)); -// } +#[test] +fn ok_bytes_buffer_ownership() { + let mut original_array = [1u8, 2u8, 3u8, 4u8]; + let slice = raw_slice::from_parts::(__addr_of(original_array), 4); + + // Check Bytes duplicates the original slice + let mut bytes = Bytes::from(slice); + bytes.set(0, 5); + assert(original_array[0] == 1); + + // At this point, slice equals [5, 2, 3, 4] + let encoded_slice = encode(bytes); + + // `Bytes` should duplicate the underlying buffer, + // so when we write to it, it should not change + // `encoded_slice` + let mut bytes = abi_decode::(encoded_slice); + bytes.set(0, 6); + assert(bytes.get(0) == Some(6)); + + let mut bytes = abi_decode::(encoded_slice); + assert(bytes.get(0) == Some(5)); +} diff --git a/sway-lib-std/src/vec.sw b/sway-lib-std/src/vec.sw index 8ae7fe65da7..5b7830b848c 100644 --- a/sway-lib-std/src/vec.sw +++ b/sway-lib-std/src/vec.sw @@ -705,27 +705,26 @@ impl Iterator for VecIter { } } -// TODO: Uncomment when fixed. https://github.com/FuelLabs/sway/issues/6567 -// #[test] -// fn ok_vec_buffer_ownership() { -// let mut original_array = [1u8, 2u8, 3u8, 4u8]; -// let slice = raw_slice::from_parts::(__addr_of(original_array), 4); - -// // Check Vec duplicates the original slice -// let mut bytes = Vec::::from(slice); -// bytes.set(0, 5); -// assert(original_array[0] == 1); - -// // At this point, slice equals [5, 2, 3, 4] -// let encoded_slice = encode(bytes); - -// // `Vec` should duplicate the underlying buffer, -// // so when we write to it, it should not change -// // `encoded_slice` -// let mut bytes = abi_decode::>(encoded_slice); -// bytes.set(0, 6); -// assert(bytes.get(0) == Some(6)); - -// let mut bytes = abi_decode::>(encoded_slice); -// assert(bytes.get(0) == Some(5)); -// } +#[test] +fn ok_vec_buffer_ownership() { + let mut original_array = [1u8, 2u8, 3u8, 4u8]; + let slice = raw_slice::from_parts::(__addr_of(original_array), 4); + + // Check Vec duplicates the original slice + let mut bytes = Vec::::from(slice); + bytes.set(0, 5); + assert(original_array[0] == 1); + + // At this point, slice equals [5, 2, 3, 4] + let encoded_slice = encode(bytes); + + // `Vec` should duplicate the underlying buffer, + // so when we write to it, it should not change + // `encoded_slice` + let mut bytes = abi_decode::>(encoded_slice); + bytes.set(0, 6); + assert(bytes.get(0) == Some(6)); + + let mut bytes = abi_decode::>(encoded_slice); + assert(bytes.get(0) == Some(5)); +} From d0deb79a59bd808bf1fbea7f2e4ea1a72cfd2f2f Mon Sep 17 00:00:00 2001 From: IGI-111 Date: Wed, 13 Nov 2024 12:05:45 +0700 Subject: [PATCH 09/52] Add verifications-complete job (#6716) ## Description Add a single job that depends on all the CI checks so we can make a single job required. ## Checklist - [ ] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] 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). - [ ] I have requested a review from the relevant team or maintainers. --- .github/workflows/ci.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6b251402bc..35bbf0a657a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,42 @@ env: NIGHTLY_RUST_VERSION: nightly-2024-10-21 jobs: + verifications-complete: + needs: + - build-sway-lib-core + - build-sway-lib-std + - build-sway-examples + - build-reference-examples + - forc-fmt-check-sway-lib-core + - forc-fmt-check-sway-lib-std + - forc-fmt-check-sway-examples + - forc-fmt-check-panic + - check-sdk-harness-test-suite-compatibility + - build-mdbook + - build-forc-doc-sway-lib-std + - build-forc-test-project + - cargo-build-workspace + - cargo-clippy + - cargo-toml-fmt-check + - cargo-fmt-check + - cargo-run-e2e-test-evm + - cargo-test-lib-std + - forc-run-benchmarks + - forc-unit-tests + - forc-pkg-fuels-deps-check + - cargo-test-sway-lsp + - cargo-test-forc + - cargo-test-workspace + - cargo-unused-deps-check + - pre-publish-check + - cargo-run-e2e-test + - cargo-run-e2e-test-release + - cargo-test-forc-debug + - cargo-test-forc-client + - notify-slack-on-failure + runs-on: ubuntu-latest + steps: + - run: echo "pass" get-fuel-core-version: runs-on: buildjet-4vcpu-ubuntu-2204 outputs: From f39a49404b91f0bc163f593e65c9415e29b4830c Mon Sep 17 00:00:00 2001 From: Sophie Dankel <47993817+sdankel@users.noreply.github.com> Date: Wed, 13 Nov 2024 00:26:52 -0800 Subject: [PATCH 10/52] Add modules to forc-doc search index (#6711) ## Description Closes https://github.com/FuelLabs/sway/issues/6710 Modules such as `math` in the std library now show up in search results. image ## Checklist - [ ] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] 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). - [ ] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: Joshua Batty --- forc-plugins/forc-doc/src/render/search.rs | 4 +- forc-plugins/forc-doc/src/search.rs | 47 +++++++++++++++++-- .../forc-doc/src/static.files/swaydoc.css | 1 + .../src/tests/expects/impl_trait/mod.rs | 8 ++-- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/forc-plugins/forc-doc/src/render/search.rs b/forc-plugins/forc-doc/src/render/search.rs index 9213c17210d..584256189e6 100644 --- a/forc-plugins/forc-doc/src/render/search.rs +++ b/forc-plugins/forc-doc/src/render/search.rs @@ -47,7 +47,9 @@ pub(crate) fn generate_searchbar(module_info: &ModuleInfo) -> Box if (results.length > 0) {{ const resultList = results.map(item => {{ const formattedName = `${{item.name}}`; - const name = [...item.module_info, formattedName].join("::"); + const name = item.type_name === "module" + ? [...item.module_info.slice(0, -1), formattedName].join("::") + : [...item.module_info, formattedName].join("::"); const path = ["{}", ...item.module_info, item.html_filename].join("/"); const left = `${{name}}`; const right = `

${{item.preview}}

`; diff --git a/forc-plugins/forc-doc/src/search.rs b/forc-plugins/forc-doc/src/search.rs index 2506292a21e..2073fc750a6 100644 --- a/forc-plugins/forc-doc/src/search.rs +++ b/forc-plugins/forc-doc/src/search.rs @@ -1,13 +1,17 @@ -use crate::doc::{Document, Documentation}; +use crate::doc::{module::ModuleInfo, Document, Documentation}; use anyhow::Result; use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, fs, path::Path}; +use std::{ + collections::{BTreeMap, HashMap}, + fs, + path::Path, +}; const JS_SEARCH_FILE_NAME: &str = "search.js"; /// Creates the search index javascript file for the search bar. pub fn write_search_index(doc_path: &Path, docs: &Documentation) -> Result<()> { - let json_data = docs.to_json_value()?; + let json_data = docs.to_search_index_json_value()?; let module_export = "\"object\"==typeof exports&&\"undefined\"!=typeof module&&(module.exports=SEARCH_INDEX);"; let js_data = format!("var SEARCH_INDEX={json_data};\n{module_export}"); @@ -17,14 +21,28 @@ pub fn write_search_index(doc_path: &Path, docs: &Documentation) -> Result<()> { impl Documentation { /// Generates a mapping of program name to a vector of documentable items within the program /// and returns the map as a `serde_json::Value`. - fn to_json_value(&self) -> Result { + fn to_search_index_json_value(&self) -> Result { let mut map = HashMap::with_capacity(self.len()); + let mut modules = BTreeMap::new(); for doc in self.iter() { let project_name = doc.module_info.project_name().to_string(); map.entry(project_name) .or_insert_with(Vec::new) .push(JsonSearchItem::from(doc)); + modules.insert( + doc.module_info.module_prefixes.join("::"), + doc.module_info.clone(), + ); } + + // Insert the modules themselves into the map. + for (_, module) in modules.iter() { + let project_name = module.project_name().to_string(); + map.entry(project_name) + .or_insert_with(Vec::new) + .push(JsonSearchItem::from(module)); + } + serde_json::to_value(map) } } @@ -57,3 +75,24 @@ impl<'a> From<&'a Document> for JsonSearchItem { } } } + +impl<'a> From<&'a ModuleInfo> for JsonSearchItem { + fn from(value: &'a ModuleInfo) -> Self { + Self { + name: value + .module_prefixes + .last() + .unwrap_or(&String::new()) + .to_string(), + html_filename: "index.html".into(), + module_info: value.module_prefixes.clone(), + preview: value + .preview_opt() + .unwrap_or_default() + .replace("
", "") + .replace("

", "") + .replace("

", ""), + type_name: "module".into(), + } + } +} diff --git a/forc-plugins/forc-doc/src/static.files/swaydoc.css b/forc-plugins/forc-doc/src/static.files/swaydoc.css index 9ed50926ad1..193f3e77586 100644 --- a/forc-plugins/forc-doc/src/static.files/swaydoc.css +++ b/forc-plugins/forc-doc/src/static.files/swaydoc.css @@ -952,6 +952,7 @@ table, .search-results .type.trait { color: #B78CF2; } +.search-results .type.module, .search-results .type.constant { color: #D2991D; } diff --git a/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs b/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs index 9ead7b2f1dc..d68364e7e4f 100644 --- a/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs +++ b/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs @@ -30,13 +30,13 @@ fn test_impl_traits_default() { &doc_path, project_name, &expect![[r##" - Bar in bar - Sway
pub struct Bar {}

Implementations

fn foo_bar()

Trait Implementations

fn abi_encode(self, buffer: Buffer) -> Buffer

fn abi_decode(refmut _buffer: BufferReader) -> Self

fn foo()

something more about foo();

+ Bar in bar - Sway
pub struct Bar {}

Implementations

fn foo_bar()

Trait Implementations

fn abi_encode(self, buffer: Buffer) -> Buffer

fn abi_decode(refmut _buffer: BufferReader) -> Self

fn foo()

something more about foo();

fn add(self, other: Self) -> Self

fn subtract(self, other: Self) -> Self

"##]], ); assert_search_js( &doc_path, &expect![[r#" - var SEARCH_INDEX={"core":[{"html_filename":"trait.AsRawSlice.html","module_info":["core","raw_slice"],"name":"AsRawSlice","preview":"Trait to return a type as a raw_slice.\n","type_name":"trait"},{"html_filename":"fn.from_str_array.html","module_info":["core","str"],"name":"from_str_array","preview":"","type_name":"function"},{"html_filename":"trait.Add.html","module_info":["core","ops"],"name":"Add","preview":"Trait for the addition of two values.\n","type_name":"trait"},{"html_filename":"trait.Subtract.html","module_info":["core","ops"],"name":"Subtract","preview":"Trait for the subtraction of two values.\n","type_name":"trait"},{"html_filename":"trait.Multiply.html","module_info":["core","ops"],"name":"Multiply","preview":"Trait for the multiplication of two values.\n","type_name":"trait"},{"html_filename":"trait.Divide.html","module_info":["core","ops"],"name":"Divide","preview":"Trait for the division of two values.\n","type_name":"trait"},{"html_filename":"trait.Mod.html","module_info":["core","ops"],"name":"Mod","preview":"Trait for the modulo of two values.\n","type_name":"trait"},{"html_filename":"trait.Not.html","module_info":["core","ops"],"name":"Not","preview":"Trait to invert a type.\n","type_name":"trait"},{"html_filename":"trait.Eq.html","module_info":["core","ops"],"name":"Eq","preview":"Trait to evaluate if two types are equal.\n","type_name":"trait"},{"html_filename":"trait.Ord.html","module_info":["core","ops"],"name":"Ord","preview":"Trait to evaluate if one value is greater or less than another of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseAnd.html","module_info":["core","ops"],"name":"BitwiseAnd","preview":"Trait to bitwise AND two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseOr.html","module_info":["core","ops"],"name":"BitwiseOr","preview":"Trait to bitwise OR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseXor.html","module_info":["core","ops"],"name":"BitwiseXor","preview":"Trait to bitwise XOR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.Shift.html","module_info":["core","ops"],"name":"Shift","preview":"Trait to bit shift a value.\n","type_name":"trait"},{"html_filename":"trait.TotalOrd.html","module_info":["core","ops"],"name":"TotalOrd","preview":"Trait to compare values of the same type.\n","type_name":"trait"},{"html_filename":"fn.ok_str_eq.html","module_info":["core","ops"],"name":"ok_str_eq","preview":"","type_name":"function"},{"html_filename":"struct.StorageKey.html","module_info":["core","storage"],"name":"StorageKey","preview":"Describes a location in storage.\n","type_name":"struct"},{"html_filename":"struct.Buffer.html","module_info":["core","codec"],"name":"Buffer","preview":"","type_name":"struct"},{"html_filename":"struct.BufferReader.html","module_info":["core","codec"],"name":"BufferReader","preview":"","type_name":"struct"},{"html_filename":"trait.AbiDecode.html","module_info":["core","codec"],"name":"AbiDecode","preview":"","type_name":"trait"},{"html_filename":"trait.AbiEncode.html","module_info":["core","codec"],"name":"AbiEncode","preview":"","type_name":"trait"},{"html_filename":"fn.encode.html","module_info":["core","codec"],"name":"encode","preview":"","type_name":"function"},{"html_filename":"fn.abi_decode.html","module_info":["core","codec"],"name":"abi_decode","preview":"","type_name":"function"},{"html_filename":"fn.abi_decode_in_place.html","module_info":["core","codec"],"name":"abi_decode_in_place","preview":"","type_name":"function"},{"html_filename":"fn.contract_call.html","module_info":["core","codec"],"name":"contract_call","preview":"","type_name":"function"},{"html_filename":"fn.decode_script_data.html","module_info":["core","codec"],"name":"decode_script_data","preview":"","type_name":"function"},{"html_filename":"fn.decode_predicate_data.html","module_info":["core","codec"],"name":"decode_predicate_data","preview":"","type_name":"function"},{"html_filename":"fn.decode_predicate_data_by_index.html","module_info":["core","codec"],"name":"decode_predicate_data_by_index","preview":"","type_name":"function"},{"html_filename":"fn.decode_first_param.html","module_info":["core","codec"],"name":"decode_first_param","preview":"","type_name":"function"},{"html_filename":"fn.decode_second_param.html","module_info":["core","codec"],"name":"decode_second_param","preview":"","type_name":"function"},{"html_filename":"primitive.u256.html","module_info":["core"],"name":"u256","preview":"256-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u64.html","module_info":["core"],"name":"u64","preview":"64-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u32.html","module_info":["core"],"name":"u32","preview":"32-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u16.html","module_info":["core"],"name":"u16","preview":"16-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u8.html","module_info":["core"],"name":"u8","preview":"8-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.b256.html","module_info":["core"],"name":"b256","preview":"256 bits (32 bytes), i.e. a hash","type_name":"primitive"},{"html_filename":"primitive.str.html","module_info":["core"],"name":"str","preview":"string slice","type_name":"primitive"},{"html_filename":"primitive.bool.html","module_info":["core"],"name":"bool","preview":"Boolean true or false","type_name":"primitive"},{"html_filename":"primitive.str[0].html","module_info":["core"],"name":"str[0]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[1].html","module_info":["core"],"name":"str[1]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[2].html","module_info":["core"],"name":"str[2]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[3].html","module_info":["core"],"name":"str[3]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[4].html","module_info":["core"],"name":"str[4]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[5].html","module_info":["core"],"name":"str[5]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[6].html","module_info":["core"],"name":"str[6]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[7].html","module_info":["core"],"name":"str[7]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[8].html","module_info":["core"],"name":"str[8]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[9].html","module_info":["core"],"name":"str[9]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[10].html","module_info":["core"],"name":"str[10]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[11].html","module_info":["core"],"name":"str[11]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[12].html","module_info":["core"],"name":"str[12]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[13].html","module_info":["core"],"name":"str[13]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[14].html","module_info":["core"],"name":"str[14]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[15].html","module_info":["core"],"name":"str[15]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[16].html","module_info":["core"],"name":"str[16]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[17].html","module_info":["core"],"name":"str[17]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[18].html","module_info":["core"],"name":"str[18]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[19].html","module_info":["core"],"name":"str[19]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[20].html","module_info":["core"],"name":"str[20]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[21].html","module_info":["core"],"name":"str[21]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[22].html","module_info":["core"],"name":"str[22]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[23].html","module_info":["core"],"name":"str[23]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[24].html","module_info":["core"],"name":"str[24]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[25].html","module_info":["core"],"name":"str[25]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[26].html","module_info":["core"],"name":"str[26]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[27].html","module_info":["core"],"name":"str[27]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[28].html","module_info":["core"],"name":"str[28]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[29].html","module_info":["core"],"name":"str[29]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[30].html","module_info":["core"],"name":"str[30]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[31].html","module_info":["core"],"name":"str[31]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[32].html","module_info":["core"],"name":"str[32]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[33].html","module_info":["core"],"name":"str[33]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[34].html","module_info":["core"],"name":"str[34]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[35].html","module_info":["core"],"name":"str[35]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[36].html","module_info":["core"],"name":"str[36]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[37].html","module_info":["core"],"name":"str[37]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[38].html","module_info":["core"],"name":"str[38]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[39].html","module_info":["core"],"name":"str[39]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[40].html","module_info":["core"],"name":"str[40]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[41].html","module_info":["core"],"name":"str[41]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[42].html","module_info":["core"],"name":"str[42]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[43].html","module_info":["core"],"name":"str[43]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[44].html","module_info":["core"],"name":"str[44]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[45].html","module_info":["core"],"name":"str[45]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[46].html","module_info":["core"],"name":"str[46]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[47].html","module_info":["core"],"name":"str[47]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[48].html","module_info":["core"],"name":"str[48]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[49].html","module_info":["core"],"name":"str[49]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[50].html","module_info":["core"],"name":"str[50]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[51].html","module_info":["core"],"name":"str[51]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[52].html","module_info":["core"],"name":"str[52]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[53].html","module_info":["core"],"name":"str[53]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[54].html","module_info":["core"],"name":"str[54]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[55].html","module_info":["core"],"name":"str[55]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[56].html","module_info":["core"],"name":"str[56]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[57].html","module_info":["core"],"name":"str[57]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[58].html","module_info":["core"],"name":"str[58]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[59].html","module_info":["core"],"name":"str[59]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[60].html","module_info":["core"],"name":"str[60]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[61].html","module_info":["core"],"name":"str[61]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[62].html","module_info":["core"],"name":"str[62]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[63].html","module_info":["core"],"name":"str[63]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[64].html","module_info":["core"],"name":"str[64]","preview":"fixed-length string","type_name":"primitive"}],"impl_traits":[{"html_filename":"trait.Foo.html","module_info":["impl_traits","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits","bar"],"name":"Bar","preview":"","type_name":"struct"}]}; + var SEARCH_INDEX={"core":[{"html_filename":"trait.AsRawSlice.html","module_info":["core","raw_slice"],"name":"AsRawSlice","preview":"Trait to return a type as a raw_slice.\n","type_name":"trait"},{"html_filename":"fn.from_str_array.html","module_info":["core","str"],"name":"from_str_array","preview":"","type_name":"function"},{"html_filename":"trait.Add.html","module_info":["core","ops"],"name":"Add","preview":"Trait for the addition of two values.\n","type_name":"trait"},{"html_filename":"trait.Subtract.html","module_info":["core","ops"],"name":"Subtract","preview":"Trait for the subtraction of two values.\n","type_name":"trait"},{"html_filename":"trait.Multiply.html","module_info":["core","ops"],"name":"Multiply","preview":"Trait for the multiplication of two values.\n","type_name":"trait"},{"html_filename":"trait.Divide.html","module_info":["core","ops"],"name":"Divide","preview":"Trait for the division of two values.\n","type_name":"trait"},{"html_filename":"trait.Mod.html","module_info":["core","ops"],"name":"Mod","preview":"Trait for the modulo of two values.\n","type_name":"trait"},{"html_filename":"trait.Not.html","module_info":["core","ops"],"name":"Not","preview":"Trait to invert a type.\n","type_name":"trait"},{"html_filename":"trait.Eq.html","module_info":["core","ops"],"name":"Eq","preview":"Trait to evaluate if two types are equal.\n","type_name":"trait"},{"html_filename":"trait.Ord.html","module_info":["core","ops"],"name":"Ord","preview":"Trait to evaluate if one value is greater or less than another of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseAnd.html","module_info":["core","ops"],"name":"BitwiseAnd","preview":"Trait to bitwise AND two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseOr.html","module_info":["core","ops"],"name":"BitwiseOr","preview":"Trait to bitwise OR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseXor.html","module_info":["core","ops"],"name":"BitwiseXor","preview":"Trait to bitwise XOR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.Shift.html","module_info":["core","ops"],"name":"Shift","preview":"Trait to bit shift a value.\n","type_name":"trait"},{"html_filename":"trait.TotalOrd.html","module_info":["core","ops"],"name":"TotalOrd","preview":"Trait to compare values of the same type.\n","type_name":"trait"},{"html_filename":"fn.ok_str_eq.html","module_info":["core","ops"],"name":"ok_str_eq","preview":"","type_name":"function"},{"html_filename":"struct.StorageKey.html","module_info":["core","storage"],"name":"StorageKey","preview":"Describes a location in storage.\n","type_name":"struct"},{"html_filename":"struct.Buffer.html","module_info":["core","codec"],"name":"Buffer","preview":"","type_name":"struct"},{"html_filename":"struct.BufferReader.html","module_info":["core","codec"],"name":"BufferReader","preview":"","type_name":"struct"},{"html_filename":"trait.AbiDecode.html","module_info":["core","codec"],"name":"AbiDecode","preview":"","type_name":"trait"},{"html_filename":"trait.AbiEncode.html","module_info":["core","codec"],"name":"AbiEncode","preview":"","type_name":"trait"},{"html_filename":"fn.encode.html","module_info":["core","codec"],"name":"encode","preview":"","type_name":"function"},{"html_filename":"fn.abi_decode.html","module_info":["core","codec"],"name":"abi_decode","preview":"","type_name":"function"},{"html_filename":"fn.abi_decode_in_place.html","module_info":["core","codec"],"name":"abi_decode_in_place","preview":"","type_name":"function"},{"html_filename":"fn.contract_call.html","module_info":["core","codec"],"name":"contract_call","preview":"","type_name":"function"},{"html_filename":"fn.decode_script_data.html","module_info":["core","codec"],"name":"decode_script_data","preview":"","type_name":"function"},{"html_filename":"fn.decode_predicate_data.html","module_info":["core","codec"],"name":"decode_predicate_data","preview":"","type_name":"function"},{"html_filename":"fn.decode_predicate_data_by_index.html","module_info":["core","codec"],"name":"decode_predicate_data_by_index","preview":"","type_name":"function"},{"html_filename":"fn.decode_first_param.html","module_info":["core","codec"],"name":"decode_first_param","preview":"","type_name":"function"},{"html_filename":"fn.decode_second_param.html","module_info":["core","codec"],"name":"decode_second_param","preview":"","type_name":"function"},{"html_filename":"primitive.u256.html","module_info":["core"],"name":"u256","preview":"256-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u64.html","module_info":["core"],"name":"u64","preview":"64-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u32.html","module_info":["core"],"name":"u32","preview":"32-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u16.html","module_info":["core"],"name":"u16","preview":"16-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u8.html","module_info":["core"],"name":"u8","preview":"8-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.b256.html","module_info":["core"],"name":"b256","preview":"256 bits (32 bytes), i.e. a hash","type_name":"primitive"},{"html_filename":"primitive.str.html","module_info":["core"],"name":"str","preview":"string slice","type_name":"primitive"},{"html_filename":"primitive.bool.html","module_info":["core"],"name":"bool","preview":"Boolean true or false","type_name":"primitive"},{"html_filename":"primitive.str[0].html","module_info":["core"],"name":"str[0]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[1].html","module_info":["core"],"name":"str[1]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[2].html","module_info":["core"],"name":"str[2]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[3].html","module_info":["core"],"name":"str[3]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[4].html","module_info":["core"],"name":"str[4]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[5].html","module_info":["core"],"name":"str[5]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[6].html","module_info":["core"],"name":"str[6]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[7].html","module_info":["core"],"name":"str[7]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[8].html","module_info":["core"],"name":"str[8]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[9].html","module_info":["core"],"name":"str[9]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[10].html","module_info":["core"],"name":"str[10]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[11].html","module_info":["core"],"name":"str[11]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[12].html","module_info":["core"],"name":"str[12]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[13].html","module_info":["core"],"name":"str[13]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[14].html","module_info":["core"],"name":"str[14]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[15].html","module_info":["core"],"name":"str[15]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[16].html","module_info":["core"],"name":"str[16]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[17].html","module_info":["core"],"name":"str[17]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[18].html","module_info":["core"],"name":"str[18]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[19].html","module_info":["core"],"name":"str[19]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[20].html","module_info":["core"],"name":"str[20]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[21].html","module_info":["core"],"name":"str[21]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[22].html","module_info":["core"],"name":"str[22]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[23].html","module_info":["core"],"name":"str[23]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[24].html","module_info":["core"],"name":"str[24]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[25].html","module_info":["core"],"name":"str[25]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[26].html","module_info":["core"],"name":"str[26]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[27].html","module_info":["core"],"name":"str[27]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[28].html","module_info":["core"],"name":"str[28]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[29].html","module_info":["core"],"name":"str[29]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[30].html","module_info":["core"],"name":"str[30]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[31].html","module_info":["core"],"name":"str[31]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[32].html","module_info":["core"],"name":"str[32]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[33].html","module_info":["core"],"name":"str[33]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[34].html","module_info":["core"],"name":"str[34]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[35].html","module_info":["core"],"name":"str[35]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[36].html","module_info":["core"],"name":"str[36]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[37].html","module_info":["core"],"name":"str[37]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[38].html","module_info":["core"],"name":"str[38]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[39].html","module_info":["core"],"name":"str[39]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[40].html","module_info":["core"],"name":"str[40]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[41].html","module_info":["core"],"name":"str[41]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[42].html","module_info":["core"],"name":"str[42]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[43].html","module_info":["core"],"name":"str[43]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[44].html","module_info":["core"],"name":"str[44]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[45].html","module_info":["core"],"name":"str[45]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[46].html","module_info":["core"],"name":"str[46]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[47].html","module_info":["core"],"name":"str[47]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[48].html","module_info":["core"],"name":"str[48]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[49].html","module_info":["core"],"name":"str[49]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[50].html","module_info":["core"],"name":"str[50]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[51].html","module_info":["core"],"name":"str[51]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[52].html","module_info":["core"],"name":"str[52]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[53].html","module_info":["core"],"name":"str[53]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[54].html","module_info":["core"],"name":"str[54]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[55].html","module_info":["core"],"name":"str[55]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[56].html","module_info":["core"],"name":"str[56]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[57].html","module_info":["core"],"name":"str[57]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[58].html","module_info":["core"],"name":"str[58]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[59].html","module_info":["core"],"name":"str[59]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[60].html","module_info":["core"],"name":"str[60]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[61].html","module_info":["core"],"name":"str[61]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[62].html","module_info":["core"],"name":"str[62]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[63].html","module_info":["core"],"name":"str[63]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[64].html","module_info":["core"],"name":"str[64]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"index.html","module_info":["core"],"name":"core","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","codec"],"name":"codec","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","ops"],"name":"ops","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","raw_slice"],"name":"raw_slice","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","storage"],"name":"storage","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","str"],"name":"str","preview":"","type_name":"module"}],"impl_traits":[{"html_filename":"trait.Foo.html","module_info":["impl_traits","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits","bar"],"name":"Bar","preview":"","type_name":"struct"},{"html_filename":"index.html","module_info":["impl_traits","bar"],"name":"bar","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["impl_traits","foo"],"name":"foo","preview":"","type_name":"module"}]}; "object"==typeof exports&&"undefined"!=typeof module&&(module.exports=SEARCH_INDEX);"#]], ); assert_file_tree( @@ -180,13 +180,13 @@ fn test_impl_traits_no_deps() { &doc_path, project_name, &expect![[r##" - Bar in bar - Sway
pub struct Bar {}

Implementations

fn foo_bar()

Trait Implementations

fn abi_encode(self, buffer: Buffer) -> Buffer

fn abi_decode(refmut _buffer: BufferReader) -> Self

fn foo()

something more about foo();

+ Bar in bar - Sway
pub struct Bar {}

Implementations

fn foo_bar()

Trait Implementations

fn abi_encode(self, buffer: Buffer) -> Buffer

fn abi_decode(refmut _buffer: BufferReader) -> Self

fn foo()

something more about foo();

fn add(self, other: Self) -> Self

fn subtract(self, other: Self) -> Self

"##]], ); assert_search_js( &doc_path, &expect![[ - r#"var SEARCH_INDEX={"impl_traits_clone":[{"html_filename":"trait.Foo.html","module_info":["impl_traits_clone","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits_clone","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits_clone","bar"],"name":"Bar","preview":"","type_name":"struct"}]}; + r#"var SEARCH_INDEX={"impl_traits_clone":[{"html_filename":"trait.Foo.html","module_info":["impl_traits_clone","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits_clone","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits_clone","bar"],"name":"Bar","preview":"","type_name":"struct"},{"html_filename":"index.html","module_info":["impl_traits_clone","bar"],"name":"bar","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["impl_traits_clone","foo"],"name":"foo","preview":"","type_name":"module"}]}; "object"==typeof exports&&"undefined"!=typeof module&&(module.exports=SEARCH_INDEX);"# ]], ); From 861ca10a06c0572cbd3b11cf342fc9dd9df8118a Mon Sep 17 00:00:00 2001 From: Daniel Frederico Lins Leite Date: Wed, 13 Nov 2024 16:35:46 -0300 Subject: [PATCH 11/52] Test encoding raw slices does not allows buffer overflows (#6699) ## Description Test for https://github.com/FuelLabs/sway/pull/6686 buffer overflow on `Bytes` encoding. This test fails without the fix and pass with it. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] 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. --------- Co-authored-by: Joshua Batty Co-authored-by: Sophie Dankel <47993817+sdankel@users.noreply.github.com> --- sway-lib-std/src/bytes.sw | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/sway-lib-std/src/bytes.sw b/sway-lib-std/src/bytes.sw index b1fd11327ad..c02b097811f 100644 --- a/sway-lib-std/src/bytes.sw +++ b/sway-lib-std/src/bytes.sw @@ -950,3 +950,33 @@ fn ok_bytes_buffer_ownership() { let mut bytes = abi_decode::(encoded_slice); assert(bytes.get(0) == Some(5)); } + +#[test] +fn ok_bytes_bigger_than_3064() { + let mut v: Bytes = Bytes::new(); + + // We allocate 1024 bytes initially, this is throw away because + // it is not big enough for the buffer. + // Then we used to double the buffer to 2048. + // Then we write an `u64` with the length of the buffer. + // Then we write the buffer itself. + // (1024 + 2048) - 8 = 3064 + // Thus, we need a buffer with 3065 bytes to write into the red zone + let mut a = 3065; + while a > 0 { + v.push(1u8); + a -= 1; + } + + // This red zone should not be overwritten + let red_zone = asm(size: 1024) { + aloc size; + hp: raw_ptr + }; + red_zone.write(0xFFFFFFFFFFFFFFFF); + assert(red_zone.read::() == 0xFFFFFFFFFFFFFFFF); + + let _ = encode(v); + + assert(red_zone.read::() == 0xFFFFFFFFFFFFFFFF); +} From f7fa086f5a7a720fe41f5e5314b3e5ada3c3cb4d Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Thu, 14 Nov 2024 18:31:39 +0530 Subject: [PATCH 12/52] Add revert with log function to std lib (#6717) ## Description Adds a `revert_with_log` function that reverts unconditionally with a message Closes #6629 ## Checklist - [ ] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] 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). - [ ] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: Sophie Dankel <47993817+sdankel@users.noreply.github.com> --- sway-lib-std/src/error_signals.sw | 7 ++++ sway-lib-std/src/prelude.sw | 2 +- sway-lib-std/src/revert.sw | 34 ++++++++++++++++++- .../revert_inline_tests/src/main.sw | 5 +++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/sway-lib-std/src/error_signals.sw b/sway-lib-std/src/error_signals.sw index bbc4f6f291b..87f86699378 100644 --- a/sway-lib-std/src/error_signals.sw +++ b/sway-lib-std/src/error_signals.sw @@ -35,3 +35,10 @@ pub const FAILED_ASSERT_SIGNAL = 0xffff_ffff_ffff_0004; /// /// The value is: 18446744073709486085 pub const FAILED_ASSERT_NE_SIGNAL = 0xffff_ffff_ffff_0005; + +/// A revert with this value signals that it was caused by a call to `std::revert::revert_with_log`. +/// +/// # Additional Information +/// +/// The value is: 18446744073709486086 +pub const REVERT_WITH_LOG_SIGNAL = 0xffff_ffff_ffff_0006; diff --git a/sway-lib-std/src/prelude.sw b/sway-lib-std/src/prelude.sw index 6f207cc7b45..f8d42cf0044 100644 --- a/sway-lib-std/src/prelude.sw +++ b/sway-lib-std/src/prelude.sw @@ -21,7 +21,7 @@ pub use ::vec::{Vec, VecIter}; pub use ::assert::{assert, assert_eq, assert_ne}; pub use ::option::Option::{self, *}; pub use ::result::Result::{self, *}; -pub use ::revert::{require, revert}; +pub use ::revert::{require, revert, revert_with_log}; // Convert pub use ::convert::From; diff --git a/sway-lib-std/src/revert.sw b/sway-lib-std/src/revert.sw index ba6ddeadf88..f53dd5378d2 100644 --- a/sway-lib-std/src/revert.sw +++ b/sway-lib-std/src/revert.sw @@ -2,7 +2,7 @@ library; use ::logging::log; -use ::error_signals::FAILED_REQUIRE_SIGNAL; +use ::error_signals::{FAILED_REQUIRE_SIGNAL, REVERT_WITH_LOG_SIGNAL}; /// Will either panic or revert with a given number depending on the context. /// @@ -71,3 +71,35 @@ where revert(FAILED_REQUIRE_SIGNAL) } } + +/// Reverts unconditionally and logs `value`. +/// +/// # Arguments +/// +/// * `value`: [T] - The value which will be logged. +/// +/// # Reverts +/// +/// * Reverts unconditionally. +/// +/// # Examples +/// +/// ```sway +/// fn foo() { +/// revert_with_log("Example error message"); +/// } +/// ``` +#[cfg(experimental_new_encoding = false)] +pub fn revert_with_log(value: T) { + log(value); + revert(REVERT_WITH_LOG_SIGNAL) +} + +#[cfg(experimental_new_encoding = true)] +pub fn revert_with_log(value: T) +where + T: AbiEncode, +{ + log(value); + revert(REVERT_WITH_LOG_SIGNAL) +} diff --git a/test/src/in_language_tests/test_programs/revert_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/revert_inline_tests/src/main.sw index cff1e49fc0e..64c74e30b63 100644 --- a/test/src/in_language_tests/test_programs/revert_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/revert_inline_tests/src/main.sw @@ -14,3 +14,8 @@ fn revert_revert_require() { fn pass_revert_require() { require(true, "error"); } + +#[test(should_revert)] +fn revert_revert_with_log() { + revert_with_log("error") +} \ No newline at end of file From 9951c1da7165b18ceccb281c335129b363fa2105 Mon Sep 17 00:00:00 2001 From: Daniel Frederico Lins Leite Date: Thu, 14 Nov 2024 13:02:04 -0300 Subject: [PATCH 13/52] Transmute intrinsics (#6692) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This PR implements the `__transmute` intrinsic. As Rust this intrinsic should be a no-op semantically equal to a pointer cast. Although this PR does not aim that it is 100% no-op yet. At the moment some trade-offs were taken: 1 - References, pointers etc... are not allowed at the moment; 2 - `u16` and `u32` actually occupy 64bits. To allow transmute to work in complex aggregates, this PR is accepting them as `u64`. Doing otherwise would forbid `__transmute` to be no-op. Specially in complex aggregates; ## Checklist - [ ] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] 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). - [ ] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: João Matos --- sway-ast/src/intrinsics.rs | 3 + sway-core/src/ir_generation/const_eval.rs | 135 +++++++++++++++++- sway-core/src/ir_generation/function.rs | 63 +++++++- .../ast_node/expression/intrinsic_function.rs | 110 ++++++++++++++ .../semantic_analysis/cei_pattern_analysis.rs | 3 +- sway-error/src/error.rs | 3 + .../language/intrinsics/transmute/.gitignore | 2 + .../language/intrinsics/transmute/Forc.lock | 8 ++ .../language/intrinsics/transmute/Forc.toml | 8 ++ .../transmute/debug/transmute-abi.json | 28 ++++ .../transmute/debug/transmute-bin-hash | 1 + .../intrinsics/transmute/debug/transmute.bin | Bin 0 -> 1088 bytes .../intrinsics/transmute/snapshot.toml | 0 .../language/intrinsics/transmute/src/main.sw | 16 +++ .../language/intrinsics/transmute/stdout.snap | 62 ++++++++ .../language/intrinsics/transmute/.gitignore | 2 + .../language/intrinsics/transmute/Forc.lock | 8 ++ .../language/intrinsics/transmute/Forc.toml | 8 ++ .../json_abi_oracle_new_encoding.json | 28 ++++ .../language/intrinsics/transmute/src/main.sw | 121 ++++++++++++++++ .../language/intrinsics/transmute/test.toml | 4 + 21 files changed, 608 insertions(+), 5 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/.gitignore create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-abi.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-bin-hash create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute.bin create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/snapshot.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/stdout.snap create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/.gitignore create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/json_abi_oracle_new_encoding.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/test.toml diff --git a/sway-ast/src/intrinsics.rs b/sway-ast/src/intrinsics.rs index 182d47fa3d9..30dea17436d 100644 --- a/sway-ast/src/intrinsics.rs +++ b/sway-ast/src/intrinsics.rs @@ -43,6 +43,7 @@ pub enum Intrinsic { EncodeBufferAsRawSlice, // let slice: raw_slice = __encode_buffer_as_raw_slice(buffer) Slice, // let ref_to_slice = __slice::(item: T, inclusive_start_index, exclusive_end_index) ElemAt, // let elem: &T = __elem_at::(item: T, index) + Transmute, // let dst: B = __transmute::(src) } impl fmt::Display for Intrinsic { @@ -89,6 +90,7 @@ impl fmt::Display for Intrinsic { Intrinsic::EncodeBufferAsRawSlice => "encode_buffer_as_raw_slice", Intrinsic::Slice => "slice", Intrinsic::ElemAt => "elem_at", + Intrinsic::Transmute => "transmute", }; write!(f, "{s}") } @@ -139,6 +141,7 @@ impl Intrinsic { "__encode_buffer_as_raw_slice" => EncodeBufferAsRawSlice, "__slice" => Slice, "__elem_at" => ElemAt, + "__transmute" => Transmute, _ => return None, }) } diff --git a/sway-core/src/ir_generation/const_eval.rs b/sway-core/src/ir_generation/const_eval.rs index 258d63cb6d2..9a986c54656 100644 --- a/sway-core/src/ir_generation/const_eval.rs +++ b/sway-core/src/ir_generation/const_eval.rs @@ -1,4 +1,7 @@ -use std::ops::{BitAnd, BitOr, BitXor, Not, Rem}; +use std::{ + io::Read, + ops::{BitAnd, BitOr, BitXor, Not, Rem}, +}; use crate::{ engine_threading::*, @@ -1363,6 +1366,136 @@ fn const_eval_intrinsic( }), } } + Intrinsic::Transmute => { + let src_type = &intrinsic.type_arguments[0]; + let src_ir_type = convert_resolved_type_id( + lookup.engines.te(), + lookup.engines.de(), + lookup.context, + src_type.type_id, + &src_type.span, + ) + .unwrap(); + + let dst_type = &intrinsic.type_arguments[1]; + let dst_ir_type = convert_resolved_type_id( + lookup.engines.te(), + lookup.engines.de(), + lookup.context, + dst_type.type_id, + &dst_type.span, + ) + .unwrap(); + + // check IR sizes match + let src_ir_type_in_bytes = src_ir_type.size(lookup.context).in_bytes(); + let dst_ir_type_in_bytes = dst_ir_type.size(lookup.context).in_bytes(); + if src_ir_type_in_bytes != dst_ir_type_in_bytes { + return Err(ConstEvalError::CompileError); + } + + fn append_bytes( + ctx: &Context<'_>, + bytes: &mut Vec, + t: &Type, + value: &ConstantValue, + ) -> Result<(), ConstEvalError> { + match t.get_content(ctx) { + TypeContent::Array(item_type, size) => match value { + ConstantValue::Array(items) => { + assert!(*size as usize == items.len()); + for item in items { + append_bytes(ctx, bytes, item_type, &item.value)?; + } + } + _ => unreachable!(), + }, + TypeContent::Uint(8) => match value { + ConstantValue::Uint(v) => { + bytes.extend((*v as u8).to_be_bytes()); + } + _ => unreachable!(), + }, + TypeContent::Uint(16) => match value { + ConstantValue::Uint(v) => { + bytes.extend([0u8, 0u8, 0u8, 0u8, 0u8, 0u8]); + bytes.extend((*v as u16).to_be_bytes()); + } + _ => unreachable!(), + }, + TypeContent::Uint(32) => match value { + ConstantValue::Uint(v) => { + bytes.extend([0u8, 0u8, 0u8, 0u8]); + bytes.extend((*v as u32).to_be_bytes()); + } + _ => unreachable!(), + }, + TypeContent::Uint(64) => match value { + ConstantValue::Uint(v) => { + bytes.extend((*v).to_be_bytes()); + } + _ => unreachable!(), + }, + _ => return Err(ConstEvalError::CompileError), + } + Ok(()) + } + + fn transmute_bytes( + ctx: &Context<'_>, + bytes: &mut std::io::Cursor>, + t: &Type, + ) -> Result { + Ok(match t.get_content(ctx) { + TypeContent::Uint(8) => { + let mut buffer = [0u8]; + let _ = bytes.read_exact(&mut buffer); + Constant { + ty: Type::get_uint8(ctx), + value: ConstantValue::Uint(buffer[0] as u64), + } + } + TypeContent::Uint(16) => { + let mut buffer = [0u8; 8]; // u16 = u64 at runtime + let _ = bytes.read_exact(&mut buffer); + let buffer = [buffer[6], buffer[7]]; + Constant { + ty: Type::get_uint16(ctx), + value: ConstantValue::Uint(u16::from_be_bytes(buffer) as u64), + } + } + TypeContent::Uint(32) => { + let mut buffer = [0u8; 8]; // u32 = u64 at runtime + let _ = bytes.read_exact(&mut buffer); + let buffer = [buffer[4], buffer[5], buffer[6], buffer[7]]; + Constant { + ty: Type::get_uint32(ctx), + value: ConstantValue::Uint(u32::from_be_bytes(buffer) as u64), + } + } + TypeContent::Uint(64) => { + let mut buffer = [0u8; 8]; + let _ = bytes.read_exact(&mut buffer); + Constant { + ty: Type::get_uint64(ctx), + value: ConstantValue::Uint(u64::from_be_bytes(buffer)), + } + } + _ => return Err(ConstEvalError::CompileError), + }) + } + + let mut runtime_bytes = vec![]; + append_bytes( + lookup.context, + &mut runtime_bytes, + &src_ir_type, + &args[0].value, + )?; + let mut cursor = std::io::Cursor::new(runtime_bytes); + let c = transmute_bytes(lookup.context, &mut cursor, &dst_ir_type)?; + Ok(Some(c)) + } } } diff --git a/sway-core/src/ir_generation/function.rs b/sway-core/src/ir_generation/function.rs index 54fd1d31f75..f3a7064568e 100644 --- a/sway-core/src/ir_generation/function.rs +++ b/sway-core/src/ir_generation/function.rs @@ -660,9 +660,13 @@ impl<'eng> FnCompiler<'eng> { span_md_idx, ) } - ty::TyExpressionVariant::IntrinsicFunction(kind) => { - self.compile_intrinsic_function(context, md_mgr, kind, ast_expr.span.clone()) - } + ty::TyExpressionVariant::IntrinsicFunction(kind) => self.compile_intrinsic_function( + context, + md_mgr, + kind, + ast_expr.span.clone(), + ast_expr.return_type, + ), ty::TyExpressionVariant::AbiName(_) => { let val = Value::new_constant(context, Constant::new_unit(context)); Ok(TerminatorValue::new(val, context)) @@ -869,6 +873,7 @@ impl<'eng> FnCompiler<'eng> { span: _, }: &ty::TyIntrinsicFunctionKind, span: Span, + return_type: TypeId, ) -> Result { fn store_key_in_local_mem( compiler: &mut FnCompiler, @@ -2174,9 +2179,61 @@ impl<'eng> FnCompiler<'eng> { } Intrinsic::Slice => self.compile_intrinsic_slice(arguments, context, md_mgr), Intrinsic::ElemAt => self.compile_intrinsic_elem_at(arguments, context, md_mgr), + Intrinsic::Transmute => { + self.compile_intrinsic_transmute(arguments, return_type, context, md_mgr, &span) + } } } + fn compile_intrinsic_transmute( + &mut self, + arguments: &[ty::TyExpression], + return_type: TypeId, + context: &mut Context, + md_mgr: &mut MetadataManager, + span: &Span, + ) -> Result { + assert!(arguments.len() == 1); + + let te = self.engines.te(); + let de = self.engines.de(); + + let return_type_ir_type = convert_resolved_type_id(te, de, context, return_type, span)?; + let return_type_ir_type_ptr = Type::new_ptr(context, return_type_ir_type); + + let first_argument_expr = &arguments[0]; + let first_argument_value = return_on_termination_or_extract!( + self.compile_expression_to_value(context, md_mgr, first_argument_expr)? + ); + let first_argument_type = first_argument_value + .get_type(context) + .expect("transmute first argument type not found"); + let first_argument_ptr = save_to_local_return_ptr(self, context, first_argument_value)?; + + // check IR sizes match + let first_arg_size = first_argument_type.size(context).in_bytes(); + let return_type_size = return_type_ir_type.size(context).in_bytes(); + if first_arg_size != return_type_size { + return Err(CompileError::Internal( + "Types size do not match", + span.clone(), + )); + } + + let u64 = Type::get_uint64(context); + let first_argument_ptr = self + .current_block + .append(context) + .ptr_to_int(first_argument_ptr, u64); + let first_argument_ptr = self + .current_block + .append(context) + .int_to_ptr(first_argument_ptr, return_type_ir_type_ptr); + + let final_value = self.current_block.append(context).load(first_argument_ptr); + Ok(TerminatorValue::new(final_value, context)) + } + fn ptr_to_first_element( &mut self, context: &mut Context, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs index 3ed6c9de234..421509fbc81 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs @@ -106,8 +106,118 @@ impl ty::TyIntrinsicFunctionKind { type_check_slice(handler, ctx, kind, arguments, type_arguments, span) } Intrinsic::ElemAt => type_check_elem_at(arguments, handler, kind, span, ctx), + Intrinsic::Transmute => { + type_check_transmute(arguments, handler, kind, type_arguments, span, ctx) + } + } + } +} + +fn type_check_transmute( + arguments: &[Expression], + handler: &Handler, + kind: Intrinsic, + type_arguments: &[TypeArgument], + span: Span, + mut ctx: TypeCheckContext, +) -> Result<(TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { + if arguments.len() != 1 { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { + name: kind.to_string(), + expected: 1, + span, + })); + } + + let engines = ctx.engines(); + + // Both type arguments needs to be explicitly defined + if type_arguments.len() != 2 { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumTArgs { + name: kind.to_string(), + expected: 2, + span, + })); + } + + let src_type = ctx + .resolve_type( + handler, + type_arguments[0].type_id, + &type_arguments[0].span, + EnforceTypeArguments::Yes, + None, + ) + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); + let return_type = ctx + .resolve_type( + handler, + type_arguments[1].type_id, + &type_arguments[1].span, + EnforceTypeArguments::Yes, + None, + ) + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); + + // Forbid ref and ptr types + fn forbid_ref_ptr_types( + engines: &Engines, + handler: &Handler, + t: TypeId, + span: &Span, + ) -> Result<(), ErrorEmitted> { + let types = t.extract_any_including_self( + engines, + &|t| { + matches!( + t, + TypeInfo::StringSlice + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::Ptr(_) + | TypeInfo::Slice(_) + | TypeInfo::Ref { .. } + ) + }, + vec![], + 0, + ); + if !types.is_empty() { + Err(handler.emit_err(CompileError::TypeNotAllowed { + reason: sway_error::error::TypeNotAllowedReason::NotAllowedInTransmute, + span: span.clone(), + })) + } else { + Ok(()) } } + + forbid_ref_ptr_types(engines, handler, src_type, &type_arguments[0].span)?; + forbid_ref_ptr_types(engines, handler, return_type, &type_arguments[1].span)?; + + // check first argument + let arg_type = engines.te().get(src_type); + let first_argument_typed_expr = { + let ctx = ctx + .by_ref() + .with_help_text("") + .with_type_annotation(engines.te().insert( + engines, + (*arg_type).clone(), + type_arguments[0].span.source_id(), + )); + ty::TyExpression::type_check(handler, ctx, &arguments[0]).unwrap() + }; + + Ok(( + TyIntrinsicFunctionKind { + kind, + arguments: vec![first_argument_typed_expr], + type_arguments: type_arguments.to_vec(), + span, + }, + return_type, + )) } fn type_check_elem_at( diff --git a/sway-core/src/semantic_analysis/cei_pattern_analysis.rs b/sway-core/src/semantic_analysis/cei_pattern_analysis.rs index 1dbad596ed4..1f40ad03ac7 100644 --- a/sway-core/src/semantic_analysis/cei_pattern_analysis.rs +++ b/sway-core/src/semantic_analysis/cei_pattern_analysis.rs @@ -649,7 +649,8 @@ fn effects_of_intrinsic(intr: &sway_ast::Intrinsic) -> HashSet { | EncodeBufferAppend | EncodeBufferAsRawSlice | Slice - | ElemAt => HashSet::new(), + | ElemAt + | Transmute => HashSet::new(), } } diff --git a/sway-error/src/error.rs b/sway-error/src/error.rs index 3998426f92e..fb129fa9903 100644 --- a/sway-error/src/error.rs +++ b/sway-error/src/error.rs @@ -2812,6 +2812,9 @@ pub enum TypeNotAllowedReason { #[error("slices or types containing slices on `const` are not allowed.")] SliceInConst, + + #[error("references, pointers, slices, string slices or types containing any of these are not allowed.")] + NotAllowedInTransmute, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/.gitignore b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.lock new file mode 100644 index 00000000000..f9932679777 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "core" +source = "path+from-root-E4EB5F90E61EC58F" + +[[package]] +name = "transmute" +source = "member" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.toml new file mode 100644 index 00000000000..457f84ef26a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +license = "Apache-2.0" +entry = "main.sw" +name = "transmute" + +[dependencies] +core = { path = "../../../../../../../../sway-lib-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-abi.json b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-abi.json new file mode 100644 index 00000000000..c42f6cefac2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-abi.json @@ -0,0 +1,28 @@ +{ + "programType": "script", + "specVersion": "1", + "encodingVersion": "1", + "concreteTypes": [ + { + "type": "u64", + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypes": [], + "functions": [ + { + "inputs": [], + "name": "main", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "attributes": null + } + ], + "loggedTypes": [ + { + "logId": "1515152261580153489", + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "messagesTypes": [], + "configurables": [] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-bin-hash b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-bin-hash new file mode 100644 index 00000000000..86a358e416a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-bin-hash @@ -0,0 +1 @@ +0x82d76771fa3e7e2cc3c0f9904b45673c9066384f3077cd97e20892c965a096db \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute.bin b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute.bin new file mode 100644 index 0000000000000000000000000000000000000000..4c9d69d93cbd0cdf9999c405362669932f70c5c3 GIT binary patch literal 1088 zcmd5*&2G~`82lXE#QcaZ#gU>75k8d4M@!_;<64g8ghuKLgopsw6(^37g%ILWA30JG z&|@FLmN;MS@DHdI+*>i>ujti+c6q6%H>Lj2ORwSVB|nCDM{M5rI``na@;lcB zdL0z+%6o6Df%AH}k=|%)`a|4P!G4LkI_8xwtCgP;eIQEsnL~TX#usGd!Gu&+c4k@8 z_V}}X;!oZae>9?4=(HxFMGOhLhM4zFg<)NePKd#$1~RDp`vxryl|vb10{t|UkJ8JO zrwvzT<~m&k6liT8)Z z{5D1Ywwj5ddIZN|lsi1ittK?yfi9=y!P#WSpABYsmR!Q2GgEoH(4Tf^b?JVIL#ru$ z#_*5+08dN0mJ#=nUDrGS=Qi{(+g(+&7~>k!fZ>Hi@4~_<%W|iPDE1ecVR`mGnczX6a`6ny{y literal 0 HcmV?d00001 diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/snapshot.toml b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/snapshot.toml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw new file mode 100644 index 00000000000..6873ab62973 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw @@ -0,0 +1,16 @@ +script; + +fn main() { + // Missing type arguments + let _ = __transmute(1u64); + let _ = __transmute::(1u64); + + // Wrong source type + let _ = __transmute::(1u32); + + // Different sizes + let _ = __transmute::(1u64); + + // Invalid types + let _ = __transmute::<&u64, &u8>(&1u64); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/stdout.snap b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/stdout.snap new file mode 100644 index 00000000000..70f758a10e0 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/stdout.snap @@ -0,0 +1,62 @@ +--- +source: test/tests/tests.rs +snapshot_kind: text +--- +> forc build --path test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute +exit status: 1 +output: + Building test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute + Compiling library core (sway-lib-core) + Compiling script transmute (test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute) +error + --> test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw:5:13 + | +3 | fn main() { +4 | // Missing type arguments +5 | let _ = __transmute(1u64); + | ^^^^^^^^^^^^^^^^^ Call to "transmute" expects 2 type arguments +6 | let _ = __transmute::(1u64); +7 | + | +____ + +error + --> test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw:6:13 + | +4 | // Missing type arguments +5 | let _ = __transmute(1u64); +6 | let _ = __transmute::(1u64); + | ^^^^^^^^^^^^^^^^^^^^^^^^ Call to "transmute" expects 2 type arguments +7 | +8 | // Wrong source type + | +____ + +error + --> test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw:9:36 + | + 7 | + 8 | // Wrong source type + 9 | let _ = __transmute::(1u32); + | ^^^^ Mismatched types. +expected: u64 +found: u32. + +10 | +11 | // Different sizes + | +____ + +error + --> test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw:15:27 + | +13 | +14 | // Invalid types +15 | let _ = __transmute::<&u64, &u8>(&1u64); + | ^^^^ references, pointers, slices, string slices or types containing any of these are not allowed. +16 | } + | +____ + + Aborting due to 4 errors. +error: Failed to compile transmute diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/.gitignore b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.lock new file mode 100644 index 00000000000..f9932679777 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "core" +source = "path+from-root-E4EB5F90E61EC58F" + +[[package]] +name = "transmute" +source = "member" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.toml new file mode 100644 index 00000000000..457f84ef26a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +license = "Apache-2.0" +entry = "main.sw" +name = "transmute" + +[dependencies] +core = { path = "../../../../../../../../sway-lib-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/json_abi_oracle_new_encoding.json new file mode 100644 index 00000000000..7ebeae3ddd5 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/json_abi_oracle_new_encoding.json @@ -0,0 +1,28 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "type": "u64" + } + ], + "configurables": [], + "encodingVersion": "1", + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "loggedTypes": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "logId": "1515152261580153489" + } + ], + "messagesTypes": [], + "metadataTypes": [], + "programType": "script", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/src/main.sw new file mode 100644 index 00000000000..9bad6776dcc --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/src/main.sw @@ -0,0 +1,121 @@ +script; + +fn assert(v: bool) { + if !v { + __revert(0); + } +} + +enum SomeEnum { + A: u64, + B: u64 +} + +pub struct SomeStruct { + #[allow(dead_code)] + tag: u64, + #[allow(dead_code)] + value: u64 +} + +fn const_transmute() { + // u16 needs 8 bytes as u64 + const U8ARRAY_U16 = __transmute::<[u8; 8], u16>([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8]); + assert(U8ARRAY_U16 == 0x0102u16); + + // u32 needs 8 bytes as u64 + const U8ARRAY_U32 = __transmute::<[u8; 8], u32>([0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8, 4u8]); + assert(U8ARRAY_U32 == 0x01020304u32); + + const U8ARRAY_U64 = __transmute::<[u8; 8], u64>([1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8]); + assert(U8ARRAY_U64 == 0x0102030405060708u64); + + // u32 <-> u64 + const U32_U64 = __transmute::(1u32); + assert(U32_U64 == 0x0000000000000001u64); + + const U64_U32 = __transmute::(1u64); + assert(U64_U32 == 0x00000001u32); +} + +fn main() { + const_transmute(); + + // Check transmute work as nop + let u8_u8 = __transmute::(1); + assert(u8_u8 == 1); + + let u16_u16 = __transmute::(1); + assert(u16_u16 == 1); + + let u32_u32 = __transmute::(1); + assert(u32_u32 == 1); + + let u64_u64 = __transmute::(1); + assert(u64_u64 == 1); + + // Check transmute arrays + let u8array_u8 = __transmute::<[u8; 1], u8>([1u8]); + assert(u8array_u8 == 1); + + // u16 needs 8 bytes as u64 + let u8array_u16 = __transmute::<[u8; 8], u64>([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8]); + assert(u8array_u16 == 1); + + // u32 needs 8 bytes as u64 + let u8array_u32 = __transmute::<[u8; 8], u32>([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8]); + assert(u8array_u32 == 1); + + let u8array_u64 = __transmute::<[u8; 8], u64>([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8]); + assert(u8array_u64 == 1); + + // u32 <-> u64 + let u32_u64 = __transmute::(1u32); + assert(u32_u64 == 0x0000000000000001u64); + + let u64_u32 = __transmute::(1u64); + assert(u64_u32 == 0x00000001u32); + + // check u256 and b256 are transmutable + let u256_b256 = __transmute::(u256::max()); + assert(u256_b256 == b256::max()); + + // b256 to arrays of u64 and back + let b256_u64array = __transmute::(b256::max()); + assert(b256_u64array[0] == u64::max()); + assert(b256_u64array[1] == u64::max()); + assert(b256_u64array[2] == u64::max()); + assert(b256_u64array[3] == u64::max()); + let u64array_b256 = __transmute::<[u64; 4], b256>(b256_u64array); + assert(u64array_b256 == b256::max()); + + // Check tuples + let b256_tuple_u64 = __transmute::(b256::max()); + assert(b256_tuple_u64.0 == u64::max()); + assert(b256_tuple_u64.1 == u64::max()); + assert(b256_tuple_u64.2 == u64::max()); + assert(b256_tuple_u64.3 == u64::max()); + let tuple_u64_b256 = __transmute::<(u64, u64, u64, u64), b256>(b256_tuple_u64); + assert(tuple_u64_b256 == b256::max()); + + // u16 is actually as big as a u64 + // even inside "structs" + let tuple_u8_u6_u8 = __transmute::<(u8, u16, u8), (u8, u64, u8)>((1, 2, 3)); + assert(tuple_u8_u6_u8.0 == 1); + assert(tuple_u8_u6_u8.1 == 2); + assert(tuple_u8_u6_u8.2 == 3); + + // Check struct to enum + let some_struct: SomeStruct = SomeStruct { tag: 0, value: 1 }; + let some_enum = __transmute::(some_struct); + match some_enum { + SomeEnum::A(v) => assert(v == 1), + _ => {} + }; + + // check enum to struct + let some_enum = SomeEnum::B(1); + let some_struct = __transmute::(some_enum); + assert(some_struct.tag == 1); + assert(some_struct.value == 1); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/test.toml new file mode 100644 index 00000000000..f656259dc91 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 0 } +expected_result_new_encoding = { action = "return_data", value = "" } + From 6e31144e2bb6ac414a8d99769b0bea51c8a21cef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Matos?= Date: Fri, 15 Nov 2024 00:00:23 +0000 Subject: [PATCH 14/52] Profiling support (#6705) ## Description This pull request adds the profile feature in the Sway compiler. It communicates with an external `forc-perf` executable in order to signal the beginning and end of different compilation phases for profiling purposes. (re-opening of https://github.com/FuelLabs/sway/pull/6565) ## 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). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --------- Co-authored-by: Camden Smallwood Co-authored-by: GeorgiosDelkos Co-authored-by: IGI-111 --- Cargo.lock | 1 + forc-pkg/Cargo.toml | 1 + forc-pkg/src/manifest/build_profile.rs | 5 + forc-pkg/src/pkg.rs | 95 ++++++++++++++++++- forc-plugins/forc-client/src/op/deploy.rs | 1 + forc-plugins/forc-client/src/op/run/mod.rs | 1 + forc-test/src/lib.rs | 4 + forc/Cargo.toml | 1 + forc/src/cli/commands/test.rs | 1 + forc/src/cli/shared.rs | 3 + forc/src/ops/forc_build.rs | 1 + forc/src/ops/forc_contract_id.rs | 1 + forc/src/ops/forc_predicate_root.rs | 1 + sway-core/src/asm_generation/finalized_asm.rs | 18 ++++ .../src/asm_generation/fuel/data_section.rs | 4 +- sway-core/src/asm_generation/mod.rs | 3 +- sway-core/src/build_config.rs | 6 ++ sway-core/src/lib.rs | 14 ++- sway-ir/Cargo.toml | 1 + sway-ir/src/irtype.rs | 2 +- sway-utils/src/performance.rs | 20 +++- 21 files changed, 173 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d0e9ea139dc..159d6d5f8cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7723,6 +7723,7 @@ dependencies = [ "peg", "prettydiff", "rustc-hash 1.1.0", + "serde", "slotmap", "sway-features", "sway-ir-macros", diff --git a/forc-pkg/Cargo.toml b/forc-pkg/Cargo.toml index 20dcf7436cc..6e0e6431fac 100644 --- a/forc-pkg/Cargo.toml +++ b/forc-pkg/Cargo.toml @@ -45,3 +45,4 @@ regex = "^1.10.2" [target.'cfg(not(target_os = "macos"))'.dependencies] sysinfo = "0.29" + diff --git a/forc-pkg/src/manifest/build_profile.rs b/forc-pkg/src/manifest/build_profile.rs index af5822ec693..a196cd51068 100644 --- a/forc-pkg/src/manifest/build_profile.rs +++ b/forc-pkg/src/manifest/build_profile.rs @@ -24,6 +24,8 @@ pub struct BuildProfile { #[serde(default)] pub time_phases: bool, #[serde(default)] + pub profile: bool, + #[serde(default)] pub metrics_outfile: Option, #[serde(default)] pub include_tests: bool, @@ -52,6 +54,7 @@ impl BuildProfile { print_bytecode_spans: false, terse: false, time_phases: false, + profile: false, metrics_outfile: None, include_tests: false, error_on_warnings: false, @@ -72,6 +75,7 @@ impl BuildProfile { print_bytecode_spans: false, terse: false, time_phases: false, + profile: false, metrics_outfile: None, include_tests: false, error_on_warnings: false, @@ -140,6 +144,7 @@ mod tests { print_bytecode_spans: false, terse: true, time_phases: true, + profile: false, metrics_outfile: Some("metrics_outfile".into()), include_tests: true, error_on_warnings: true, diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index 4a798f01f48..ab4733949b8 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -300,6 +300,8 @@ pub struct BuildOpts { pub release: bool, /// Output the time elapsed over each part of the compilation process. pub time_phases: bool, + /// Profile the build process. + pub profile: bool, /// If set, outputs compilation metrics info in JSON format. pub metrics_outfile: Option, /// Warnings must be treated as compiler errors. @@ -1561,6 +1563,7 @@ pub fn sway_build_config( .with_print_ir(build_profile.print_ir.clone()) .with_include_tests(build_profile.include_tests) .with_time_phases(build_profile.time_phases) + .with_profile(build_profile.profile) .with_metrics(build_profile.metrics_outfile.clone()) .with_optimization_level(build_profile.optimization_level); Ok(build_config) @@ -1780,6 +1783,7 @@ pub fn compile( // First, compile to an AST. We'll update the namespace and check for JSON ABI output. let ast_res = time_expr!( + pkg.name, "compile to ast", "compile_to_ast", sway_core::compile_to_ast( @@ -1819,6 +1823,7 @@ pub fn compile( } let asm_res = time_expr!( + pkg.name, "compile ast to asm", "compile_ast_to_asm", sway_core::ast_to_asm( @@ -1839,6 +1844,7 @@ pub fn compile( let mut program_abi = match pkg.target { BuildTarget::Fuel => { let program_abi_res = time_expr!( + pkg.name, "generate JSON ABI program", "generate_json_abi", fuel_abi::generate_program_abi( @@ -1877,6 +1883,7 @@ pub fn compile( }; let abi = time_expr!( + pkg.name, "generate JSON ABI program", "generate_json_abi", evm_abi::generate_abi_program(typed_program, engines), @@ -1899,15 +1906,22 @@ pub fn compile( .map(|finalized_entry| PkgEntry::from_finalized_entry(finalized_entry, engines)) .collect::>()?; - let asm = match asm_res { + let mut asm = match asm_res { Err(_) => return fail(handler), Ok(asm) => asm, }; let bc_res = time_expr!( + pkg.name, "compile asm to bytecode", "compile_asm_to_bytecode", - sway_core::asm_to_bytecode(&handler, asm, source_map, engines.se(), &sway_build_config), + sway_core::asm_to_bytecode( + &handler, + &mut asm, + source_map, + engines.se(), + &sway_build_config + ), Some(sway_build_config.clone()), metrics ); @@ -1957,9 +1971,84 @@ pub fn compile( warnings, metrics, }; + if sway_build_config.profile { + report_assembly_information(&asm, &compiled_package); + } + Ok(compiled_package) } +/// Reports assembly information for a compiled package to an external `dyno` process through `stdout`. +fn report_assembly_information( + compiled_asm: &sway_core::CompiledAsm, + compiled_package: &CompiledPackage, +) { + // Get the bytes of the compiled package. + let mut bytes = compiled_package.bytecode.bytes.clone(); + + // Attempt to get the data section offset out of the compiled package bytes. + let data_offset = u64::from_be_bytes( + bytes + .iter() + .skip(8) + .take(8) + .cloned() + .collect::>() + .try_into() + .unwrap(), + ); + let data_section_size = bytes.len() as u64 - data_offset; + + // Remove the data section from the compiled package bytes. + bytes.truncate(data_offset as usize); + + // Calculate the unpadded size of each data section section. + // Implementation based directly on `sway_core::asm_generation::Entry::to_bytes`, referenced here: + // https://github.com/FuelLabs/sway/blob/afd6a6709e7cb11c676059a5004012cc466e653b/sway-core/src/asm_generation/fuel/data_section.rs#L147 + fn calculate_entry_size(entry: &sway_core::asm_generation::Entry) -> u64 { + match &entry.value { + sway_core::asm_generation::Datum::Byte(value) => std::mem::size_of_val(value) as u64, + + sway_core::asm_generation::Datum::Word(value) => std::mem::size_of_val(value) as u64, + + sway_core::asm_generation::Datum::ByteArray(bytes) + | sway_core::asm_generation::Datum::Slice(bytes) => { + if bytes.len() % 8 == 0 { + bytes.len() as u64 + } else { + ((bytes.len() + 7) & 0xfffffff8_usize) as u64 + } + } + + sway_core::asm_generation::Datum::Collection(items) => { + items.iter().map(calculate_entry_size).sum() + } + } + } + + // Compute the assembly information to be reported. + let asm_information = sway_core::asm_generation::AsmInformation { + bytecode_size: bytes.len() as _, + data_section: sway_core::asm_generation::DataSectionInformation { + size: data_section_size, + used: compiled_asm + .0 + .data_section + .value_pairs + .iter() + .map(calculate_entry_size) + .sum(), + value_pairs: compiled_asm.0.data_section.value_pairs.clone(), + }, + }; + + // Report the assembly information to the `dyno` process through `stdout`. + println!( + "/dyno info {}", + serde_json::to_string(&asm_information).unwrap() + ); +} + impl PkgEntry { /// Returns whether this `PkgEntry` corresponds to a test. pub fn is_test(&self) -> bool { @@ -2062,6 +2151,7 @@ fn build_profile_from_opts( pkg, print, time_phases, + profile: profile_opt, build_profile, release, metrics_outfile, @@ -2102,6 +2192,7 @@ fn build_profile_from_opts( profile.print_bytecode_spans |= print.bytecode_spans; profile.terse |= pkg.terse; profile.time_phases |= time_phases; + profile.profile |= profile_opt; if profile.metrics_outfile.is_none() { profile.metrics_outfile.clone_from(metrics_outfile); } diff --git a/forc-plugins/forc-client/src/op/deploy.rs b/forc-plugins/forc-client/src/op/deploy.rs index 8f86c333672..44eb8eb5442 100644 --- a/forc-plugins/forc-client/src/op/deploy.rs +++ b/forc-plugins/forc-client/src/op/deploy.rs @@ -913,6 +913,7 @@ fn build_opts_from_cmd(cmd: &cmd::Deploy, member_filter: pkg::MemberFilter) -> p reverse_order: cmd.print.reverse_order, }, time_phases: cmd.print.time_phases, + profile: cmd.print.profile, metrics_outfile: cmd.print.metrics_outfile.clone(), minify: pkg::MinifyOpts { json_abi: cmd.minify.json_abi, diff --git a/forc-plugins/forc-client/src/op/run/mod.rs b/forc-plugins/forc-client/src/op/run/mod.rs index debf0579c19..7d21d439e8c 100644 --- a/forc-plugins/forc-client/src/op/run/mod.rs +++ b/forc-plugins/forc-client/src/op/run/mod.rs @@ -267,6 +267,7 @@ fn build_opts_from_cmd(cmd: &cmd::Run) -> pkg::BuildOpts { release: cmd.build_profile.release, error_on_warnings: cmd.build_profile.error_on_warnings, time_phases: cmd.print.time_phases, + profile: cmd.print.profile, metrics_outfile: cmd.print.metrics_outfile.clone(), binary_outfile: cmd.build_output.bin_file.clone(), debug_outfile: cmd.build_output.debug_file.clone(), diff --git a/forc-test/src/lib.rs b/forc-test/src/lib.rs index c7bd19e95fd..bccc4cc0209 100644 --- a/forc-test/src/lib.rs +++ b/forc-test/src/lib.rs @@ -151,6 +151,8 @@ pub struct TestOpts { pub error_on_warnings: bool, /// Output the time elapsed over each part of the compilation process. pub time_phases: bool, + /// Profile the compilation process. + pub profile: bool, /// Output compilation metrics into file. pub metrics_outfile: Option, /// Set of enabled experimental flags @@ -453,6 +455,7 @@ impl From for pkg::BuildOpts { release: val.release, error_on_warnings: val.error_on_warnings, time_phases: val.time_phases, + profile: val.profile, metrics_outfile: val.metrics_outfile, tests: true, member_filter: Default::default(), @@ -476,6 +479,7 @@ impl TestOpts { release: self.release, error_on_warnings: self.error_on_warnings, time_phases: self.time_phases, + profile: self.profile, metrics_outfile: self.metrics_outfile, tests: true, member_filter: Default::default(), diff --git a/forc/Cargo.toml b/forc/Cargo.toml index b94be79b3cc..b3257f1ad1f 100644 --- a/forc/Cargo.toml +++ b/forc/Cargo.toml @@ -51,6 +51,7 @@ whoami.workspace = true default = [] test = [] util = [] +profile = [] [dev-dependencies] completest-pty = "0.5.0" diff --git a/forc/src/cli/commands/test.rs b/forc/src/cli/commands/test.rs index c67e9140b81..685a7d4e9bb 100644 --- a/forc/src/cli/commands/test.rs +++ b/forc/src/cli/commands/test.rs @@ -243,6 +243,7 @@ fn opts_from_cmd(cmd: Command) -> forc_test::TestOpts { reverse_order: cmd.build.print.reverse_order, }, time_phases: cmd.build.print.time_phases, + profile: cmd.build.print.profile, metrics_outfile: cmd.build.print.metrics_outfile, minify: pkg::MinifyOpts { json_abi: cmd.build.minify.json_abi, diff --git a/forc/src/cli/shared.rs b/forc/src/cli/shared.rs index 28b38465df3..23ccdd59cb9 100644 --- a/forc/src/cli/shared.rs +++ b/forc/src/cli/shared.rs @@ -99,6 +99,9 @@ pub struct Print { /// Output the time elapsed over each part of the compilation process. #[clap(long)] pub time_phases: bool, + /// Profile the compilation process. + #[clap(long)] + pub profile: bool, /// Output build errors and warnings in reverse order. #[clap(long)] pub reverse_order: bool, diff --git a/forc/src/ops/forc_build.rs b/forc/src/ops/forc_build.rs index 1118bdb5d54..2ec40cca931 100644 --- a/forc/src/ops/forc_build.rs +++ b/forc/src/ops/forc_build.rs @@ -30,6 +30,7 @@ fn opts_from_cmd(cmd: BuildCommand) -> pkg::BuildOpts { reverse_order: cmd.build.print.reverse_order, }, time_phases: cmd.build.print.time_phases, + profile: cmd.build.print.profile, metrics_outfile: cmd.build.print.metrics_outfile, minify: pkg::MinifyOpts { json_abi: cmd.build.minify.json_abi, diff --git a/forc/src/ops/forc_contract_id.rs b/forc/src/ops/forc_contract_id.rs index f80f4f5262f..9cc18edcfeb 100644 --- a/forc/src/ops/forc_contract_id.rs +++ b/forc/src/ops/forc_contract_id.rs @@ -64,6 +64,7 @@ fn build_opts_from_cmd(cmd: &ContractIdCommand) -> pkg::BuildOpts { reverse_order: cmd.print.reverse_order, }, time_phases: cmd.print.time_phases, + profile: cmd.print.profile, metrics_outfile: cmd.print.metrics_outfile.clone(), minify: pkg::MinifyOpts { json_abi: cmd.minify.json_abi, diff --git a/forc/src/ops/forc_predicate_root.rs b/forc/src/ops/forc_predicate_root.rs index 34be42c4117..41b7c5020a8 100644 --- a/forc/src/ops/forc_predicate_root.rs +++ b/forc/src/ops/forc_predicate_root.rs @@ -33,6 +33,7 @@ fn build_opts_from_cmd(cmd: PredicateRootCommand) -> pkg::BuildOpts { reverse_order: cmd.print.reverse_order, }, time_phases: cmd.print.time_phases, + profile: cmd.print.profile, metrics_outfile: cmd.print.metrics_outfile, minify: pkg::MinifyOpts { json_abi: cmd.minify.json_abi, diff --git a/sway-core/src/asm_generation/finalized_asm.rs b/sway-core/src/asm_generation/finalized_asm.rs index ce3c81e3a56..1bb66535693 100644 --- a/sway-core/src/asm_generation/finalized_asm.rs +++ b/sway-core/src/asm_generation/finalized_asm.rs @@ -19,6 +19,24 @@ use sway_types::SourceEngine; use either::Either; use std::{collections::BTreeMap, fmt}; +/// Represents an ASM set which has had register allocation, jump elimination, and optimization +/// applied to it +#[derive(Clone, serde::Serialize)] +pub struct AsmInformation { + pub bytecode_size: u64, + pub data_section: DataSectionInformation, +} + +#[derive(Default, Clone, Debug, serde::Serialize)] +pub struct DataSectionInformation { + /// The total size of the data section in bytes + pub size: u64, + /// The used size of the data section in bytes + pub used: u64, + /// The data to be put in the data section of the asm + pub value_pairs: Vec, +} + /// Represents an ASM set which has had register allocation, jump elimination, and optimization /// applied to it #[derive(Clone)] diff --git a/sway-core/src/asm_generation/fuel/data_section.rs b/sway-core/src/asm_generation/fuel/data_section.rs index 3db12443f4f..76f3300c705 100644 --- a/sway-core/src/asm_generation/fuel/data_section.rs +++ b/sway-core/src/asm_generation/fuel/data_section.rs @@ -4,7 +4,7 @@ use std::{fmt, iter::repeat}; // An entry in the data section. It's important for the size to be correct, especially for unions // where the size could be larger than the represented value. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, serde::Serialize)] pub struct Entry { pub value: Datum, pub padding: Padding, @@ -13,7 +13,7 @@ pub struct Entry { pub name: Option, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, serde::Serialize)] pub enum Datum { Byte(u8), Word(u64), diff --git a/sway-core/src/asm_generation/mod.rs b/sway-core/src/asm_generation/mod.rs index 2cd0e7d0605..dc7be862366 100644 --- a/sway-core/src/asm_generation/mod.rs +++ b/sway-core/src/asm_generation/mod.rs @@ -8,7 +8,8 @@ pub mod fuel; pub mod instruction_set; mod finalized_asm; -pub use finalized_asm::{CompiledBytecode, FinalizedAsm, FinalizedEntry}; +pub use finalized_asm::*; +pub use fuel::data_section::{Datum, Entry}; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ProgramKind { diff --git a/sway-core/src/build_config.rs b/sway-core/src/build_config.rs index 711ceb014d4..4f4ad896662 100644 --- a/sway-core/src/build_config.rs +++ b/sway-core/src/build_config.rs @@ -188,6 +188,7 @@ pub struct BuildConfig { pub(crate) include_tests: bool, pub(crate) optimization_level: OptLevel, pub time_phases: bool, + pub profile: bool, pub metrics_outfile: Option, pub lsp_mode: Option, } @@ -234,6 +235,7 @@ impl BuildConfig { print_ir: PrintIr::default(), include_tests: false, time_phases: false, + profile: false, metrics_outfile: None, optimization_level: OptLevel::Opt0, lsp_mode: None, @@ -280,6 +282,10 @@ impl BuildConfig { } } + pub fn with_profile(self, a: bool) -> Self { + Self { profile: a, ..self } + } + pub fn with_metrics(self, a: Option) -> Self { Self { metrics_outfile: a, diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index d66b8e779eb..d59970de1b0 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -740,6 +740,7 @@ pub fn compile_to_ast( // Parse the program to a concrete syntax tree (CST). let parse_program_opt = time_expr!( + package_name, "parse the program to a concrete syntax tree (CST)", "parse_cst", parse(input, handler, engines, build_config, experimental), @@ -764,6 +765,7 @@ pub fn compile_to_ast( // Type check (+ other static analysis) the CST to a typed AST. let typed_res = time_expr!( + package_name, "parse the concrete syntax tree (CST) to a typed AST", "parse_ast", parsed_to_ast( @@ -980,7 +982,7 @@ pub fn compile_to_bytecode( package_name: &str, experimental: ExperimentalFeatures, ) -> Result { - let asm_res = compile_to_asm( + let mut asm_res = compile_to_asm( handler, engines, input, @@ -989,13 +991,19 @@ pub fn compile_to_bytecode( package_name, experimental, )?; - asm_to_bytecode(handler, asm_res, source_map, engines.se(), build_config) + asm_to_bytecode( + handler, + &mut asm_res, + source_map, + engines.se(), + build_config, + ) } /// Given the assembly (opcodes), compile to [CompiledBytecode], containing the asm in bytecode form. pub fn asm_to_bytecode( handler: &Handler, - mut asm: CompiledAsm, + asm: &mut CompiledAsm, source_map: &mut SourceMap, source_engine: &SourceEngine, build_config: &BuildConfig, diff --git a/sway-ir/Cargo.toml b/sway-ir/Cargo.toml index 331302af16b..c4264f9281c 100644 --- a/sway-ir/Cargo.toml +++ b/sway-ir/Cargo.toml @@ -18,6 +18,7 @@ once_cell.workspace = true peg.workspace = true prettydiff.workspace = true rustc-hash.workspace = true +serde = { version = "1.0", features = ["derive"] } slotmap.workspace = true sway-features.workspace = true sway-ir-macros.workspace = true diff --git a/sway-ir/src/irtype.rs b/sway-ir/src/irtype.rs index 1771ca954bc..dc96427d56a 100644 --- a/sway-ir/src/irtype.rs +++ b/sway-ir/src/irtype.rs @@ -642,7 +642,7 @@ impl TypeSize { /// the value in aggregates. E.g., in an array of `u8`, each `u8` is "padded" /// to its size of one byte while as a struct field, it will be right padded /// to 8 bytes. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, serde::Serialize)] pub enum Padding { Left { target_size: usize }, Right { target_size: usize }, diff --git a/sway-utils/src/performance.rs b/sway-utils/src/performance.rs index cbf53cc5510..479c229c5e3 100644 --- a/sway-utils/src/performance.rs +++ b/sway-utils/src/performance.rs @@ -14,12 +14,28 @@ pub struct PerformanceData { pub reused_programs: u64, } +#[derive(serde::Serialize, Clone)] +pub struct FunctionEntryPoint { + /// The original entry point function name. + pub fn_name: String, + /// The immediate instruction offset at which the entry function begins. + pub imm: u64, + /// The function selector (only `Some` for contract ABI methods). + pub selector: Option<[u8; 4]>, +} + #[macro_export] // Time the given expression and print/save the result. macro_rules! time_expr { - ($description:expr, $key:expr, $expression:expr, $build_config:expr, $data:expr) => {{ + ($pkg_name:expr, $description:expr, $key:expr, $expression:expr, $build_config:expr, $data:expr) => {{ + use std::io::{BufRead, Read, Write}; if let Some(cfg) = $build_config { - if cfg.time_phases || cfg.metrics_outfile.is_some() { + if cfg.profile { + println!("/dyno start {} {}", $pkg_name, $description); + let output = { $expression }; + println!("/dyno stop {} {}", $pkg_name, $description); + output + } else if cfg.time_phases || cfg.metrics_outfile.is_some() { let expr_start = std::time::Instant::now(); let output = { $expression }; let elapsed = expr_start.elapsed(); From 3b07f499c2a23934359c5d7585a48d9f5fc0f447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Ron=C4=8Devi=C4=87?= Date: Fri, 15 Nov 2024 04:46:56 +0100 Subject: [PATCH 15/52] Storage domains (#6466) ## Description This PR fixes #6317 by implementing `storage_domains` experimental feature. This feature introduces two _storage domains_, one for the storage fields defined inside of the `storage` declaration, and a different one for storage slots generated inside of the `StorageMap`. The PR strictly fixes the issue described in #6317 by applying the recommendation proposed in the issue. A general approach to storage key domains will be discussed as a part of the [Configurable and composable storage RFC](https://github.com/FuelLabs/sway-rfcs/pull/40). Additionally, the PR: - adds expressive diagnostics for the duplicated storage keys warning. - removes the misleading internal compiler error that always followed the storage key type mismatch error (see demo below). Closes #6317, #6701. ## Breaking Changes The PR changes the way how storage keys are generated for `storage` fields. Instead of `sha256("storage::ns1::ns2.field_name")` we now use `sha256((0u8, "storage::ns1::ns2.field_name"))`. This is a breaking change for those who relied on the storage key calculation. ## Demo Before, every type-mismatch was always followed by an ICE, because the compilation continued despite the type-mismatch. ![Mismatched types and ICE - Before](https://github.com/user-attachments/assets/ac7915f7-3458-409e-a2bb-118dd4925234) This is solved now, and the type-mismatch has a dedicated help message. ![Mismatched types and ICE - After](https://github.com/user-attachments/assets/570aedd3-4c9c-4945-bfd0-5f12d68dbead) ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --------- Co-authored-by: Sophie Dankel <47993817+sdankel@users.noreply.github.com> Co-authored-by: IGI-111 --- sway-core/src/ir_generation/function.rs | 11 +- sway-core/src/ir_generation/storage.rs | 73 +- .../src/language/ty/declaration/storage.rs | 20 +- .../ast_node/declaration/declaration.rs | 34 +- .../ast_node/declaration/storage.rs | 42 +- .../typed_expression/enum_instantiation.rs | 6 +- .../typed_expression/struct_instantiation.rs | 6 +- sway-error/src/warning.rs | 70 +- sway-features/src/lib.rs | 3 + sway-ir/tests/tests.rs | 2 + sway-lib-std/src/storage/storage_map.sw | 34 +- sway-utils/src/constants.rs | 3 +- test/src/e2e_vm_tests/harness.rs | 64 +- test/src/e2e_vm_tests/mod.rs | 22 +- .../should_fail/invalid_cfg_arg/stdout.snap | 2 +- .../Forc.lock | 8 + .../Forc.toml | 9 + .../src/main.sw | 9 + .../test.toml | 17 + .../duplicated_storage_keys/src/main.sw | 14 +- .../test.storage_domains.toml | 30 + .../duplicated_storage_keys/test.toml | 34 +- .../call_basic_storage/src/main.sw | 2 +- .../call_storage_enum/src/main.sw | 2 +- .../storage_slot_key_calculation/Forc.lock | 13 + .../storage_slot_key_calculation/Forc.toml | 8 + .../storage_slot_key_calculation/src/main.sw | 53 ++ .../test.storage_domains.toml | 1 + .../storage_slot_key_calculation/test.toml | 2 + .../json_abi_oracle.storage_domains.json | 297 +++++++ ..._storage_slots_oracle.storage_domains.json | 58 ++ .../test_contracts/basic_storage/src/main.sw | 2 - .../basic_storage/test.storage_domains.toml | 1 + .../test_contracts/basic_storage/test.toml | 2 +- .../json_abi_oracle.storage_domains.json | 102 +++ ..._storage_slots_oracle.storage_domains.json | 6 + .../test.storage_domains.toml | 1 + .../json_abi_oracle.storage_domains.json | 769 ++++++++++++++++++ ..._storage_slots_oracle.storage_domains.json | 74 ++ .../test.storage_domains.toml | 1 + .../json_abi_oracle.storage_domains.json | 31 + ..._storage_slots_oracle.storage_domains.json | 62 ++ .../storage_enum_contract/src/main.sw | 12 - .../test.storage_domains.toml | 1 + .../json_abi_oracle.storage_domains.json | 289 +++++++ ..._storage_slots_oracle.storage_domains.json | 54 ++ .../test.storage_domains.toml | 1 + .../storage_namespace/test.toml | 2 +- test/src/ir_generation/mod.rs | 4 +- 49 files changed, 2236 insertions(+), 127 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.storage_domains.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.storage_domains.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_abi_oracle.storage_domains.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_storage_slots_oracle.storage_domains.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.storage_domains.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_abi_oracle.storage_domains.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_storage_slots_oracle.storage_domains.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/test.storage_domains.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_abi_oracle.storage_domains.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_storage_slots_oracle.storage_domains.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/test.storage_domains.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_abi_oracle.storage_domains.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_storage_slots_oracle.storage_domains.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/test.storage_domains.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_abi_oracle.storage_domains.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_storage_slots_oracle.storage_domains.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.storage_domains.toml diff --git a/sway-core/src/ir_generation/function.rs b/sway-core/src/ir_generation/function.rs index f3a7064568e..4171056c2e7 100644 --- a/sway-core/src/ir_generation/function.rs +++ b/sway-core/src/ir_generation/function.rs @@ -4338,6 +4338,14 @@ impl<'eng> FnCompiler<'eng> { base_type: &Type, span_md_idx: Option, ) -> Result { + // Use the `struct_field_names` to get a field id that is unique even for zero-sized values that live in the same slot. + // We calculate the `unique_field_id` early, here, before the `storage_filed_names` get consumed by `get_storage_key` below. + let unique_field_id = get_storage_field_id( + &storage_field_names, + &struct_field_names, + context.experimental, + ); + // Get the actual storage key as a `Bytes32` as well as the offset, in words, // within the slot. The offset depends on what field of the top level storage // variable is being accessed. @@ -4371,7 +4379,7 @@ impl<'eng> FnCompiler<'eng> { // particular slot is the remaining offset, in words. ( add_to_b256( - get_storage_key(storage_field_names.clone(), key.clone()), + get_storage_key(storage_field_names, key, context.experimental), offset_in_slots, ), offset_remaining, @@ -4428,7 +4436,6 @@ impl<'eng> FnCompiler<'eng> { .add_metadatum(context, span_md_idx); // Store the field identifier as the third field in the `StorageKey` struct - let unique_field_id = get_storage_field_id(storage_field_names, struct_field_names); // use the struct_field_names to get a field id that is unique even for zero-sized values that live in the same slot let field_id = convert_literal_to_value(context, &Literal::B256(unique_field_id.into())) .add_metadatum(context, span_md_idx); let gep_2_val = diff --git a/sway-core/src/ir_generation/storage.rs b/sway-core/src/ir_generation/storage.rs index 14fd2b8ef00..4f42a74a2e8 100644 --- a/sway-core/src/ir_generation/storage.rs +++ b/sway-core/src/ir_generation/storage.rs @@ -3,6 +3,7 @@ use crate::fuel_prelude::{ fuel_tx::StorageSlot, fuel_types::{Bytes32, Bytes8}, }; +use sway_features::ExperimentalFeatures; use sway_ir::{ constant::{Constant, ConstantValue}, context::Context, @@ -20,28 +21,31 @@ enum InByte8Padding { } /// Hands out storage keys using storage field names or an existing key. -/// Basically returns sha256("storage::::.") +/// Basically returns sha256((0u8, "storage::::.")) /// or key if defined. -pub(super) fn get_storage_key(storage_field_names: Vec, key: Option) -> Bytes32 { - if let Some(key) = key { - return key.to_be_bytes().into(); +pub(super) fn get_storage_key( + storage_field_names: Vec, + key: Option, + experimental: ExperimentalFeatures, +) -> Bytes32 { + match key { + Some(key) => key.to_be_bytes().into(), + None => hash_storage_key_string(get_storage_key_string(&storage_field_names), experimental), } - - Hasher::hash(get_storage_key_string(storage_field_names)) } -pub fn get_storage_key_string(storage_field_names: Vec) -> String { +pub fn get_storage_key_string(storage_field_names: &[String]) -> String { if storage_field_names.len() == 1 { format!( "{}{}{}", - sway_utils::constants::STORAGE_DOMAIN, + sway_utils::constants::STORAGE_TOP_LEVEL_NAMESPACE, sway_utils::constants::STORAGE_FIELD_SEPARATOR, storage_field_names.last().unwrap(), ) } else { format!( "{}{}{}{}{}", - sway_utils::constants::STORAGE_DOMAIN, + sway_utils::constants::STORAGE_TOP_LEVEL_NAMESPACE, sway_utils::constants::STORAGE_NAMESPACE_SEPARATOR, storage_field_names .iter() @@ -56,10 +60,11 @@ pub fn get_storage_key_string(storage_field_names: Vec) -> String { } /// Hands out unique storage field ids using storage field names and struct field names. -/// Basically returns sha256("storage::::...") +/// Basically returns sha256((0u8, "storage::::...")). pub(super) fn get_storage_field_id( - storage_field_names: Vec, - struct_field_names: Vec, + storage_field_names: &[String], + struct_field_names: &[String], + experimental: ExperimentalFeatures, ) -> Bytes32 { let data = format!( "{}{}", @@ -74,7 +79,32 @@ pub(super) fn get_storage_field_id( ) } ); - Hasher::hash(data) + + hash_storage_key_string(data, experimental) +} + +fn hash_storage_key_string( + storage_key_string: String, + experimental: ExperimentalFeatures, +) -> Bytes32 { + let mut hasher = Hasher::default(); + // Certain storage types, like, e.g., `StorageMap` allow + // storage slots of their contained elements to be defined + // based on developer's input. E.g., the `key` in a `StorageMap` + // used to calculate the storage slot is a developer input. + // + // To ensure that pre-images of such storage slots can never + // be the same as a pre-image of compiler generated key of storage + // field, we prefix the pre-images with a single byte that denotes + // the domain. Storage types like `StorageMap` must have a different + // domain prefix than the `STORAGE_DOMAIN` which is 0u8. + // + // For detailed elaboration see: https://github.com/FuelLabs/sway/issues/6317 + if experimental.storage_domains { + hasher.input(sway_utils::constants::STORAGE_DOMAIN); + } + hasher.input(storage_key_string); + hasher.finalize() } use uint::construct_uint; @@ -109,17 +139,18 @@ pub fn serialize_to_storage_slots( key: Option, ty: &Type, ) -> Vec { + let experimental = context.experimental; match &constant.value { ConstantValue::Undef => vec![], // If not being a part of an aggregate, single byte values like `bool`, `u8`, and unit // are stored as a byte at the beginning of the storage slot. ConstantValue::Unit if ty.is_unit(context) => vec![StorageSlot::new( - get_storage_key(storage_field_names, key), + get_storage_key(storage_field_names, key, experimental), Bytes32::new([0; 32]), )], ConstantValue::Bool(b) if ty.is_bool(context) => { vec![StorageSlot::new( - get_storage_key(storage_field_names, key), + get_storage_key(storage_field_names, key, experimental), Bytes32::new([ if *b { 1 } else { 0 }, 0, @@ -158,7 +189,7 @@ pub fn serialize_to_storage_slots( } ConstantValue::Uint(b) if ty.is_uint8(context) => { vec![StorageSlot::new( - get_storage_key(storage_field_names, key), + get_storage_key(storage_field_names, key, experimental), Bytes32::new([ *b as u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -168,7 +199,7 @@ pub fn serialize_to_storage_slots( // Similarly, other uint values are stored at the beginning of the storage slot. ConstantValue::Uint(n) if ty.is_uint(context) => { vec![StorageSlot::new( - get_storage_key(storage_field_names, key), + get_storage_key(storage_field_names, key, experimental), Bytes32::new( n.to_be_bytes() .iter() @@ -182,13 +213,13 @@ pub fn serialize_to_storage_slots( } ConstantValue::U256(b) if ty.is_uint_of(context, 256) => { vec![StorageSlot::new( - get_storage_key(storage_field_names, key), + get_storage_key(storage_field_names, key, experimental), Bytes32::new(b.to_be_bytes()), )] } ConstantValue::B256(b) if ty.is_b256(context) => { vec![StorageSlot::new( - get_storage_key(storage_field_names, key), + get_storage_key(storage_field_names, key, experimental), Bytes32::new(b.to_be_bytes()), )] } @@ -224,8 +255,10 @@ pub fn serialize_to_storage_slots( type_size_in_bytes, ty.as_string(context) ); + + let storage_key = get_storage_key(storage_field_names, key, experimental); (0..(type_size_in_bytes + 31) / 32) - .map(|i| add_to_b256(get_storage_key(storage_field_names.clone(), key.clone()), i)) + .map(|i| add_to_b256(storage_key, i)) .zip((0..packed.len() / 4).map(|i| { Bytes32::new( Vec::from_iter((0..4).flat_map(|j| *packed[4 * i + j])) diff --git a/sway-core/src/language/ty/declaration/storage.rs b/sway-core/src/language/ty/declaration/storage.rs index 23e4b7a09ba..abc5a67b20c 100644 --- a/sway-core/src/language/ty/declaration/storage.rs +++ b/sway-core/src/language/ty/declaration/storage.rs @@ -8,8 +8,10 @@ use sway_types::{Ident, Named, Span, Spanned}; use crate::{ engine_threading::*, - language::{parsed::StorageDeclaration, ty::*}, + ir_generation::storage::get_storage_key_string, + language::parsed::StorageDeclaration, transform::{self}, + ty::*, type_system::*, Namespace, }; @@ -252,6 +254,22 @@ pub struct TyStorageField { pub attributes: transform::AttributesMap, } +impl TyStorageField { + /// Returns the full name of the [TyStorageField], consisting + /// of its name preceded by its full namespace path. + /// E.g., "storage::ns1::ns1.name". + pub fn full_name(&self) -> String { + get_storage_key_string( + &self + .namespace_names + .iter() + .map(|i| i.as_str().to_string()) + .chain(vec![self.name.as_str().to_string()]) + .collect::>(), + ) + } +} + impl EqWithEngines for TyStorageField {} impl PartialEqWithEngines for TyStorageField { fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool { 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 0f965bd0d4e..b063fd53028 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -441,22 +441,32 @@ impl TyDecl { let initializer = ty::TyExpression::type_check(handler, ctx.by_ref(), &initializer)?; - let mut key_ty_expression = None; - if let Some(key_expression) = key_expression { - let mut key_ctx = - ctx.with_type_annotation(engines.te().id_of_b256()); - - key_ty_expression = Some(ty::TyExpression::type_check( - handler, - key_ctx.by_ref(), - &key_expression, - )?); - } + let key_expression = match key_expression { + Some(key_expression) => { + let key_ctx = ctx + .with_type_annotation(engines.te().id_of_b256()) + .with_help_text("Storage keys must have type \"b256\"."); + + // TODO: Remove the `handler.scope` once https://github.com/FuelLabs/sway/issues/5606 gets solved. + // We need it here so that we can short-circuit in case of a `TypeMismatch` error which is + // not treated as an error in the `type_check()`'s result. + let typed_expr = handler.scope(|handler| { + ty::TyExpression::type_check( + handler, + key_ctx, + &key_expression, + ) + })?; + + Some(typed_expr) + } + None => None, + }; fields_buf.push(ty::TyStorageField { name, namespace_names: namespace_names.clone(), - key_expression: key_ty_expression, + key_expression, type_argument, initializer, span: field_span, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs b/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs index 08e0984b7ed..7df2bb722d4 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs @@ -4,8 +4,7 @@ use crate::{ decl_engine::parsed_id::ParsedDeclId, fuel_prelude::fuel_tx::StorageSlot, ir_generation::{ - const_eval::compile_constant_expression_to_constant, - storage::{get_storage_key_string, serialize_to_storage_slots}, + const_eval::compile_constant_expression_to_constant, storage::serialize_to_storage_slots, }, language::{ parsed::StorageDeclaration, @@ -54,32 +53,27 @@ impl ty::TyStorageDecl { let slots = f.get_initialized_storage_slots(engines, context, md_mgr, module); // Check if slot with same key was already used and throw warning. - if let Ok(slots) = slots.clone() { - for s in slots.into_iter() { + if let Ok(slots) = &slots { + for s in slots.iter() { if let Some(old_field) = slot_fields.insert(*s.key(), f.clone()) { handler.emit_warn(CompileWarning { span: f.span(), warning_content: sway_error::warning::Warning::DuplicatedStorageKey { - key: format!("{:X} ", s.key()), - field1: get_storage_key_string( - old_field - .namespace_names - .iter() - .map(|i| i.as_str().to_string()) - .chain(vec![old_field - .name - .as_str() - .to_string()]) - .collect::>(), - ), - field2: get_storage_key_string( - f.namespace_names - .iter() - .map(|i| i.as_str().to_string()) - .chain(vec![f.name.as_str().to_string()]) - .collect::>(), - ), + first_field: (&old_field.name).into(), + first_field_full_name: old_field.full_name(), + first_field_key_is_compiler_generated: old_field + .key_expression + .is_none(), + second_field: (&f.name).into(), + second_field_full_name: f.full_name(), + second_field_key_is_compiler_generated: f + .key_expression + .is_none(), + key: format!("0x{:x}", s.key()), + experimental_storage_domains: context + .experimental + .storage_domains, }, }) } @@ -151,7 +145,7 @@ impl ty::TyStorageField { Ok(Some(key)) } else { Err(CompileError::Internal( - "Expected B256 key", + "Storage keys must have type \"b256\".", key_expression.span.clone(), )) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs index 4da63001bb4..742cadb1691 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs @@ -136,9 +136,9 @@ pub(crate) fn instantiate_enum( .with_help_text(help_text) .with_type_annotation(enum_variant_type_id); - // TODO-IG: Remove the `handler.scope` once https://github.com/FuelLabs/sway/issues/5606 gets solved. - // We need it here so that we can short-circuit in case of a `TypeMismatch` error which is - // not treated as an error in the `type_check()`'s result. + // TODO: Remove the `handler.scope` once https://github.com/FuelLabs/sway/issues/5606 gets solved. + // We need it here so that we can short-circuit in case of a `TypeMismatch` error which is + // not treated as an error in the `type_check()`'s result. let typed_expr = handler .scope(|handler| ty::TyExpression::type_check(handler, enum_ctx, single_expr))?; diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs index 47c190a0c2b..bf52842ea81 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs @@ -397,9 +397,9 @@ fn type_check_field_arguments( .with_type_annotation(struct_field.type_argument.type_id) .with_unify_generic(true); - // TODO-IG: Remove the `handler.scope` once https://github.com/FuelLabs/sway/issues/5606 gets solved. - // We need it here so that we can short-circuit in case of a `TypeMismatch` error which is - // not treated as an error in the `type_check()`'s result. + // TODO: Remove the `handler.scope` once https://github.com/FuelLabs/sway/issues/5606 gets solved. + // We need it here so that we can short-circuit in case of a `TypeMismatch` error which is + // not treated as an error in the `type_check()`'s result. let typed_expr = handler .scope(|handler| ty::TyExpression::type_check(handler, ctx, &field.value)); diff --git a/sway-error/src/warning.rs b/sway-error/src/warning.rs index 78a4ac8953b..dce69c85805 100644 --- a/sway-error/src/warning.rs +++ b/sway-error/src/warning.rs @@ -1,4 +1,7 @@ -use crate::diagnostic::{Code, Diagnostic, Hint, Issue, Reason, ToDiagnostic}; +use crate::{ + diagnostic::{Code, Diagnostic, Hint, Issue, Reason, ToDiagnostic}, + formatting::Indent, +}; use core::fmt; @@ -128,9 +131,15 @@ pub enum Warning { message: String, }, DuplicatedStorageKey { + first_field: IdentUnique, + first_field_full_name: String, + first_field_key_is_compiler_generated: bool, + second_field: IdentUnique, + second_field_full_name: String, + second_field_key_is_compiler_generated: bool, key: String, - field1: String, - field2: String, + // True if the experimental feature `storage_domains` is used. + experimental_storage_domains: bool, }, } @@ -279,7 +288,8 @@ impl fmt::Display for Warning { You can enable the new behavior with the --experimental-private-modules flag, which will become the default behavior in a later release. More details are available in the related RFC: https://github.com/FuelLabs/sway-rfcs/blob/master/rfcs/0008-private-modules.md"), UsingDeprecated { message } => write!(f, "{}", message), - DuplicatedStorageKey { key, field1, field2 } => write!(f, "Two storage fields are using the same storage key.\nFirst field: {field1}\nSecond field: {field2}\nKey: {key}"), + DuplicatedStorageKey { first_field_full_name, second_field_full_name, key, .. } => + write!(f, "Two storage fields have the same storage key.\nFirst field: {first_field_full_name}\nSecond field: {second_field_full_name}\nKey: {key}"), } } } @@ -412,6 +422,58 @@ impl ToDiagnostic for CompileWarning { "Consider adding assembly instructions or a return register to the ASM block, or removing the block altogether.".to_string(), ], }, + DuplicatedStorageKey { first_field, first_field_full_name, first_field_key_is_compiler_generated, second_field, second_field_full_name, second_field_key_is_compiler_generated, key, experimental_storage_domains } => Diagnostic { + reason: Some(Reason::new(code(1), "Two storage fields have the same storage key".to_string())), + issue: Issue::warning( + source_engine, + first_field.span(), + format!("\"{first_field_full_name}\" has the same storage key as \"{second_field_full_name}\"."), + ), + hints: vec![ + Hint::info( + source_engine, + second_field.span(), + format!("\"{second_field_full_name}\" is declared here."), + ), + ], + help: vec![ + if *first_field_key_is_compiler_generated || *second_field_key_is_compiler_generated { + format!("The key of \"{}\" is generated by the compiler using the following formula:", + if *first_field_key_is_compiler_generated { + first_field_full_name + } else { + second_field_full_name + } + ) + } else { + "Both keys are explicitly defined by using the `in` keyword.".to_string() + }, + if *first_field_key_is_compiler_generated || *second_field_key_is_compiler_generated { + if *experimental_storage_domains { + format!("{}sha256((0u8, \"{}\"))", + Indent::Single, + if *first_field_key_is_compiler_generated { + first_field_full_name + } else { + second_field_full_name + } + ) + } else { + format!("{}sha256(\"{}\")", + Indent::Single, + if *first_field_key_is_compiler_generated { + first_field_full_name + } else { + second_field_full_name + } + ) + } + } else { + Diagnostic::help_none() + }, + format!("The common key is: {key}.") + ], + }, _ => 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-features/src/lib.rs b/sway-features/src/lib.rs index 55d50920891..fdff644741a 100644 --- a/sway-features/src/lib.rs +++ b/sway-features/src/lib.rs @@ -131,6 +131,8 @@ impl ExperimentalFeatures { features! { new_encoding = true, "https://github.com/FuelLabs/sway/issues/5727", + storage_domains = false, + "https://github.com/FuelLabs/sway/issues/6701", } #[derive(Clone, Debug, Default, Parser)] @@ -228,6 +230,7 @@ mod tests { let mut features = ExperimentalFeatures { new_encoding: false, + ..Default::default() }; std::env::set_var("FORC_EXPERIMENTAL", "new_encoding"); diff --git a/sway-ir/tests/tests.rs b/sway-ir/tests/tests.rs index 743b3523977..5e6ccaeaa8f 100644 --- a/sway-ir/tests/tests.rs +++ b/sway-ir/tests/tests.rs @@ -29,6 +29,8 @@ fn run_tests bool>(sub_dir: &str, opt_fn: F) { let experimental = ExperimentalFeatures { new_encoding: false, + // TODO: Properly support experimental features in IR tests. + ..Default::default() }; let mut ir = sway_ir::parser::parse(&input, &source_engine, experimental).unwrap_or_else( diff --git a/sway-lib-std/src/storage/storage_map.sw b/sway-lib-std/src/storage/storage_map.sw index 360ed95ade3..4d7aca969ae 100644 --- a/sway-lib-std/src/storage/storage_map.sw +++ b/sway-lib-std/src/storage/storage_map.sw @@ -6,6 +6,22 @@ use ::result::Result; use ::storage::storage_api::*; use ::storage::storage_key::*; +/// The storage domain value of the [StorageMap]. +/// +/// Storage slots of elements contained within a [StorageMap] +/// are calculated based on developers' or users' input (the key). +/// +/// To ensure that pre-images used to calculate storage slots can never +/// be the same as a pre-image of a compiler generated key of a storage +/// field, we prefix the pre-images with a single byte that denotes +/// the storage map domain. +/// +/// The domain prefix for the [StorageMap] is 1u8. +/// +/// For detailed elaboration see: https://github.com/FuelLabs/sway/issues/6317 +#[cfg(experimental_storage_domains = true)] +const STORAGE_MAP_DOMAIN: u8 = 1; + /// Errors pertaining to the `StorageMap` struct. pub enum StorageMapError { /// Indicates that a value already exists for the key. @@ -51,7 +67,7 @@ where where K: Hash, { - let key = sha256((key, self.field_id())); + let key = self.get_slot_key(key); write::(key, 0, value); } @@ -85,7 +101,7 @@ where where K: Hash, { - let key = sha256((key, self.field_id())); + let key = self.get_slot_key(key); StorageKey::::new(key, 0, key) } @@ -124,7 +140,7 @@ where where K: Hash, { - let key = sha256((key, self.field_id())); + let key = self.get_slot_key(key); clear::(key, 0) } @@ -175,7 +191,7 @@ where where K: Hash, { - let key = sha256((key, self.field_id())); + let key = self.get_slot_key(key); let val = read::(key, 0); @@ -189,4 +205,14 @@ where } } } + + #[cfg(experimental_storage_domains = false)] + fn get_slot_key(self, key: K) -> b256 { + sha256((key, self.field_id())) + } + + #[cfg(experimental_storage_domains = true)] + fn get_slot_key(self, key: K) -> b256 { + sha256((STORAGE_MAP_DOMAIN, key, self.field_id())) + } } diff --git a/sway-utils/src/constants.rs b/sway-utils/src/constants.rs index 00214945ed5..c0f8b6938a9 100644 --- a/sway-utils/src/constants.rs +++ b/sway-utils/src/constants.rs @@ -7,7 +7,8 @@ pub const USER_FORC_DIRECTORY: &str = ".forc"; pub const SRC_DIR: &str = "src"; pub const DEFAULT_NODE_URL: &str = "http://127.0.0.1:4000"; pub const LANGUAGE_NAME: &str = "Sway"; -pub const STORAGE_DOMAIN: &str = "storage"; +pub const STORAGE_DOMAIN: [u8; 1] = [0u8]; +pub const STORAGE_TOP_LEVEL_NAMESPACE: &str = "storage"; pub const STORAGE_NAMESPACE_SEPARATOR: &str = "::"; pub const STORAGE_FIELD_SEPARATOR: &str = "."; pub const STRUCT_FIELD_SEPARATOR: &str = "."; diff --git a/test/src/e2e_vm_tests/harness.rs b/test/src/e2e_vm_tests/harness.rs index 164d442e7bf..31dbcda4b48 100644 --- a/test/src/e2e_vm_tests/harness.rs +++ b/test/src/e2e_vm_tests/harness.rs @@ -398,22 +398,28 @@ pub(crate) fn test_json_abi( } if fs::metadata(oracle_path.clone()).is_err() { - bail!("JSON ABI oracle file does not exist for this test."); + bail!( + "JSON ABI oracle file does not exist for this test\nExpected oracle path: {}", + &oracle_path + ); } if fs::metadata(output_path.clone()).is_err() { - bail!("JSON ABI output file does not exist for this test."); + bail!( + "JSON ABI output file does not exist for this test\nExpected output path: {}", + &output_path + ); } - let oracle_contents = - fs::read_to_string(&oracle_path).expect("Something went wrong reading the file."); - let output_contents = - fs::read_to_string(&output_path).expect("Something went wrong reading the file."); + let oracle_contents = fs::read_to_string(&oracle_path) + .expect("Something went wrong reading the JSON ABI oracle file."); + let output_contents = fs::read_to_string(&output_path) + .expect("Something went wrong reading the JSON ABI output file."); if oracle_contents != output_contents { - println!("Mismatched ABI JSON output [{oracle_path}] versus [{output_path}]",); - println!( - "{}", + bail!( + "Mismatched ABI JSON output.\nOracle path: {}\nOutput path: {}\n{}", + oracle_path, + output_path, prettydiff::diff_lines(&oracle_contents, &output_contents) ); - bail!("Mismatched ABI JSON output."); } Ok(()) } @@ -435,29 +441,47 @@ fn emit_json_abi(file_name: &str, built_package: &BuiltPackage) -> Result<()> { Ok(()) } -pub(crate) fn test_json_storage_slots(file_name: &str, built_package: &BuiltPackage) -> Result<()> { +pub(crate) fn test_json_storage_slots( + file_name: &str, + built_package: &BuiltPackage, + suffix: &Option, +) -> Result<()> { emit_json_storage_slots(file_name, built_package)?; let manifest_dir = env!("CARGO_MANIFEST_DIR"); let oracle_path = format!( - "{}/src/e2e_vm_tests/test_programs/{}/{}", - manifest_dir, file_name, "json_storage_slots_oracle.json" + "{}/src/e2e_vm_tests/test_programs/{}/json_storage_slots_oracle.{}json", + manifest_dir, + file_name, + suffix + .as_ref() + .unwrap() + .strip_prefix("test") + .unwrap() + .strip_suffix("toml") + .unwrap() + .trim_start_matches('.') ); let output_path = format!( "{}/src/e2e_vm_tests/test_programs/{}/{}", manifest_dir, file_name, "json_storage_slots_output.json" ); if fs::metadata(oracle_path.clone()).is_err() { - bail!("JSON storage slots oracle file does not exist for this test."); + bail!("JSON storage slots oracle file does not exist for this test.\nExpected oracle path: {}", &oracle_path); } if fs::metadata(output_path.clone()).is_err() { - bail!("JSON storage slots output file does not exist for this test."); + bail!("JSON storage slots output file does not exist for this test.\nExpected output path: {}", &output_path); } - let oracle_contents = - fs::read_to_string(oracle_path).expect("Something went wrong reading the file."); - let output_contents = - fs::read_to_string(output_path).expect("Something went wrong reading the file."); + let oracle_contents = fs::read_to_string(oracle_path.clone()) + .expect("Something went wrong reading the JSON storage slots oracle file."); + let output_contents = fs::read_to_string(output_path.clone()) + .expect("Something went wrong reading the JSON storage slots output file."); if oracle_contents != output_contents { - bail!("Mismatched storage slots JSON output."); + bail!( + "Mismatched storage slots JSON output.\nOracle path: {}\nOutput path: {}\n{}", + oracle_path, + output_path, + prettydiff::diff_lines(&oracle_contents, &output_contents) + ); } Ok(()) } diff --git a/test/src/e2e_vm_tests/mod.rs b/test/src/e2e_vm_tests/mod.rs index 62dc360fea1..725056b9ac7 100644 --- a/test/src/e2e_vm_tests/mod.rs +++ b/test/src/e2e_vm_tests/mod.rs @@ -515,7 +515,7 @@ impl TestContext { if validate_storage_slots { for (name, built_pkg) in &compiled_pkgs { let (result, out) = run_and_capture_output(|| async { - harness::test_json_storage_slots(name, built_pkg) + harness::test_json_storage_slots(name, built_pkg, &suffix) }) .await; result?; @@ -602,7 +602,15 @@ impl TestContext { ))); } } - _ => todo!(), + TestResult::ReturnData(_) => { + todo!("Test result `ReturnData` is currently not implemented.") + } + TestResult::Return(_) => { + todo!("Test result `Return` is currently not implemented.") + } + TestResult::Revert(_) => { + todo!("Test result `Revert` is currently not implemented.") + } }, Receipt::ReturnData { data, .. } => match expected_result.unwrap() { TestResult::ReturnData(v) => { @@ -612,7 +620,15 @@ impl TestContext { ))); } } - _ => todo!(), + TestResult::Result(_) => { + todo!("Test result `Result` is currently not implemented.") + } + TestResult::Return(_) => { + todo!("Test result `Return` is currently not implemented.") + } + TestResult::Revert(_) => { + todo!("Test result `Revert` is currently not implemented.") + } }, _ => {} }; diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/invalid_cfg_arg/stdout.snap b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_cfg_arg/stdout.snap index fee2b903ecd..84c0fa58caf 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/invalid_cfg_arg/stdout.snap +++ b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_cfg_arg/stdout.snap @@ -11,7 +11,7 @@ warning | 1 | predicate; 2 | #[cfg(c)] a - | --- Unexpected attribute value: "c" for attribute: "cfg" expected value "target" or "program_type" or "experimental_new_encoding" + | --- Unexpected attribute value: "c" for attribute: "cfg" expected value "target" or "program_type" or "experimental_new_encoding" or "experimental_storage_domains" | ____ diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.lock new file mode 100644 index 00000000000..6024e958c64 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "core" +source = "path+from-root-C0C563B172E50A8D" + +[[package]] +name = "storage_invalid_storage_key_type" +source = "member" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.toml new file mode 100644 index 00000000000..18a5527966d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "storage_invalid_storage_key_type" +implicit-std = false + +[dependencies] +core = { path = "../../../../../../sway-lib-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/src/main.sw new file mode 100644 index 00000000000..18a4f599f52 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/src/main.sw @@ -0,0 +1,9 @@ +contract; + +fn get_u256() -> u256 { + 0x0u256 +} + +storage { + field in get_u256(): u64 = 0, +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/test.toml new file mode 100644 index 00000000000..150a184e449 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/test.toml @@ -0,0 +1,17 @@ +category = "fail" + +#check: $()error +#check: $()field in get_u256(): u64 = 0, +#nextln: $()Mismatched types. +#nextln: $()expected: b256 +#nextln: $()found: u256. +#nextln: $()Function return type does not match up with local type annotation. + +#check: $()error +#check: $()field in get_u256(): u64 = 0, +#nextln: $()Mismatched types. +#nextln: $()expected: b256 +#nextln: $()found: u256. +#nextln: $()Storage keys must have type "b256". + +#check: $()2 errors. \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/src/main.sw index 54c8ccf3246..2bfa29631e6 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/src/main.sw @@ -2,12 +2,24 @@ contract; storage { f1:u64 = 1, + #[cfg(experimental_storage_domains = true)] + f2 in 0xcecf0a910789de762c699a85a66835df1662df633238cbb25804b7f78640747b: u64 = 2, + #[cfg(experimental_storage_domains = false)] f2 in 0x36389d1013642dcb070193fc48b0316e9dfdfef1860096dc5957e3eb44430b83: u64 = 2, ns1 { f3 in 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca: u64 = 2, }, ns2 { f4 in 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca: u64 = 2, - } + }, + ns3 { + #[cfg(experimental_storage_domains = true)] + f5 in 0x41e70e0fdfa49becc40cbfd5c057ab0540e8844f3d737fa3b1ab21a564b48069: u64 = 3, + #[cfg(experimental_storage_domains = false)] + f5 in 0xa49ebab6739a90f7658bbbdc2ed139942bd0b7be2e89aa8d90a953c45bf7a211: u64 = 3, + }, + ns4 { + f6: u64 = 4, + }, } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.storage_domains.toml new file mode 100644 index 00000000000..4e181f7e13d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.storage_domains.toml @@ -0,0 +1,30 @@ +category = "compile" +experimental = { storage_domains = true } + +# check: $()Two storage fields have the same storage key +# check: $()f1:u64 = 1, +# nextln: $()"storage.f1" has the same storage key as "storage.f2". +# check: $()f2 in 0xcecf0a910789de762c699a85a66835df1662df633238cbb25804b7f78640747b: u64 = 2, +# nextln: $()"storage.f2" is declared here. +# check: $()The key of "storage.f1" is generated by the compiler using the following formula: +# nextln: $()sha256((0u8, "storage.f1")) +# nextln: $()The common key is: 0xcecf0a910789de762c699a85a66835df1662df633238cbb25804b7f78640747b. + +# check: $()Two storage fields have the same storage key +# check: $()f3 in 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca: u64 = 2, +# nextln: $()"storage::ns1.f3" has the same storage key as "storage::ns2.f4". +# check: $()f4 in 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca: u64 = 2, +# nextln: $()"storage::ns2.f4" is declared here. +# check: $()Both keys are explicitly defined by using the `in` keyword. +# nextln: $()The common key is: 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca. + +# check: $()Two storage fields have the same storage key +# check: $()f5 in 0x41e70e0fdfa49becc40cbfd5c057ab0540e8844f3d737fa3b1ab21a564b48069: u64 = 3, +# nextln: $()"storage::ns3.f5" has the same storage key as "storage::ns4.f6". +# check: $()f6: u64 = 4, +# nextln: $()"storage::ns4.f6" is declared here. +# check: $()The key of "storage::ns4.f6" is generated by the compiler using the following formula: +# nextln: $()sha256((0u8, "storage::ns4.f6")) +# nextln: $()The common key is: 0x41e70e0fdfa49becc40cbfd5c057ab0540e8844f3d737fa3b1ab21a564b48069. + +expected_warnings = 9 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.toml index 8e5e7a86ef3..30c36d8b5f8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.toml @@ -1,13 +1,29 @@ category = "compile" -# check: $()Two storage fields are using the same storage key. -# nextln: $()First field: storage.f1 -# nextln: $()Second field: storage.f2 -# nextln: $()Key: 36389D1013642DCB070193FC48B0316E9DFDFEF1860096DC5957E3EB44430B83 +# check: $()Two storage fields have the same storage key +# check: $()f1:u64 = 1, +# nextln: $()"storage.f1" has the same storage key as "storage.f2". +# check: $()f2 in 0x36389d1013642dcb070193fc48b0316e9dfdfef1860096dc5957e3eb44430b83: u64 = 2, +# nextln: $()"storage.f2" is declared here. +# check: $()The key of "storage.f1" is generated by the compiler using the following formula: +# nextln: $()sha256("storage.f1") +# nextln: $()The common key is: 0x36389d1013642dcb070193fc48b0316e9dfdfef1860096dc5957e3eb44430b83. -# check: $()Two storage fields are using the same storage key. -# nextln: $()First field: storage::ns1.f3 -# nextln: $()Second field: storage::ns2.f4 -# nextln: $()Key: 5F4C20CE4BD128E5393A4C2B82007DAC795FA0006D01ACF8DB4C42632BC680CA +# check: $()Two storage fields have the same storage key +# check: $()f3 in 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca: u64 = 2, +# nextln: $()"storage::ns1.f3" has the same storage key as "storage::ns2.f4". +# check: $()f4 in 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca: u64 = 2, +# nextln: $()"storage::ns2.f4" is declared here. +# check: $()Both keys are explicitly defined by using the `in` keyword. +# nextln: $()The common key is: 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca. -expected_warnings = 6 +# check: $()Two storage fields have the same storage key +# check: $()f5 in 0xa49ebab6739a90f7658bbbdc2ed139942bd0b7be2e89aa8d90a953c45bf7a211: u64 = 3, +# nextln: $()"storage::ns3.f5" has the same storage key as "storage::ns4.f6". +# check: $()f6: u64 = 4, +# nextln: $()"storage::ns4.f6" is declared here. +# check: $()The key of "storage::ns4.f6" is generated by the compiler using the following formula: +# nextln: $()sha256("storage::ns4.f6") +# nextln: $()The common key is: 0xa49ebab6739a90f7658bbbdc2ed139942bd0b7be2e89aa8d90a953c45bf7a211. + +expected_warnings = 9 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw index 1ed97f22e9d..d7218234e92 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw @@ -4,7 +4,7 @@ use basic_storage_abi::{BasicStorage, Quad}; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x94db39f409a31b9f2ebcadeea44378e419208c20de90f5d8e1e33dc1523754cb; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xb48002b23e2861d62237348199ff111e310f5dd10298a01562e3a4d41cb6aae6; // AUTO-CONTRACT-ID ../../test_contracts/basic_storage --release +const CONTRACT_ID = 0x27857d650234acd05b5fa9a9bc34abf76fa66d2e6ce8c8b24416805b75005bd0; // AUTO-CONTRACT-ID ../../test_contracts/basic_storage --release fn main() -> u64 { let addr = abi(BasicStorage, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw index af5bdc4cd47..06673118a96 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw @@ -5,7 +5,7 @@ use storage_enum_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xc601d11767195485a6654d566c67774134668863d8c797a8c69e8778fb1f89e9; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x434f5f10c3270134e51a1963f610286466e448c1c6109e4f20502939c7a3d429; // AUTO-CONTRACT-ID ../../test_contracts/storage_enum_contract --release +const CONTRACT_ID = 0x47084a8c1eb453b655842e1b3067ee1f0d9081052bd74ac606efa6ae9a56d901; // AUTO-CONTRACT-ID ../../test_contracts/storage_enum_contract --release fn main() -> u64 { let caller = abi(StorageEnum, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.lock new file mode 100644 index 00000000000..fe96407a20f --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-90F1067CD9AC8A94" + +[[package]] +name = "std" +source = "path+from-root-90F1067CD9AC8A94" +dependencies = ["core"] + +[[package]] +name = "storage_slot_key_calculation" +source = "member" +dependencies = ["std"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.toml new file mode 100644 index 00000000000..cb479a470ea --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.toml @@ -0,0 +1,8 @@ +[project] +name = "storage_slot_key_calculation" +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/src/main.sw new file mode 100644 index 00000000000..a4810dff242 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/src/main.sw @@ -0,0 +1,53 @@ +contract; + +use std::hash::*; + +storage { + a: u8 = 0, + b: u8 = 0, + ns1 { + a: u8 = 0, + b: u8 = 0, + }, + ns2 { + ns3 { + a: u8 = 0, + b: u8 = 0, + }, + }, +} + +abi TestStorageKeyCalculation { + #[storage(read)] + fn test_storage_key_calculation(); +} + +impl TestStorageKeyCalculation for Contract { + #[cfg(experimental_storage_domains = false)] + #[storage(read)] + fn test_storage_key_calculation() { + assert_eq(storage.a.slot(), sha256("storage.a")); + assert_eq(storage.b.slot(), sha256("storage.b")); + assert_eq(storage::ns1.a.slot(), sha256("storage::ns1.a")); + assert_eq(storage::ns1.b.slot(), sha256("storage::ns1.b")); + assert_eq(storage::ns2::ns3.a.slot(), sha256("storage::ns2::ns3.a")); + assert_eq(storage::ns2::ns3.b.slot(), sha256("storage::ns2::ns3.b")); + } + + #[cfg(experimental_storage_domains = true)] + #[storage(read)] + fn test_storage_key_calculation() { + assert_eq(storage.a.slot(), sha256((0u8, "storage.a"))); + assert_eq(storage.b.slot(), sha256((0u8, "storage.b"))); + assert_eq(storage::ns1.a.slot(), sha256((0u8, "storage::ns1.a"))); + assert_eq(storage::ns1.b.slot(), sha256((0u8, "storage::ns1.b"))); + assert_eq(storage::ns2::ns3.a.slot(), sha256((0u8, "storage::ns2::ns3.a"))); + assert_eq(storage::ns2::ns3.b.slot(), sha256((0u8, "storage::ns2::ns3.b"))); + } +} + +#[test] +fn test() { + let caller = abi(TestStorageKeyCalculation, CONTRACT_ID); + caller.test_storage_key_calculation(); +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.storage_domains.toml new file mode 100644 index 00000000000..0890b8a8510 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.storage_domains.toml @@ -0,0 +1 @@ +experimental = { storage_domains = true } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.toml new file mode 100644 index 00000000000..c82484373af --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.toml @@ -0,0 +1,2 @@ +category = "unit_tests_pass" +expected_warnings = 1 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_abi_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_abi_oracle.storage_domains.json new file mode 100644 index 00000000000..2f821ed58f1 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_abi_oracle.storage_domains.json @@ -0,0 +1,297 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d", + "type": "()" + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "type": "b256" + }, + { + "concreteTypeId": "d852149004cc9ec0bbe7dc4e37bffea1d41469b759512b6136f2e865a4c06e7d", + "metadataTypeId": 0, + "type": "enum std::option::Option", + "typeArguments": [ + "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + ] + }, + { + "concreteTypeId": "6906df92e2e485dde893b7d719d621b8910422e7c468f99caa5920e6ac19d9c6", + "metadataTypeId": 3, + "type": "struct basic_storage_abi::Quad" + }, + { + "concreteTypeId": "7880d311d30802b48bd6a100a31adb5af17f94bff12daee556d4f02c1ac5b2ff", + "metadataTypeId": 5, + "type": "struct std::vec::Vec", + "typeArguments": [ + "6906df92e2e485dde893b7d719d621b8910422e7c468f99caa5920e6ac19d9c6" + ] + }, + { + "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", + "type": "u256" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "type": "u64" + }, + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "type": "u8" + } + ], + "configurables": [], + "encodingVersion": "1", + "functions": [ + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "storage_key" + } + ], + "name": "get_u64", + "output": "d852149004cc9ec0bbe7dc4e37bffea1d41469b759512b6136f2e865a4c06e7d" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "slots" + } + ], + "name": "intrinsic_load_quad", + "output": "7880d311d30802b48bd6a100a31adb5af17f94bff12daee556d4f02c1ac5b2ff" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + } + ], + "name": "intrinsic_load_word", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "7880d311d30802b48bd6a100a31adb5af17f94bff12daee556d4f02c1ac5b2ff", + "name": "values" + } + ], + "name": "intrinsic_store_quad", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "value" + } + ], + "name": "intrinsic_store_word", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "value" + } + ], + "name": "store_u64", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "read", + "write" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "test_storage_exhaustive", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + } + ], + "loggedTypes": [ + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "logId": "14454674236531057292" + }, + { + "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", + "logId": "1970142151624111756" + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "logId": "8961848586872524460" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "logId": "1515152261580153489" + } + ], + "messagesTypes": [], + "metadataTypes": [ + { + "components": [ + { + "name": "None", + "typeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "name": "Some", + "typeId": 1 + } + ], + "metadataTypeId": 0, + "type": "enum std::option::Option", + "typeParameters": [ + 1 + ] + }, + { + "metadataTypeId": 1, + "type": "generic T" + }, + { + "metadataTypeId": 2, + "type": "raw untyped ptr" + }, + { + "components": [ + { + "name": "v1", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "v2", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "v3", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "v4", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypeId": 3, + "type": "struct basic_storage_abi::Quad" + }, + { + "components": [ + { + "name": "ptr", + "typeId": 2 + }, + { + "name": "cap", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypeId": 4, + "type": "struct std::vec::RawVec", + "typeParameters": [ + 1 + ] + }, + { + "components": [ + { + "name": "buf", + "typeArguments": [ + { + "name": "", + "typeId": 1 + } + ], + "typeId": 4 + }, + { + "name": "len", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypeId": 5, + "type": "struct std::vec::Vec", + "typeParameters": [ + 1 + ] + } + ], + "programType": "contract", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_storage_slots_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_storage_slots_oracle.storage_domains.json new file mode 100644 index 00000000000..8c0169567bb --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_storage_slots_oracle.storage_domains.json @@ -0,0 +1,58 @@ +[ + { + "key": "040f131e97eaba9c2d25f5c1d6ea9489ce530940dd87d486f8cd9c7ff5360f6c", + "value": "6161616161000000000000000000000000000000000000000000000000000000" + }, + { + "key": "077f64b0ca598a020551265c0faf95f8e860b45700f27c06af3640a123818b17", + "value": "6161000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "2b46310c8d886cf7d9e4339837ecc696ecfaf2c431e56e725c552b92b11c3bc8", + "value": "0000000000000000000000000000000000000000000000000000000001234567" + }, + { + "key": "30226b031f925fbb2a1ad161ce31b798a684c6f52ed49cf84e244d324eceaf58", + "value": "6161616100000000000000000000000000000000000000000000000000000000" + }, + { + "key": "42e97a774f87c61347e7283755a043a5a896d37e801045e8f5ce538b6d1ce8c8", + "value": "0000000000000000000000000000000000000000000000000000000001234567" + }, + { + "key": "78dabd24c80fc40f05bae92654874f2f77bd13ef803fd55ccf014ff5849cdfd0", + "value": "6161616161610000000000000000000000000000000000000000000000000000" + }, + { + "key": "848a0a618b9c374a4b1b47c59ef2f0a01f5c42bb5e805ffd669412ce283b992a", + "value": "6161616161616161000000000000000000000000000000000000000000000000" + }, + { + "key": "84e44dc0900861559343f0fc02dc0d92f7e87872a50e730a85740b701b162863", + "value": "6161616161616100000000000000000000000000000000000000000000000000" + }, + { + "key": "933a534d4af4c376b0b569e8d8a2c62e635e26f403e124cb91d9c42e83d54373", + "value": "0100000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "976540acfef542cb328d6679def3e281cdb1a5bbaca7d9e59a30aa74f3952d90", + "value": "6100000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "9d3f8eb1f2d99b97a2fd6fa68fe7e5a9c5b6734739f8dd84f2ae3da221206a80", + "value": "0000000000000002000000000000000000000000000000000000000000000000" + }, + { + "key": "a42ed3ecc6aaf8d594f165e6c60cdaf172d59436167556f954e6559036736ceb", + "value": "6161610000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "d33763008c92b260fc4381d53aa5976de2b5f991798799fa5edf300bb4a40e02", + "value": "6161616161616161616100000000000000000000000000000000000000000000" + }, + { + "key": "f8fde9e56bb5ab545fdfe17edabb876e6f4cd1b3296d92b266d4acb9ca0b5f79", + "value": "6161616161616161610000000000000000000000000000000000000000000000" + } +] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw index 532709bfed7..251577caf5b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw @@ -296,8 +296,6 @@ fn test_storage() { assert_eq(storage::ns1::ns2.c1.read(), NS1_NS2_C1); assert_eq(storage.c1.slot(), C1KEY); - assert_eq(storage.const_b256.slot(), sha256("storage.const_b256")); - assert_eq(storage::ns1::ns2.c1.slot(), sha256("storage::ns1::ns2.c1")); } // If these comparisons are done inline just above then it blows out the register allocator due to diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.storage_domains.toml new file mode 100644 index 00000000000..0890b8a8510 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.storage_domains.toml @@ -0,0 +1 @@ +experimental = { storage_domains = true } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.toml index 8bce24f6a24..c1349fc15dc 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.toml @@ -1,4 +1,4 @@ category = "compile" validate_abi = true validate_storage_slots = true -expected_warnings = 3 +expected_warnings = 2 # TODO-DCA: Set to zero once https://github.com/FuelLabs/sway/issues/5921 is fixed. diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_abi_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_abi_oracle.storage_domains.json new file mode 100644 index 00000000000..edd98a1f3d1 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_abi_oracle.storage_domains.json @@ -0,0 +1,102 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "d852149004cc9ec0bbe7dc4e37bffea1d41469b759512b6136f2e865a4c06e7d", + "metadataTypeId": 1, + "type": "enum std::option::Option", + "typeArguments": [ + "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + ] + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "type": "u64" + } + ], + "configurables": [], + "encodingVersion": "1", + "functions": [ + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read", + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "increment_by" + } + ], + "name": "increment", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read", + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "d852149004cc9ec0bbe7dc4e37bffea1d41469b759512b6136f2e865a4c06e7d", + "name": "initial_value" + } + ], + "name": "increment_or_not", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "loggedTypes": [], + "messagesTypes": [], + "metadataTypes": [ + { + "metadataTypeId": 0, + "type": "()" + }, + { + "components": [ + { + "name": "None", + "typeId": 0 + }, + { + "name": "Some", + "typeId": 2 + } + ], + "metadataTypeId": 1, + "type": "enum std::option::Option", + "typeParameters": [ + 2 + ] + }, + { + "metadataTypeId": 2, + "type": "generic T" + } + ], + "programType": "contract", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_storage_slots_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_storage_slots_oracle.storage_domains.json new file mode 100644 index 00000000000..efa6132760a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_storage_slots_oracle.storage_domains.json @@ -0,0 +1,6 @@ +[ + { + "key": "d810923c0d6cc6ed49622594d7368eb1e124753474e3ebd52a66c6c2ecb42642", + "value": "0000000000000000000000000000000000000000000000000000000000000000" + } +] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/test.storage_domains.toml new file mode 100644 index 00000000000..24be96bbf31 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/test.storage_domains.toml @@ -0,0 +1 @@ +experimental = { storage_domains = true } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_abi_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_abi_oracle.storage_domains.json new file mode 100644 index 00000000000..9a1f9ebd31e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_abi_oracle.storage_domains.json @@ -0,0 +1,769 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d", + "type": "()" + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "type": "b256" + }, + { + "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", + "type": "bool" + }, + { + "concreteTypeId": "35b24140807b67d1f1675de36775d5d6c62b04f3721f616a9adee739e24c9c15", + "metadataTypeId": 0, + "type": "enum storage_access_abi::E" + }, + { + "concreteTypeId": "893a66eb2f595d7e0cc15e2253da1b6e53fd634ad542b2f1a198a8ae3d8d92b2", + "type": "str[40]" + }, + { + "concreteTypeId": "427fd62288add8763eb5e0c4facf553d877489a3038b29a8a1045e9a853660f0", + "metadataTypeId": 1, + "type": "struct storage_access_abi::S" + }, + { + "concreteTypeId": "74df8abb4a65a07ec7420c0f167703fc6e26c9e43b8036ffacb89d399f13db73", + "metadataTypeId": 2, + "type": "struct storage_access_abi::T" + }, + { + "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", + "type": "u16" + }, + { + "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", + "type": "u32" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "type": "u64" + }, + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "type": "u8" + } + ], + "configurables": [], + "encodingVersion": "1", + "functions": [ + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_boolean", + "output": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_e", + "output": "35b24140807b67d1f1675de36775d5d6c62b04f3721f616a9adee739e24c9c15" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_e2", + "output": "35b24140807b67d1f1675de36775d5d6c62b04f3721f616a9adee739e24c9c15" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_int16", + "output": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_int32", + "output": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_int8", + "output": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s", + "output": "427fd62288add8763eb5e0c4facf553d877489a3038b29a8a1045e9a853660f0" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t", + "output": "74df8abb4a65a07ec7420c0f167703fc6e26c9e43b8036ffacb89d399f13db73" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_boolean", + "output": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_int16", + "output": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_int32", + "output": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_int8", + "output": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_x", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_y", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_z", + "output": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_x", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_y", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_z", + "output": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_string", + "output": "893a66eb2f595d7e0cc15e2253da1b6e53fd634ad542b2f1a198a8ae3d8d92b2" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_x", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_y", + "output": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", + "name": "boolean" + } + ], + "name": "set_boolean", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "35b24140807b67d1f1675de36775d5d6c62b04f3721f616a9adee739e24c9c15", + "name": "e" + } + ], + "name": "set_e", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", + "name": "int16" + } + ], + "name": "set_int16", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", + "name": "int32" + } + ], + "name": "set_int32", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "name": "int8" + } + ], + "name": "set_int8", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "427fd62288add8763eb5e0c4facf553d877489a3038b29a8a1045e9a853660f0", + "name": "s" + } + ], + "name": "set_s", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "74df8abb4a65a07ec7420c0f167703fc6e26c9e43b8036ffacb89d399f13db73", + "name": "t" + } + ], + "name": "set_s_dot_t", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", + "name": "boolean" + } + ], + "name": "set_s_dot_t_dot_boolean", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", + "name": "int16" + } + ], + "name": "set_s_dot_t_dot_int16", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", + "name": "int32" + } + ], + "name": "set_s_dot_t_dot_int32", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "name": "int8" + } + ], + "name": "set_s_dot_t_dot_int8", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "x" + } + ], + "name": "set_s_dot_t_dot_x", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "y" + } + ], + "name": "set_s_dot_t_dot_y", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "z" + } + ], + "name": "set_s_dot_t_dot_z", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "x" + } + ], + "name": "set_s_dot_x", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "y" + } + ], + "name": "set_s_dot_y", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "z" + } + ], + "name": "set_s_dot_z", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "893a66eb2f595d7e0cc15e2253da1b6e53fd634ad542b2f1a198a8ae3d8d92b2", + "name": "string" + } + ], + "name": "set_string", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "x" + } + ], + "name": "set_x", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "y" + } + ], + "name": "set_y", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + } + ], + "loggedTypes": [ + { + "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", + "logId": "13213829929622723620" + } + ], + "messagesTypes": [], + "metadataTypes": [ + { + "components": [ + { + "name": "A", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "B", + "typeId": 2 + } + ], + "metadataTypeId": 0, + "type": "enum storage_access_abi::E" + }, + { + "components": [ + { + "name": "x", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "y", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "z", + "typeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b" + }, + { + "name": "t", + "typeId": 2 + } + ], + "metadataTypeId": 1, + "type": "struct storage_access_abi::S" + }, + { + "components": [ + { + "name": "x", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "y", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "z", + "typeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b" + }, + { + "name": "boolean", + "typeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + }, + { + "name": "int8", + "typeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b" + }, + { + "name": "int16", + "typeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef" + }, + { + "name": "int32", + "typeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc" + } + ], + "metadataTypeId": 2, + "type": "struct storage_access_abi::T" + } + ], + "programType": "contract", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_storage_slots_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_storage_slots_oracle.storage_domains.json new file mode 100644 index 00000000000..ff1eae7956b --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_storage_slots_oracle.storage_domains.json @@ -0,0 +1,74 @@ +[ + { + "key": "419b1120ea993203d7e223dfbe76184322453d6f8de946e827a8669102ab395b", + "value": "0000000000000040000000000000000000000000000000000000000000000000" + }, + { + "key": "4b06f7ce27bc88217a7c9d4300619d2900cef25ecb29a790ec869b02e4191275", + "value": "4141414141414141414141414141414141414141414141414141414141414141" + }, + { + "key": "4b06f7ce27bc88217a7c9d4300619d2900cef25ecb29a790ec869b02e4191276", + "value": "4141414141414141000000000000000000000000000000000000000000000000" + }, + { + "key": "7299da45c4430837636de04fb23f3343a80d88c1dc0455562b3066913f0d7745", + "value": "0000000000000020000000000000000000000000000000000000000000000000" + }, + { + "key": "865b6b6b53f4babe503029163d7076d649da88a10c4ed333d19c645d271f495c", + "value": "0000000000000010000000000000000000000000000000000000000000000000" + }, + { + "key": "8e06966f123f8d6e298f853c70d34036061474c4674b7960119ac4a08a557f0c", + "value": "0000000000000001000000000000000100000000000000020000000000000000" + }, + { + "key": "8e06966f123f8d6e298f853c70d34036061474c4674b7960119ac4a08a557f0d", + "value": "0000000000000000000000000000000000000000000000030100000000000000" + }, + { + "key": "8e06966f123f8d6e298f853c70d34036061474c4674b7960119ac4a08a557f0e", + "value": "0400000000000000000000000000000500000000000000060000000000000000" + }, + { + "key": "9538bea0a4c2601b6bd45782e4c10df5728427e310421d9a5d93f85a1f3704f2", + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "9538bea0a4c2601b6bd45782e4c10df5728427e310421d9a5d93f85a1f3704f3", + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "9538bea0a4c2601b6bd45782e4c10df5728427e310421d9a5d93f85a1f3704f4", + "value": "0000000000000000000000000000000000000000000003090000000000000000" + }, + { + "key": "ae10a55cca3f364be094340b109ccf393d12c2c07417ff2e719b1816ac793c86", + "value": "0000000000000001000000000000000200000000000000000000000000000000" + }, + { + "key": "ae10a55cca3f364be094340b109ccf393d12c2c07417ff2e719b1816ac793c87", + "value": "0000000000000000000000000000000300000000000000040000000000000005" + }, + { + "key": "ae10a55cca3f364be094340b109ccf393d12c2c07417ff2e719b1816ac793c88", + "value": "0000000000000000000000000000000000000000000000000000000000000006" + }, + { + "key": "ae10a55cca3f364be094340b109ccf393d12c2c07417ff2e719b1816ac793c89", + "value": "0100000000000000070000000000000000000000000000080000000000000009" + }, + { + "key": "d871d81721e9905a5cafe5b82dfde0ddb930f96a8e6deb44f92a8c9ce4d24ac1", + "value": "0800000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "e8aaf9a6b72b4eee2bcb2315773bc50e9166ff05c4221843637e25f0424a5dd5", + "value": "0100000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "eb390d9f85c8c849ff8aeb05c865ca66b37ba69a7bec8489b1c467f029b650af", + "value": "0101010101010101010101010101010101010101010101010101010101010101" + } +] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/test.storage_domains.toml new file mode 100644 index 00000000000..24be96bbf31 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/test.storage_domains.toml @@ -0,0 +1 @@ +experimental = { storage_domains = true } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_abi_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_abi_oracle.storage_domains.json new file mode 100644 index 00000000000..32bd4e374ca --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_abi_oracle.storage_domains.json @@ -0,0 +1,31 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "type": "u64" + } + ], + "configurables": [], + "encodingVersion": "1", + "functions": [ + { + "attributes": [ + { + "arguments": [ + "read", + "write" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "read_write_enums", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "loggedTypes": [], + "messagesTypes": [], + "metadataTypes": [], + "programType": "contract", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_storage_slots_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_storage_slots_oracle.storage_domains.json new file mode 100644 index 00000000000..f2d1ca396cb --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_storage_slots_oracle.storage_domains.json @@ -0,0 +1,62 @@ +[ + { + "key": "12f9e955b5b2b5a00c0ebd1320f2cbd0e66c39396b3b3d7ff95c87f4b6e48c0d", + "value": "000000000000000000000000000000cd00000000000000000000000000000000" + }, + { + "key": "23e09d7a09a27d7d9c5c9d0f5191084c19a0a668c60b804a94e99234e6069c7b", + "value": "0000000000000001000000000000aa00000000000000bb00000000000000cc00" + }, + { + "key": "2e7251f5b28dbe052a7f5113d45f3cc2faccf7c955cbc0966089aa0d0059beab", + "value": "0000000000000001000000000000ab00000000000000bc00000000000000cd00" + }, + { + "key": "2e7251f5b28dbe052a7f5113d45f3cc2faccf7c955cbc0966089aa0d0059beac", + "value": "000000000000de00000000000000ef0000000000000000000000000000000000" + }, + { + "key": "2f02e964cd75fddf505a740d9daa11fef5f09b4d17058f893fc0f4e8b2244f53", + "value": "0000000000000000000000000000000100000000000000000000000000000000" + }, + { + "key": "50010301032c3383ef066fbb9ac7c25e3de42bdd5ccaec2d6e0bd26b6531bb0f", + "value": "0000000000000000000000000000000100000000000000000000000000000000" + }, + { + "key": "6b765908aa8ec7bc3a1d73cd252e40fb055de29fb0e9486a16e388cba9fa7c9f", + "value": "00000000000000000000000000000000000000000000000000000000000000ee" + }, + { + "key": "728df923e281e7cb9793c2c2d6419b735161b5e1b8d5ca2065569611418fc194", + "value": "000000000000000100000000000000cd00000000000000000000000000000000" + }, + { + "key": "7ddacb90e6ff09ed9aa4fde095854476123392aab8c73165cc65097b0a2a2578", + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "7ddacb90e6ff09ed9aa4fde095854476123392aab8c73165cc65097b0a2a2579", + "value": "000000000000000000000000000000ff00000000000000000000000000000000" + }, + { + "key": "c20357da738934c36211a22c69d4c44bc7a3b500b07d9e7328c3f0a7c2c426c0", + "value": "0000000000000002000000000000000000000000000000000000000000000000" + }, + { + "key": "d60810fb854958d678015228bfbd5a23a3e1763c1ff90f6790f69fbb85b413c6", + "value": "000000000000000000000000000000ab00000000000000000000000000000000" + }, + { + "key": "d71ff2e9ac87ec91301ee89d18b1dc8991b79753f004ce0810661bd5bfa92bd2", + "value": "0000000000000001000000000000bb0000000000000000000000000000000000" + }, + { + "key": "d9149ae8e217ec10a045c9f83c5bc9d227285fe76b9bcdc8245e6a57a23d0229", + "value": "000000000000000000000000000000aa00000000000000000000000000000000" + }, + { + "key": "e7af73ebbf0ab36c9e30283a504e1326febe010a1b2d0deae9252af8302526a1", + "value": "0000000000000002000000000000000000000000000000000000000000000000" + } +] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/src/main.sw index e604563d4e2..597bed643ce 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/src/main.sw @@ -117,10 +117,6 @@ fn check_s_u8_a(expected: u8) -> u8 { assert(i == expected); return i; }, - _ => { - assert(false); - return 99; - } } } @@ -132,10 +128,6 @@ fn check_s_u64_a(expected: u64) -> u64 { assert(i == expected); return i; }, - _ => { - assert(false); - return 9999; - } } } @@ -147,10 +139,6 @@ fn check_s_bool_a(expected: bool) -> u64 { assert(i == expected); return 171; }, - _ => { - assert(false); - return 9999; - } } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/test.storage_domains.toml new file mode 100644 index 00000000000..24be96bbf31 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/test.storage_domains.toml @@ -0,0 +1 @@ +experimental = { storage_domains = true } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_abi_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_abi_oracle.storage_domains.json new file mode 100644 index 00000000000..a7b039e5eeb --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_abi_oracle.storage_domains.json @@ -0,0 +1,289 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d", + "type": "()" + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "type": "b256" + }, + { + "concreteTypeId": "d852149004cc9ec0bbe7dc4e37bffea1d41469b759512b6136f2e865a4c06e7d", + "metadataTypeId": 0, + "type": "enum std::option::Option", + "typeArguments": [ + "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + ] + }, + { + "concreteTypeId": "6906df92e2e485dde893b7d719d621b8910422e7c468f99caa5920e6ac19d9c6", + "metadataTypeId": 3, + "type": "struct basic_storage_abi::Quad" + }, + { + "concreteTypeId": "7880d311d30802b48bd6a100a31adb5af17f94bff12daee556d4f02c1ac5b2ff", + "metadataTypeId": 5, + "type": "struct std::vec::Vec", + "typeArguments": [ + "6906df92e2e485dde893b7d719d621b8910422e7c468f99caa5920e6ac19d9c6" + ] + }, + { + "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", + "type": "u256" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "type": "u64" + } + ], + "configurables": [], + "encodingVersion": "1", + "functions": [ + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "storage_key" + } + ], + "name": "get_u64", + "output": "d852149004cc9ec0bbe7dc4e37bffea1d41469b759512b6136f2e865a4c06e7d" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "slots" + } + ], + "name": "intrinsic_load_quad", + "output": "7880d311d30802b48bd6a100a31adb5af17f94bff12daee556d4f02c1ac5b2ff" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + } + ], + "name": "intrinsic_load_word", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "7880d311d30802b48bd6a100a31adb5af17f94bff12daee556d4f02c1ac5b2ff", + "name": "values" + } + ], + "name": "intrinsic_store_quad", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "value" + } + ], + "name": "intrinsic_store_word", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "value" + } + ], + "name": "store_u64", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "read", + "write" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "test_storage_exhaustive", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + } + ], + "loggedTypes": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "logId": "1515152261580153489" + }, + { + "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", + "logId": "1970142151624111756" + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "logId": "8961848586872524460" + } + ], + "messagesTypes": [], + "metadataTypes": [ + { + "components": [ + { + "name": "None", + "typeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "name": "Some", + "typeId": 1 + } + ], + "metadataTypeId": 0, + "type": "enum std::option::Option", + "typeParameters": [ + 1 + ] + }, + { + "metadataTypeId": 1, + "type": "generic T" + }, + { + "metadataTypeId": 2, + "type": "raw untyped ptr" + }, + { + "components": [ + { + "name": "v1", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "v2", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "v3", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "v4", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypeId": 3, + "type": "struct basic_storage_abi::Quad" + }, + { + "components": [ + { + "name": "ptr", + "typeId": 2 + }, + { + "name": "cap", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypeId": 4, + "type": "struct std::vec::RawVec", + "typeParameters": [ + 1 + ] + }, + { + "components": [ + { + "name": "buf", + "typeArguments": [ + { + "name": "", + "typeId": 1 + } + ], + "typeId": 4 + }, + { + "name": "len", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypeId": 5, + "type": "struct std::vec::Vec", + "typeParameters": [ + 1 + ] + } + ], + "programType": "contract", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_storage_slots_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_storage_slots_oracle.storage_domains.json new file mode 100644 index 00000000000..30e9e240f7c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_storage_slots_oracle.storage_domains.json @@ -0,0 +1,54 @@ +[ + { + "key": "130875c838ab7f4f039a63d56d8173198d6edade9a61967c93b9d32d93547979", + "value": "6161000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "1997c0b14a3944421bc909d65cdb7f96023661790725e7a06d0bdf211002f9c0", + "value": "6161610000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "1cb08489095e2318cabf34c2c00b0f2b78c151bf4e3caf2a1762778c1b79c052", + "value": "0000000000000001000000000000000000000000000000000000000000000000" + }, + { + "key": "35338f6734c20524ba70780eae61e4dc5398122eab4a3cad9509a3d3ddc1551b", + "value": "0000000000000000000000000000000000000000000000000000000001234567" + }, + { + "key": "55279c57558d3bb1938f803552769ed7dcb3efacd74d9a16cf71d0cfbaab6c0a", + "value": "6161616161616161616100000000000000000000000000000000000000000000" + }, + { + "key": "5d5895256cdf173ecc135c1a18de5133b00b36e5caae538407a883dd44cc0dac", + "value": "0000000000000000000000000000000000000000000000000000000001234567" + }, + { + "key": "5dbeb0e7fc4c2fa3b01b9873d2a4e23488fb486046b6074b4ae463b7bbacbe89", + "value": "6161616161000000000000000000000000000000000000000000000000000000" + }, + { + "key": "659790a8d5d87a599ab69d1a3e6f48ff00c850fb7d24ccd782b209a52e4be83c", + "value": "6161616161616100000000000000000000000000000000000000000000000000" + }, + { + "key": "7aac1eb5fdc9d977b39721c2ccddb3ae405eecac0d8570e3be2d70fe677db4bd", + "value": "6161616161616161610000000000000000000000000000000000000000000000" + }, + { + "key": "8449d22802f944884dd98b791627c4265f4303014d1975f3da48fde003d77936", + "value": "6161616161616161000000000000000000000000000000000000000000000000" + }, + { + "key": "c2f546e9b4a2a37895f7f563be4610aa580468ddd8ba5d3544513965d79eac8a", + "value": "6100000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "e1ba0adcc27d3a21cfe72cc296e282f1c4b9f6798f89ac4e4b8ac95e3ee16d81", + "value": "6161616161610000000000000000000000000000000000000000000000000000" + }, + { + "key": "fdcf008347ae968111d6837c46f05f1a9943e76f6998d51ee1220b4069709a51", + "value": "6161616100000000000000000000000000000000000000000000000000000000" + } +] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.storage_domains.toml new file mode 100644 index 00000000000..24be96bbf31 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.storage_domains.toml @@ -0,0 +1 @@ +experimental = { storage_domains = true } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.toml index 94671fb72d4..a235275de20 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.toml @@ -1,4 +1,4 @@ category = "compile" validate_abi = true validate_storage_slots = true -expected_warnings = 1 +expected_warnings = 1 # TODO-DCA: Set to zero once https://github.com/FuelLabs/sway/issues/5921 is fixed. diff --git a/test/src/ir_generation/mod.rs b/test/src/ir_generation/mod.rs index 8313845fe39..6969ef1c689 100644 --- a/test/src/ir_generation/mod.rs +++ b/test/src/ir_generation/mod.rs @@ -223,7 +223,9 @@ pub(super) async fn run( tracing::info!("Testing {} ...", test_file_name.bold()); let experimental = ExperimentalFeatures { - new_encoding: false, // IR tests still need encoding v1 off + new_encoding: false, // IR tests still need encoding v1 off. + // TODO: Properly support experimental features in IR tests. + ..Default::default() }; // Compile to AST. We need to provide a faux build config otherwise the IR will have From 2b6fd7a53567581ca6e641110f9257ecd2fab173 Mon Sep 17 00:00:00 2001 From: jjcnn <38888011+jjcnn@users.noreply.github.com> Date: Fri, 15 Nov 2024 05:59:45 +0100 Subject: [PATCH 16/52] Fix module visibility check (#6685) ## Description Fixes #6673. The module visibility check has been broken for some time. In some cases, like the one described in #6673, this has resulted in modules being mistakenly regarded as inaccessible, even though they ought to be accessible. In other cases, private modules were mistakenly regarded as accessible. For examples see the updated tests in the PR. The check has now been fixed, and all tests have been updated accordingly. This bugfix can be regarded as a breaking change, because some modules that were deemed accessible before may now be deemed inaccessible and will require the addition of a `pub` keyword in front of the module declaration. ## 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). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --------- Co-authored-by: Joshua Batty Co-authored-by: IGI-111 --- examples/enums/src/main.sw | 2 +- .../src/semantic_analysis/namespace/root.rs | 41 +++++++++++++------ .../language/reexport/aliases/src/main.sw | 24 +++++------ .../src/main.sw | 6 +-- .../src/main.sw | 24 +++++------ .../reexport/simple_glob_import/src/main.sw | 8 ++-- .../reexport/simple_item_import/src/main.sw | 10 +++-- .../should_pass/dca/unused_enum/src/main.sw | 2 +- .../should_pass/dca/unused_trait/src/main.sw | 2 +- .../language/generic_traits/src/main.sw | 4 +- .../import_method_from_other_file/src/main.sw | 2 +- .../src/main.sw | 2 +- .../match_expressions_constants/src/main.sw | 2 +- .../language/module_dep/src/lib.sw | 4 +- .../language/module_dep_multiple/src/lib.sw | 4 +- .../language/reexport/aliases/src/main.sw | 20 ++++----- .../src/main.sw | 24 +++++------ .../reexport/reexport_paths/src/main.sw | 20 ++++----- .../src/main.sw | 24 +++++------ .../reexport/simple_glob_import/src/main.sw | 8 ++-- .../reexport/simple_item_import/src/main.sw | 8 ++-- .../language/reexport/visibility/src/main.sw | 12 +++--- .../language/use_absolute_path/src/main.sw | 2 +- .../should_pass/stdlib/option/src/main.sw | 2 +- .../should_pass/stdlib/result/src/main.sw | 2 +- .../test_contracts/return_struct/src/main.sw | 2 +- 26 files changed, 140 insertions(+), 121 deletions(-) diff --git a/examples/enums/src/main.sw b/examples/enums/src/main.sw index b6804891143..87dbdf428cb 100644 --- a/examples/enums/src/main.sw +++ b/examples/enums/src/main.sw @@ -2,6 +2,6 @@ library; mod basic_enum; mod enum_of_structs; -mod enum_of_enums; +pub mod enum_of_enums; mod enums_avoid; mod enums_preferred; diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 7d4e22b7265..086d91b31aa 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -683,6 +683,10 @@ impl Root { Ok(()) } + /// Check that all accessed modules in the src path are visible from the dst path. + /// If src and dst have a common ancestor module that is private, this privacy modifier is + /// ignored for visibility purposes, since src and dst are both behind that private visibility + /// modifier. Additionally, items in a private module are visible to its immediate parent. fn check_module_privacy( &self, handler: &Handler, @@ -690,20 +694,33 @@ impl Root { src: &ModulePath, dst: &ModulePath, ) -> Result<(), ErrorEmitted> { - // you are always allowed to access your ancestor's symbols - if !is_ancestor(src, dst) { - // we don't check the first prefix because direct children are always accessible - for prefix in iter_prefixes(src).skip(1) { - let module = self.module.lookup_submodule(handler, engines, prefix)?; - if module.visibility().is_private() { - let prefix_last = prefix[prefix.len() - 1].clone(); - handler.emit_err(CompileError::ImportPrivateModule { - span: prefix_last.span(), - name: prefix_last, - }); - } + // Calculate the number of src prefixes whose privacy is ignored. + let mut ignored_prefixes = 0; + + // Ignore visibility of common ancestors + ignored_prefixes += src + .iter() + .zip(dst) + .position(|(src_id, dst_id)| src_id != dst_id) + .unwrap_or(dst.len()); + + // Ignore visibility of direct submodules of the destination module + if dst.len() == ignored_prefixes { + ignored_prefixes += 1; + } + + // Check visibility of remaining submodules in the source path + for prefix in iter_prefixes(src).skip(ignored_prefixes) { + let module = self.module.lookup_submodule(handler, engines, prefix)?; + if module.visibility().is_private() { + let prefix_last = prefix[prefix.len() - 1].clone(); + handler.emit_err(CompileError::ImportPrivateModule { + span: prefix_last.span(), + name: prefix_last, + }); } } + Ok(()) } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/aliases/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/aliases/src/main.sw index d84157a1bce..a8597cf626a 100755 --- a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/aliases/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/aliases/src/main.sw @@ -1,17 +1,17 @@ script; -mod items_1; -mod lib_1; // Aliased item reexports of items_1 -mod items_2; -mod lib_2; // Aliased item reexports of items_2 -mod items_3; -mod lib_3; // Aliased item reexports of items_3 -mod items_4; -mod lib_4_1; // Aliased item reexports of items_4 -mod lib_4_2; // Aliased item reexports of lib_4_1 -mod items_5; -mod lib_5_1; // Aliased trait reexports from items_5 -mod lib_5_2; // Aliased trait reexports from items_5 +pub mod items_1; +pub mod lib_1; // Aliased item reexports of items_1 +pub mod items_2; +pub mod lib_2; // Aliased item reexports of items_2 +pub mod items_3; +pub mod lib_3; // Aliased item reexports of items_3 +pub mod items_4; +pub mod lib_4_1; // Aliased item reexports of items_4 +pub mod lib_4_2; // Aliased item reexports of lib_4_1 +pub mod items_5; +pub mod lib_5_1; // Aliased trait reexports from items_5 +pub mod lib_5_2; // Aliased trait reexports from items_5 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/multiple_imports_of_same_reexport/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/multiple_imports_of_same_reexport/src/main.sw index c4f06aaf84f..29853e98b33 100755 --- a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/multiple_imports_of_same_reexport/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/multiple_imports_of_same_reexport/src/main.sw @@ -1,8 +1,8 @@ script; -mod items_1; -mod lib_1_1; // Item reexports of items_1 -mod lib_1_2; // Item reexports of items_1 +pub mod items_1; +pub mod lib_1_1; // Item reexports of items_1 +pub mod lib_1_2; // Item reexports of items_1 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/shadowing_in_reexporting_module/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/shadowing_in_reexporting_module/src/main.sw index a2961173628..c0290b47faf 100755 --- a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/shadowing_in_reexporting_module/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/shadowing_in_reexporting_module/src/main.sw @@ -1,17 +1,17 @@ script; -mod items_1; -mod lib_1; // Item reexports of items_1 -mod items_2_1; -mod items_2_2; -mod lib_2; // Item reexports of items_2_1 and items_2_2 -mod items_3_1; -mod lib_3; // Item reexports of items_3_1 and items_3_2 -mod items_4_1; -mod items_4_2; -mod items_4_3; -mod items_4_4; -mod lib_4; // Item reexports of items_4_1 and items_4_2 +pub mod items_1; +pub mod lib_1; // Item reexports of items_1 +pub mod items_2_1; +pub mod items_2_2; +pub mod lib_2; // Item reexports of items_2_1 and items_2_2 +pub mod items_3_1; +pub mod lib_3; // Item reexports of items_3_1 and items_3_2 +pub mod items_4_1; +pub mod items_4_2; +pub mod items_4_3; +pub mod items_4_4; +pub mod lib_4; // Item reexports of items_4_1 and items_4_2 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_glob_import/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_glob_import/src/main.sw index 57262307323..fe1ea19f9c1 100755 --- a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_glob_import/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_glob_import/src/main.sw @@ -1,9 +1,9 @@ script; -mod items_1; -mod lib_1; // Item reexports of items_1 -mod items_2; -mod lib_2; // Item reexports of items_1 +pub mod items_1; +pub mod lib_1; // Item reexports of items_1 +pub mod items_2; +pub mod lib_2; // Item reexports of items_1 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_item_import/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_item_import/src/main.sw index 57262307323..8856faf59f6 100755 --- a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_item_import/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_item_import/src/main.sw @@ -1,9 +1,11 @@ script; -mod items_1; -mod lib_1; // Item reexports of items_1 -mod items_2; -mod lib_2; // Item reexports of items_1 +pub mod items_1; +pub mod lib_1; // Item reexports of items_1 +pub mod items_2; +pub mod lib_2; // Item reexports of items_2 +pub mod items_3; +pub mod lib_3; // Item reexports of items_3 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_enum/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_enum/src/main.sw index ef39fb605a9..5fc24d795cf 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_enum/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_enum/src/main.sw @@ -1,6 +1,6 @@ script; -mod r#enum; +pub mod r#enum; mod utils; fn main() { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_trait/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_trait/src/main.sw index 2607dbb987a..7a95e67d0a5 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_trait/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_trait/src/main.sw @@ -1,6 +1,6 @@ script; -mod r#trait; +pub mod r#trait; mod utils; use r#trait::Trait; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_traits/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_traits/src/main.sw index 3e5e72a76e3..f050a4cc0fc 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_traits/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_traits/src/main.sw @@ -4,9 +4,9 @@ script; // but until then, multiple methods with the same name is undefined behavior. // https://doc.rust-lang.org/rust-by-example/trait/disambiguating.html -mod my_double; +pub mod my_double; mod my_point; -mod my_triple; +pub mod my_triple; use my_point::MyPoint; use my_triple::MyTriple; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/import_method_from_other_file/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/import_method_from_other_file/src/main.sw index 136515fc5c3..1f0fbad59be 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/import_method_from_other_file/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/import_method_from_other_file/src/main.sw @@ -1,7 +1,7 @@ script; mod context; -mod asset; +pub mod asset; mod utils; use context::Context; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/import_with_different_callpaths/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/import_with_different_callpaths/src/main.sw index 29e6fe78ddf..d672a617d81 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/import_with_different_callpaths/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/import_with_different_callpaths/src/main.sw @@ -1,6 +1,6 @@ script; -mod data_structures; +pub mod data_structures; mod eq_impls; use eq_impls::*; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/main.sw index ffa92ace5e7..df1535977a6 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/main.sw @@ -1,6 +1,6 @@ script; -mod lib; +pub mod lib; mod top_level; mod in_structs; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep/src/lib.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep/src/lib.sw index e59f07dba62..94d40f22f5b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep/src/lib.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep/src/lib.sw @@ -1,7 +1,7 @@ library; -mod a; -mod b; +pub mod a; +pub mod b; fn main() -> u32 { 1 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep_multiple/src/lib.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep_multiple/src/lib.sw index 06ceb2f6e8b..db23337b474 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep_multiple/src/lib.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep_multiple/src/lib.sw @@ -1,8 +1,8 @@ library; mod c; -mod a; -mod b; +pub mod a; +pub mod b; fn main() -> u32 { 1 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/aliases/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/aliases/src/main.sw index 18a842fa725..b1a1ee9b298 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/aliases/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/aliases/src/main.sw @@ -1,15 +1,15 @@ script; -mod items_1; -mod lib_1; // Aliased item reexports of items_1 -mod items_2; -mod lib_2; // Aliased item reexports of items_2 -mod items_3; -mod lib_3_1; // Aliased item reexports of items_3 -mod lib_3_2; // Aliased item reexports of lib_3_1 -mod items_4; -mod lib_4_1; // Aliased item reexports of items_4 -mod lib_4_2; // Aliased item reexports of items_4 with different aliases +pub mod items_1; +pub mod lib_1; // Aliased item reexports of items_1 +pub mod items_2; +pub mod lib_2; // Aliased item reexports of items_2 +pub mod items_3; +pub mod lib_3_1; // Aliased item reexports of items_3 +pub mod lib_3_2; // Aliased item reexports of lib_3_1 +pub mod items_4; +pub mod lib_4_1; // Aliased item reexports of items_4 +pub mod lib_4_2; // Aliased item reexports of items_4 with different aliases mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/multiple_imports_of_same_reexport/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/multiple_imports_of_same_reexport/src/main.sw index 4ae46fbab15..01cd29bb68c 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/multiple_imports_of_same_reexport/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/multiple_imports_of_same_reexport/src/main.sw @@ -1,17 +1,17 @@ script; -mod items_1; -mod lib_1_1; // Item reexports of items_1 -mod lib_1_2; // Item reexports of items_1 -mod items_2; -mod lib_2_1; // Star reexports of items_2 -mod lib_2_2; // Star reexports of items_2 -mod items_3; -mod lib_3_1; // Star reexports of items_3 -mod lib_3_2; // Item reexports of items_3 -mod items_4; -mod lib_4_1; // Item reexports of items_4 -mod lib_4_2; // Star reexports of items_4 +pub mod items_1; +pub mod lib_1_1; // Item reexports of items_1 +pub mod lib_1_2; // Item reexports of items_1 +pub mod items_2; +pub mod lib_2_1; // Star reexports of items_2 +pub mod lib_2_2; // Star reexports of items_2 +pub mod items_3; +pub mod lib_3_1; // Star reexports of items_3 +pub mod lib_3_2; // Item reexports of items_3 +pub mod items_4; +pub mod lib_4_1; // Item reexports of items_4 +pub mod lib_4_2; // Star reexports of items_4 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/reexport_paths/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/reexport_paths/src/main.sw index 84a4dffa3df..738e0d7b893 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/reexport_paths/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/reexport_paths/src/main.sw @@ -1,15 +1,15 @@ script; -mod items_1; -mod lib_1_1; // Reexports of items_1 -mod lib_1_2; // Reexports of lib_1_1 -mod lib_2; // Reexports of std::hash::Hasher, which is not part of the std prelude -mod lib_3_1; // Reexports of std::hash::Hash, which is not part of the std prelude -mod lib_3_2; // Reexports of std::hash::Hash, which is not part of the std prelude -mod lib_4; // Reexport of std::registers::global_gas -mod lib_5; // Reexport of core::codec::* -//mod lib_6_1; // Reexports of std::address::Address from the std prelude -mod lib_6_2; // Reexports of std::address::Address directly from std::address +pub mod items_1; +pub mod lib_1_1; // Reexports of items_1 +pub mod lib_1_2; // Reexports of lib_1_1 +pub mod lib_2; // Reexports of std::hash::Hasher, which is not part of the std prelude +pub mod lib_3_1; // Reexports of std::hash::Hash, which is not part of the std prelude +pub mod lib_3_2; // Reexports of std::hash::Hash, which is not part of the std prelude +pub mod lib_4; // Reexport of std::registers::global_gas +pub mod lib_5; // Reexport of core::codec::* +//pub mod lib_6_1; // Reexports of std::address::Address from the std prelude +pub mod lib_6_2; // Reexports of std::address::Address directly from std::address mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/shadowing_in_reexporting_module/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/shadowing_in_reexporting_module/src/main.sw index a2961173628..c0290b47faf 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/shadowing_in_reexporting_module/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/shadowing_in_reexporting_module/src/main.sw @@ -1,17 +1,17 @@ script; -mod items_1; -mod lib_1; // Item reexports of items_1 -mod items_2_1; -mod items_2_2; -mod lib_2; // Item reexports of items_2_1 and items_2_2 -mod items_3_1; -mod lib_3; // Item reexports of items_3_1 and items_3_2 -mod items_4_1; -mod items_4_2; -mod items_4_3; -mod items_4_4; -mod lib_4; // Item reexports of items_4_1 and items_4_2 +pub mod items_1; +pub mod lib_1; // Item reexports of items_1 +pub mod items_2_1; +pub mod items_2_2; +pub mod lib_2; // Item reexports of items_2_1 and items_2_2 +pub mod items_3_1; +pub mod lib_3; // Item reexports of items_3_1 and items_3_2 +pub mod items_4_1; +pub mod items_4_2; +pub mod items_4_3; +pub mod items_4_4; +pub mod lib_4; // Item reexports of items_4_1 and items_4_2 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_glob_import/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_glob_import/src/main.sw index 57262307323..fe1ea19f9c1 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_glob_import/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_glob_import/src/main.sw @@ -1,9 +1,9 @@ script; -mod items_1; -mod lib_1; // Item reexports of items_1 -mod items_2; -mod lib_2; // Item reexports of items_1 +pub mod items_1; +pub mod lib_1; // Item reexports of items_1 +pub mod items_2; +pub mod lib_2; // Item reexports of items_1 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_item_import/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_item_import/src/main.sw index 0b3777176d7..6470ef09668 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_item_import/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_item_import/src/main.sw @@ -1,9 +1,9 @@ script; -mod items_1; -mod lib_1; // Item reexports of items_1 -mod items_2; -mod lib_2; // Item reexports of items_2 +pub mod items_1; +pub mod lib_1; // Item reexports of items_1 +pub mod items_2; +pub mod lib_2; // Item reexports of items_2 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/visibility/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/visibility/src/main.sw index 078a2114541..55d7e81f033 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/visibility/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/visibility/src/main.sw @@ -1,11 +1,11 @@ script; -mod items_1; -mod lib_1_1; // Item reexports of items_1 -mod lib_1_2; // Item imports without reexport of items_1 -mod items_2; -mod lib_2_1; // Item imports without reexport of items_1 -mod lib_2_2; // Item reexports of items_1 +pub mod items_1; +pub mod lib_1_1; // Item reexports of items_1 +pub mod lib_1_2; // Item imports without reexport of items_1 +pub mod items_2; +pub mod lib_2_1; // Item imports without reexport of items_1 +pub mod lib_2_2; // Item reexports of items_1 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/use_absolute_path/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/use_absolute_path/src/main.sw index ce2c888d964..4dd52fdef97 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/use_absolute_path/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/use_absolute_path/src/main.sw @@ -1,6 +1,6 @@ script; -mod r#trait; +pub mod r#trait; mod foo; use ::foo::*; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option/src/main.sw index f37ed2f5bff..ea66b079683 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option/src/main.sw @@ -1,6 +1,6 @@ script; -mod data_structures; +pub mod data_structures; mod tests; use tests::*; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/result/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/result/src/main.sw index f37ed2f5bff..ea66b079683 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/result/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/result/src/main.sw @@ -1,6 +1,6 @@ script; -mod data_structures; +pub mod data_structures; mod tests; use tests::*; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/return_struct/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/return_struct/src/main.sw index 1dd7e0293ea..92e93915701 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/return_struct/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/return_struct/src/main.sw @@ -1,6 +1,6 @@ contract; -mod data_structures; +pub mod data_structures; mod interface; use interface::MyContract; From 1dfca80d7cc7bba9aa936b9dfbab3dbf8c3bb760 Mon Sep 17 00:00:00 2001 From: Cameron Carstens Date: Fri, 15 Nov 2024 13:17:02 +0700 Subject: [PATCH 17/52] Make `OrdEq` trait public (#6723) ## Description An internal contributor noted that the `OrdEq` trait was private. Although it could be used if implemented on the `impl` statement directly, this has been made public to allow for importing through the `use` statement. ## 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). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --------- Co-authored-by: Joshua Batty Co-authored-by: IGI-111 --- .../src/tests/expects/impl_trait/mod.rs | 205 +++++++++--------- sway-lib-core/src/ops.sw | 2 +- 2 files changed, 104 insertions(+), 103 deletions(-) diff --git a/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs b/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs index d68364e7e4f..602b66f49d7 100644 --- a/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs +++ b/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs @@ -36,131 +36,132 @@ fn test_impl_traits_default() { assert_search_js( &doc_path, &expect![[r#" - var SEARCH_INDEX={"core":[{"html_filename":"trait.AsRawSlice.html","module_info":["core","raw_slice"],"name":"AsRawSlice","preview":"Trait to return a type as a raw_slice.\n","type_name":"trait"},{"html_filename":"fn.from_str_array.html","module_info":["core","str"],"name":"from_str_array","preview":"","type_name":"function"},{"html_filename":"trait.Add.html","module_info":["core","ops"],"name":"Add","preview":"Trait for the addition of two values.\n","type_name":"trait"},{"html_filename":"trait.Subtract.html","module_info":["core","ops"],"name":"Subtract","preview":"Trait for the subtraction of two values.\n","type_name":"trait"},{"html_filename":"trait.Multiply.html","module_info":["core","ops"],"name":"Multiply","preview":"Trait for the multiplication of two values.\n","type_name":"trait"},{"html_filename":"trait.Divide.html","module_info":["core","ops"],"name":"Divide","preview":"Trait for the division of two values.\n","type_name":"trait"},{"html_filename":"trait.Mod.html","module_info":["core","ops"],"name":"Mod","preview":"Trait for the modulo of two values.\n","type_name":"trait"},{"html_filename":"trait.Not.html","module_info":["core","ops"],"name":"Not","preview":"Trait to invert a type.\n","type_name":"trait"},{"html_filename":"trait.Eq.html","module_info":["core","ops"],"name":"Eq","preview":"Trait to evaluate if two types are equal.\n","type_name":"trait"},{"html_filename":"trait.Ord.html","module_info":["core","ops"],"name":"Ord","preview":"Trait to evaluate if one value is greater or less than another of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseAnd.html","module_info":["core","ops"],"name":"BitwiseAnd","preview":"Trait to bitwise AND two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseOr.html","module_info":["core","ops"],"name":"BitwiseOr","preview":"Trait to bitwise OR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseXor.html","module_info":["core","ops"],"name":"BitwiseXor","preview":"Trait to bitwise XOR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.Shift.html","module_info":["core","ops"],"name":"Shift","preview":"Trait to bit shift a value.\n","type_name":"trait"},{"html_filename":"trait.TotalOrd.html","module_info":["core","ops"],"name":"TotalOrd","preview":"Trait to compare values of the same type.\n","type_name":"trait"},{"html_filename":"fn.ok_str_eq.html","module_info":["core","ops"],"name":"ok_str_eq","preview":"","type_name":"function"},{"html_filename":"struct.StorageKey.html","module_info":["core","storage"],"name":"StorageKey","preview":"Describes a location in storage.\n","type_name":"struct"},{"html_filename":"struct.Buffer.html","module_info":["core","codec"],"name":"Buffer","preview":"","type_name":"struct"},{"html_filename":"struct.BufferReader.html","module_info":["core","codec"],"name":"BufferReader","preview":"","type_name":"struct"},{"html_filename":"trait.AbiDecode.html","module_info":["core","codec"],"name":"AbiDecode","preview":"","type_name":"trait"},{"html_filename":"trait.AbiEncode.html","module_info":["core","codec"],"name":"AbiEncode","preview":"","type_name":"trait"},{"html_filename":"fn.encode.html","module_info":["core","codec"],"name":"encode","preview":"","type_name":"function"},{"html_filename":"fn.abi_decode.html","module_info":["core","codec"],"name":"abi_decode","preview":"","type_name":"function"},{"html_filename":"fn.abi_decode_in_place.html","module_info":["core","codec"],"name":"abi_decode_in_place","preview":"","type_name":"function"},{"html_filename":"fn.contract_call.html","module_info":["core","codec"],"name":"contract_call","preview":"","type_name":"function"},{"html_filename":"fn.decode_script_data.html","module_info":["core","codec"],"name":"decode_script_data","preview":"","type_name":"function"},{"html_filename":"fn.decode_predicate_data.html","module_info":["core","codec"],"name":"decode_predicate_data","preview":"","type_name":"function"},{"html_filename":"fn.decode_predicate_data_by_index.html","module_info":["core","codec"],"name":"decode_predicate_data_by_index","preview":"","type_name":"function"},{"html_filename":"fn.decode_first_param.html","module_info":["core","codec"],"name":"decode_first_param","preview":"","type_name":"function"},{"html_filename":"fn.decode_second_param.html","module_info":["core","codec"],"name":"decode_second_param","preview":"","type_name":"function"},{"html_filename":"primitive.u256.html","module_info":["core"],"name":"u256","preview":"256-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u64.html","module_info":["core"],"name":"u64","preview":"64-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u32.html","module_info":["core"],"name":"u32","preview":"32-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u16.html","module_info":["core"],"name":"u16","preview":"16-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u8.html","module_info":["core"],"name":"u8","preview":"8-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.b256.html","module_info":["core"],"name":"b256","preview":"256 bits (32 bytes), i.e. a hash","type_name":"primitive"},{"html_filename":"primitive.str.html","module_info":["core"],"name":"str","preview":"string slice","type_name":"primitive"},{"html_filename":"primitive.bool.html","module_info":["core"],"name":"bool","preview":"Boolean true or false","type_name":"primitive"},{"html_filename":"primitive.str[0].html","module_info":["core"],"name":"str[0]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[1].html","module_info":["core"],"name":"str[1]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[2].html","module_info":["core"],"name":"str[2]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[3].html","module_info":["core"],"name":"str[3]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[4].html","module_info":["core"],"name":"str[4]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[5].html","module_info":["core"],"name":"str[5]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[6].html","module_info":["core"],"name":"str[6]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[7].html","module_info":["core"],"name":"str[7]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[8].html","module_info":["core"],"name":"str[8]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[9].html","module_info":["core"],"name":"str[9]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[10].html","module_info":["core"],"name":"str[10]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[11].html","module_info":["core"],"name":"str[11]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[12].html","module_info":["core"],"name":"str[12]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[13].html","module_info":["core"],"name":"str[13]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[14].html","module_info":["core"],"name":"str[14]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[15].html","module_info":["core"],"name":"str[15]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[16].html","module_info":["core"],"name":"str[16]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[17].html","module_info":["core"],"name":"str[17]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[18].html","module_info":["core"],"name":"str[18]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[19].html","module_info":["core"],"name":"str[19]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[20].html","module_info":["core"],"name":"str[20]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[21].html","module_info":["core"],"name":"str[21]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[22].html","module_info":["core"],"name":"str[22]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[23].html","module_info":["core"],"name":"str[23]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[24].html","module_info":["core"],"name":"str[24]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[25].html","module_info":["core"],"name":"str[25]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[26].html","module_info":["core"],"name":"str[26]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[27].html","module_info":["core"],"name":"str[27]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[28].html","module_info":["core"],"name":"str[28]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[29].html","module_info":["core"],"name":"str[29]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[30].html","module_info":["core"],"name":"str[30]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[31].html","module_info":["core"],"name":"str[31]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[32].html","module_info":["core"],"name":"str[32]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[33].html","module_info":["core"],"name":"str[33]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[34].html","module_info":["core"],"name":"str[34]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[35].html","module_info":["core"],"name":"str[35]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[36].html","module_info":["core"],"name":"str[36]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[37].html","module_info":["core"],"name":"str[37]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[38].html","module_info":["core"],"name":"str[38]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[39].html","module_info":["core"],"name":"str[39]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[40].html","module_info":["core"],"name":"str[40]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[41].html","module_info":["core"],"name":"str[41]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[42].html","module_info":["core"],"name":"str[42]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[43].html","module_info":["core"],"name":"str[43]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[44].html","module_info":["core"],"name":"str[44]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[45].html","module_info":["core"],"name":"str[45]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[46].html","module_info":["core"],"name":"str[46]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[47].html","module_info":["core"],"name":"str[47]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[48].html","module_info":["core"],"name":"str[48]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[49].html","module_info":["core"],"name":"str[49]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[50].html","module_info":["core"],"name":"str[50]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[51].html","module_info":["core"],"name":"str[51]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[52].html","module_info":["core"],"name":"str[52]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[53].html","module_info":["core"],"name":"str[53]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[54].html","module_info":["core"],"name":"str[54]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[55].html","module_info":["core"],"name":"str[55]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[56].html","module_info":["core"],"name":"str[56]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[57].html","module_info":["core"],"name":"str[57]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[58].html","module_info":["core"],"name":"str[58]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[59].html","module_info":["core"],"name":"str[59]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[60].html","module_info":["core"],"name":"str[60]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[61].html","module_info":["core"],"name":"str[61]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[62].html","module_info":["core"],"name":"str[62]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[63].html","module_info":["core"],"name":"str[63]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[64].html","module_info":["core"],"name":"str[64]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"index.html","module_info":["core"],"name":"core","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","codec"],"name":"codec","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","ops"],"name":"ops","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","raw_slice"],"name":"raw_slice","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","storage"],"name":"storage","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","str"],"name":"str","preview":"","type_name":"module"}],"impl_traits":[{"html_filename":"trait.Foo.html","module_info":["impl_traits","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits","bar"],"name":"Bar","preview":"","type_name":"struct"},{"html_filename":"index.html","module_info":["impl_traits","bar"],"name":"bar","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["impl_traits","foo"],"name":"foo","preview":"","type_name":"module"}]}; + var SEARCH_INDEX={"core":[{"html_filename":"trait.AsRawSlice.html","module_info":["core","raw_slice"],"name":"AsRawSlice","preview":"Trait to return a type as a raw_slice.\n","type_name":"trait"},{"html_filename":"fn.from_str_array.html","module_info":["core","str"],"name":"from_str_array","preview":"","type_name":"function"},{"html_filename":"trait.Add.html","module_info":["core","ops"],"name":"Add","preview":"Trait for the addition of two values.\n","type_name":"trait"},{"html_filename":"trait.Subtract.html","module_info":["core","ops"],"name":"Subtract","preview":"Trait for the subtraction of two values.\n","type_name":"trait"},{"html_filename":"trait.Multiply.html","module_info":["core","ops"],"name":"Multiply","preview":"Trait for the multiplication of two values.\n","type_name":"trait"},{"html_filename":"trait.Divide.html","module_info":["core","ops"],"name":"Divide","preview":"Trait for the division of two values.\n","type_name":"trait"},{"html_filename":"trait.Mod.html","module_info":["core","ops"],"name":"Mod","preview":"Trait for the modulo of two values.\n","type_name":"trait"},{"html_filename":"trait.Not.html","module_info":["core","ops"],"name":"Not","preview":"Trait to invert a type.\n","type_name":"trait"},{"html_filename":"trait.Eq.html","module_info":["core","ops"],"name":"Eq","preview":"Trait to evaluate if two types are equal.\n","type_name":"trait"},{"html_filename":"trait.Ord.html","module_info":["core","ops"],"name":"Ord","preview":"Trait to evaluate if one value is greater or less than another of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseAnd.html","module_info":["core","ops"],"name":"BitwiseAnd","preview":"Trait to bitwise AND two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseOr.html","module_info":["core","ops"],"name":"BitwiseOr","preview":"Trait to bitwise OR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseXor.html","module_info":["core","ops"],"name":"BitwiseXor","preview":"Trait to bitwise XOR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.OrdEq.html","module_info":["core","ops"],"name":"OrdEq","preview":"Trait to evaluate if one value is greater than or equal, or less than or equal to another of the same type.","type_name":"trait"},{"html_filename":"trait.Shift.html","module_info":["core","ops"],"name":"Shift","preview":"Trait to bit shift a value.\n","type_name":"trait"},{"html_filename":"trait.TotalOrd.html","module_info":["core","ops"],"name":"TotalOrd","preview":"Trait to compare values of the same type.\n","type_name":"trait"},{"html_filename":"fn.ok_str_eq.html","module_info":["core","ops"],"name":"ok_str_eq","preview":"","type_name":"function"},{"html_filename":"struct.StorageKey.html","module_info":["core","storage"],"name":"StorageKey","preview":"Describes a location in storage.\n","type_name":"struct"},{"html_filename":"struct.Buffer.html","module_info":["core","codec"],"name":"Buffer","preview":"","type_name":"struct"},{"html_filename":"struct.BufferReader.html","module_info":["core","codec"],"name":"BufferReader","preview":"","type_name":"struct"},{"html_filename":"trait.AbiDecode.html","module_info":["core","codec"],"name":"AbiDecode","preview":"","type_name":"trait"},{"html_filename":"trait.AbiEncode.html","module_info":["core","codec"],"name":"AbiEncode","preview":"","type_name":"trait"},{"html_filename":"fn.encode.html","module_info":["core","codec"],"name":"encode","preview":"","type_name":"function"},{"html_filename":"fn.abi_decode.html","module_info":["core","codec"],"name":"abi_decode","preview":"","type_name":"function"},{"html_filename":"fn.abi_decode_in_place.html","module_info":["core","codec"],"name":"abi_decode_in_place","preview":"","type_name":"function"},{"html_filename":"fn.contract_call.html","module_info":["core","codec"],"name":"contract_call","preview":"","type_name":"function"},{"html_filename":"fn.decode_script_data.html","module_info":["core","codec"],"name":"decode_script_data","preview":"","type_name":"function"},{"html_filename":"fn.decode_predicate_data.html","module_info":["core","codec"],"name":"decode_predicate_data","preview":"","type_name":"function"},{"html_filename":"fn.decode_predicate_data_by_index.html","module_info":["core","codec"],"name":"decode_predicate_data_by_index","preview":"","type_name":"function"},{"html_filename":"fn.decode_first_param.html","module_info":["core","codec"],"name":"decode_first_param","preview":"","type_name":"function"},{"html_filename":"fn.decode_second_param.html","module_info":["core","codec"],"name":"decode_second_param","preview":"","type_name":"function"},{"html_filename":"primitive.u256.html","module_info":["core"],"name":"u256","preview":"256-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u64.html","module_info":["core"],"name":"u64","preview":"64-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u32.html","module_info":["core"],"name":"u32","preview":"32-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u16.html","module_info":["core"],"name":"u16","preview":"16-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u8.html","module_info":["core"],"name":"u8","preview":"8-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.b256.html","module_info":["core"],"name":"b256","preview":"256 bits (32 bytes), i.e. a hash","type_name":"primitive"},{"html_filename":"primitive.str.html","module_info":["core"],"name":"str","preview":"string slice","type_name":"primitive"},{"html_filename":"primitive.bool.html","module_info":["core"],"name":"bool","preview":"Boolean true or false","type_name":"primitive"},{"html_filename":"primitive.str[0].html","module_info":["core"],"name":"str[0]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[1].html","module_info":["core"],"name":"str[1]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[2].html","module_info":["core"],"name":"str[2]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[3].html","module_info":["core"],"name":"str[3]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[4].html","module_info":["core"],"name":"str[4]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[5].html","module_info":["core"],"name":"str[5]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[6].html","module_info":["core"],"name":"str[6]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[7].html","module_info":["core"],"name":"str[7]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[8].html","module_info":["core"],"name":"str[8]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[9].html","module_info":["core"],"name":"str[9]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[10].html","module_info":["core"],"name":"str[10]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[11].html","module_info":["core"],"name":"str[11]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[12].html","module_info":["core"],"name":"str[12]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[13].html","module_info":["core"],"name":"str[13]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[14].html","module_info":["core"],"name":"str[14]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[15].html","module_info":["core"],"name":"str[15]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[16].html","module_info":["core"],"name":"str[16]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[17].html","module_info":["core"],"name":"str[17]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[18].html","module_info":["core"],"name":"str[18]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[19].html","module_info":["core"],"name":"str[19]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[20].html","module_info":["core"],"name":"str[20]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[21].html","module_info":["core"],"name":"str[21]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[22].html","module_info":["core"],"name":"str[22]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[23].html","module_info":["core"],"name":"str[23]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[24].html","module_info":["core"],"name":"str[24]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[25].html","module_info":["core"],"name":"str[25]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[26].html","module_info":["core"],"name":"str[26]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[27].html","module_info":["core"],"name":"str[27]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[28].html","module_info":["core"],"name":"str[28]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[29].html","module_info":["core"],"name":"str[29]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[30].html","module_info":["core"],"name":"str[30]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[31].html","module_info":["core"],"name":"str[31]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[32].html","module_info":["core"],"name":"str[32]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[33].html","module_info":["core"],"name":"str[33]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[34].html","module_info":["core"],"name":"str[34]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[35].html","module_info":["core"],"name":"str[35]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[36].html","module_info":["core"],"name":"str[36]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[37].html","module_info":["core"],"name":"str[37]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[38].html","module_info":["core"],"name":"str[38]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[39].html","module_info":["core"],"name":"str[39]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[40].html","module_info":["core"],"name":"str[40]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[41].html","module_info":["core"],"name":"str[41]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[42].html","module_info":["core"],"name":"str[42]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[43].html","module_info":["core"],"name":"str[43]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[44].html","module_info":["core"],"name":"str[44]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[45].html","module_info":["core"],"name":"str[45]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[46].html","module_info":["core"],"name":"str[46]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[47].html","module_info":["core"],"name":"str[47]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[48].html","module_info":["core"],"name":"str[48]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[49].html","module_info":["core"],"name":"str[49]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[50].html","module_info":["core"],"name":"str[50]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[51].html","module_info":["core"],"name":"str[51]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[52].html","module_info":["core"],"name":"str[52]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[53].html","module_info":["core"],"name":"str[53]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[54].html","module_info":["core"],"name":"str[54]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[55].html","module_info":["core"],"name":"str[55]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[56].html","module_info":["core"],"name":"str[56]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[57].html","module_info":["core"],"name":"str[57]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[58].html","module_info":["core"],"name":"str[58]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[59].html","module_info":["core"],"name":"str[59]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[60].html","module_info":["core"],"name":"str[60]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[61].html","module_info":["core"],"name":"str[61]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[62].html","module_info":["core"],"name":"str[62]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[63].html","module_info":["core"],"name":"str[63]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[64].html","module_info":["core"],"name":"str[64]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"index.html","module_info":["core"],"name":"core","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","codec"],"name":"codec","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","ops"],"name":"ops","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","raw_slice"],"name":"raw_slice","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","storage"],"name":"storage","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","str"],"name":"str","preview":"","type_name":"module"}],"impl_traits":[{"html_filename":"trait.Foo.html","module_info":["impl_traits","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits","bar"],"name":"Bar","preview":"","type_name":"struct"},{"html_filename":"index.html","module_info":["impl_traits","bar"],"name":"bar","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["impl_traits","foo"],"name":"foo","preview":"","type_name":"module"}]}; "object"==typeof exports&&"undefined"!=typeof module&&(module.exports=SEARCH_INDEX);"#]], ); assert_file_tree( doc_dir_name, project_name, vec![ - "core/primitive.str[26].html", - "core/primitive.str[54].html", - "core/primitive.u256.html", - "core/primitive.str[2].html", - "core/primitive.u8.html", + "core/ops/trait.TotalOrd.html", + "core/ops/trait.Mod.html", + "impl_traits/bar/index.html", + "impl_traits/all.html", "core/primitive.str[17].html", - "core/primitive.str[49].html", + "core/primitive.str[51].html", + "core/codec/fn.abi_decode.html", + "core/codec/struct.Buffer.html", + "core/codec/trait.AbiDecode.html", + "core/ops/trait.Divide.html", + "core/codec/fn.abi_decode_in_place.html", "core/primitive.str[34].html", - "core/primitive.str[46].html", - "core/primitive.str[15].html", - "core/primitive.str[21].html", - "core/primitive.str.html", - "core/primitive.str[24].html", - "core/primitive.str[38].html", - "core/primitive.str[47].html", - "core/primitive.str[31].html", - "core/primitive.bool.html", - "core/primitive.str[14].html", - "core/primitive.str[48].html", - "core/primitive.str[1].html", - "core/primitive.str[42].html", - "core/primitive.str[6].html", - "core/primitive.b256.html", - "core/primitive.str[5].html", - "core/primitive.str[43].html", + "core/codec/fn.decode_first_param.html", + "core/primitive.str[20].html", "core/primitive.str[4].html", - "core/primitive.str[19].html", - "core/primitive.str[25].html", - "core/primitive.str[57].html", - "core/primitive.str[56].html", + "core/primitive.str[42].html", "core/primitive.str[10].html", - "core/primitive.str[44].html", + "core/ops/trait.Subtract.html", + "core/primitive.str[28].html", + "core/primitive.u8.html", + "core/primitive.u256.html", + "core/str/fn.from_str_array.html", + "core/primitive.str[62].html", + "core/primitive.str[64].html", + "core/codec/trait.AbiEncode.html", + "core/primitive.str[8].html", + "core/primitive.str[43].html", + "core/codec/fn.decode_predicate_data_by_index.html", "core/primitive.str[37].html", - "core/primitive.str[0].html", - "core/primitive.str[53].html", - "core/primitive.str[59].html", - "core/primitive.str[22].html", - "core/primitive.str[33].html", - "core/primitive.str[27].html", - "core/primitive.str[13].html", + "core/primitive.b256.html", + "core/ops/trait.Eq.html", + "core/storage/index.html", + "core/primitive.str[58].html", + "core/primitive.str[44].html", + "core/raw_slice/index.html", "core/primitive.u16.html", - "core/primitive.str[3].html", "core/primitive.str[35].html", - "core/primitive.str[7].html", - "core/primitive.str[51].html", - "core/primitive.str[40].html", - "core/primitive.str[28].html", - "core/primitive.str[41].html", - "core/primitive.str[58].html", - "core/primitive.str[45].html", - "core/primitive.str[62].html", - "core/primitive.str[63].html", "core/primitive.str[60].html", - "core/primitive.str[50].html", - "core/primitive.str[55].html", - "core/primitive.str[8].html", - "core/primitive.str[32].html", - "core/primitive.str[23].html", - "core/primitive.str[30].html", - "core/primitive.str[61].html", - "core/primitive.str[18].html", - "core/primitive.u32.html", - "core/primitive.str[64].html", + "core/primitive.str[59].html", "core/primitive.str[39].html", - "core/primitive.str[29].html", - "core/primitive.str[11].html", - "core/primitive.str[20].html", - "core/primitive.str[9].html", - "core/primitive.str[12].html", + "core/primitive.str[49].html", + "core/primitive.str[40].html", + "core/index.html", + "search.js", + "core/ops/trait.OrdEq.html", + "core/primitive.bool.html", + "impl_traits/foo/trait.Baz.html", + "core/primitive.str.html", + "core/primitive.str[13].html", "core/primitive.u64.html", "core/primitive.str[16].html", - "core/primitive.str[36].html", - "core/primitive.str[52].html", - "core/all.html", - "core/codec/fn.abi_decode.html", - "core/codec/fn.abi_decode_in_place.html", - "core/codec/fn.contract_call.html", - "core/codec/fn.decode_predicate_data.html", - "core/codec/fn.decode_predicate_data_by_index.html", - "core/codec/fn.decode_first_param.html", - "core/codec/fn.decode_script_data.html", - "core/codec/fn.decode_second_param.html", - "core/codec/fn.encode.html", "core/codec/index.html", - "core/codec/struct.Buffer.html", - "core/codec/struct.BufferReader.html", - "core/codec/trait.AbiDecode.html", - "core/codec/trait.AbiEncode.html", - "core/index.html", - "core/ops/fn.ok_str_eq.html", + "core/primitive.str[47].html", + "core/primitive.str[57].html", + "core/ops/trait.Not.html", + "core/primitive.str[50].html", + "core/raw_slice/trait.AsRawSlice.html", + "core/primitive.str[24].html", + "core/primitive.str[56].html", "core/ops/index.html", - "core/ops/trait.Add.html", + "core/primitive.str[3].html", + "core/primitive.str[36].html", + "core/primitive.str[27].html", + "core/codec/fn.decode_script_data.html", + "impl_traits/index.html", + "core/primitive.str[12].html", + "impl_traits/foo/trait.Foo.html", + "core/primitive.str[15].html", + "core/primitive.str[29].html", + "core/primitive.str[22].html", "core/ops/trait.BitwiseAnd.html", - "core/ops/trait.BitwiseOr.html", - "core/ops/trait.BitwiseXor.html", - "core/ops/trait.Divide.html", - "core/ops/trait.Eq.html", - "core/ops/trait.Mod.html", - "core/ops/trait.Multiply.html", - "core/ops/trait.Not.html", + "core/all.html", + "core/primitive.str[11].html", "core/ops/trait.Ord.html", - "core/ops/trait.Shift.html", - "core/ops/trait.Subtract.html", - "core/ops/trait.TotalOrd.html", - "core/raw_slice/index.html", - "core/raw_slice/trait.AsRawSlice.html", - "core/storage/index.html", - "core/storage/struct.StorageKey.html", - "core/str/fn.from_str_array.html", "core/str/index.html", - "impl_traits/all.html", - "impl_traits/bar/index.html", - "impl_traits/bar/struct.Bar.html", + "core/primitive.str[31].html", "impl_traits/foo/index.html", - "impl_traits/foo/trait.Baz.html", - "impl_traits/foo/trait.Foo.html", - "impl_traits/index.html", - "search.js", + "core/primitive.str[55].html", + "core/primitive.str[38].html", + "core/codec/struct.BufferReader.html", + "core/primitive.str[54].html", + "core/primitive.str[53].html", + "core/primitive.str[19].html", + "core/storage/struct.StorageKey.html", + "core/primitive.str[25].html", + "core/primitive.str[30].html", + "core/codec/fn.encode.html", + "core/primitive.str[26].html", + "core/primitive.str[41].html", + "core/codec/fn.decode_second_param.html", + "core/primitive.u32.html", + "core/ops/fn.ok_str_eq.html", + "core/primitive.str[1].html", + "core/primitive.str[18].html", + "core/primitive.str[33].html", + "core/primitive.str[0].html", + "core/codec/fn.decode_predicate_data.html", + "core/primitive.str[9].html", + "core/ops/trait.Shift.html", + "core/ops/trait.Multiply.html", + "core/primitive.str[32].html", + "core/primitive.str[46].html", + "core/primitive.str[7].html", + "core/primitive.str[14].html", + "core/ops/trait.Add.html", + "core/primitive.str[23].html", + "core/primitive.str[52].html", + "core/primitive.str[48].html", + "core/primitive.str[2].html", + "core/primitive.str[5].html", + "impl_traits/bar/struct.Bar.html", + "core/primitive.str[63].html", + "core/primitive.str[21].html", + "core/codec/fn.contract_call.html", + "core/ops/trait.BitwiseXor.html", + "core/primitive.str[61].html", + "core/primitive.str[45].html", + "core/ops/trait.BitwiseOr.html", + "core/primitive.str[6].html", ], ); } diff --git a/sway-lib-core/src/ops.sw b/sway-lib-core/src/ops.sw index 371bbff5382..c49147bccae 100644 --- a/sway-lib-core/src/ops.sw +++ b/sway-lib-core/src/ops.sw @@ -995,7 +995,7 @@ impl BitwiseXor for u8 { } /// Trait to evaluate if one value is greater than or equal, or less than or equal to another of the same type. -trait OrdEq: Ord + Eq { +pub trait OrdEq: Ord + Eq { } { /// Evaluates if one value of the same type is greater or equal to than another. /// From 9741809659e44a7519a2a1e7c28225a5366fffe9 Mon Sep 17 00:00:00 2001 From: Vaivaswatha N Date: Mon, 18 Nov 2024 12:33:47 +0530 Subject: [PATCH 18/52] Add configurables section offset in the preamble (#6709) Re-enabling this feature after a bugfix. (reverted PR: #6522) --------- Co-authored-by: Sophie Dankel <47993817+sdankel@users.noreply.github.com> Co-authored-by: IGI-111 --- forc-pkg/src/pkg.rs | 30 ++- .../deployed_script-loader-abi.json | 24 +-- forc-plugins/forc-client/tests/deploy.rs | 8 +- forc-test/src/execute.rs | 25 ++- forc/src/cli/commands/parse_bytecode.rs | 8 + forc/tests/cli_integration.rs | 8 +- sway-core/src/asm_generation/finalized_asm.rs | 67 ++++-- .../allocated_abstract_instruction_set.rs | 29 ++- .../src/asm_generation/fuel/data_section.rs | 191 +++++++++++++----- .../asm_generation/fuel/fuel_asm_builder.rs | 23 ++- .../src/asm_generation/fuel/functions.rs | 22 +- .../asm_generation/fuel/programs/abstract.rs | 46 +++-- sway-core/src/asm_lang/allocated_ops.rs | 63 ++++-- sway-core/src/asm_lang/mod.rs | 11 + sway-core/src/asm_lang/virtual_ops.rs | 8 + sway-core/src/lib.rs | 22 ++ .../json_abi_oracle_new_encoding.json | 32 +-- .../configurable_dedup_decode/stdout.snap | 3 +- .../json_abi_oracle_new_encoding.json | 2 +- .../array_of_structs_caller/src/main.sw | 2 +- .../asset_ops_test/src/main.sw | 4 +- .../bal_opcode/src/main.sw | 2 +- .../call_abi_with_tuples/src/main.sw | 2 +- .../call_basic_storage/src/main.sw | 2 +- .../src/main.sw | 2 +- .../call_increment_contract/src/main.sw | 2 +- .../call_storage_enum/src/main.sw | 2 +- .../caller_auth_test/src/main.sw | 2 +- .../caller_context_test/src/main.sw | 2 +- .../nested_struct_args_caller/src/main.sw | 2 +- .../storage_access_caller/src/main.sw | 2 +- .../src/sdk-harness/test_projects/auth/mod.rs | 4 +- 32 files changed, 463 insertions(+), 189 deletions(-) diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index ab4733949b8..49829a2a321 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -46,7 +46,7 @@ use sway_core::{ transform::AttributeKind, write_dwarf, BuildTarget, Engines, FinalizedEntry, LspConfig, }; -use sway_core::{PrintAsm, PrintIr}; +use sway_core::{set_bytecode_configurables_offset, PrintAsm, PrintIr}; use sway_error::{error::CompileError, handler::Handler, warning::CompileWarning}; use sway_features::ExperimentalFeatures; use sway_types::constants::{CORE, PRELUDE, STD}; @@ -1928,7 +1928,7 @@ pub fn compile( let errored = handler.has_errors() || (handler.has_warnings() && profile.error_on_warnings); - let compiled = match bc_res { + let mut compiled = match bc_res { Ok(compiled) if !errored => compiled, _ => return fail(handler), }; @@ -1937,9 +1937,12 @@ pub fn compile( print_warnings(engines.se(), terse_mode, &pkg.name, &warnings, &tree_type); + // Metadata to be placed into the binary. + let mut md = [0u8, 0, 0, 0, 0, 0, 0, 0]; // TODO: This should probably be in `fuel_abi_json::generate_json_abi_program`? // If ABI requires knowing config offsets, they should be inputs to ABI gen. if let ProgramABI::Fuel(ref mut program_abi) = program_abi { + let mut configurables_offset = compiled.bytecode.len() as u64; if let Some(ref mut configurables) = program_abi.configurables { // Filter out all dead configurables (i.e. ones without offsets in the bytecode) configurables.retain(|c| { @@ -1948,12 +1951,22 @@ pub fn compile( .contains_key(&c.name) }); // Set the actual offsets in the JSON object - for (config, offset) in compiled.named_data_section_entries_offsets { - if let Some(idx) = configurables.iter().position(|c| c.name == config) { - configurables[idx].offset = offset; + for (config, offset) in &compiled.named_data_section_entries_offsets { + if *offset < configurables_offset { + configurables_offset = *offset; + } + if let Some(idx) = configurables.iter().position(|c| &c.name == config) { + configurables[idx].offset = *offset; } } } + + md = configurables_offset.to_be_bytes(); + } + + // We know to set the metadata only for fuelvm right now. + if let BuildTarget::Fuel = pkg.target { + set_bytecode_configurables_offset(&mut compiled, &md); } metrics.bytecode_size = compiled.bytecode.len(); @@ -2034,11 +2047,10 @@ fn report_assembly_information( used: compiled_asm .0 .data_section - .value_pairs - .iter() - .map(calculate_entry_size) + .iter_all_entries() + .map(|entry| calculate_entry_size(&entry)) .sum(), - value_pairs: compiled_asm.0.data_section.value_pairs.clone(), + value_pairs: compiled_asm.0.data_section.iter_all_entries().collect(), }, }; diff --git a/forc-plugins/forc-client/test/data/deployed_script/deployed_script-loader-abi.json b/forc-plugins/forc-client/test/data/deployed_script/deployed_script-loader-abi.json index 81b65c43cd7..c51c80ae2e9 100644 --- a/forc-plugins/forc-client/test/data/deployed_script/deployed_script-loader-abi.json +++ b/forc-plugins/forc-client/test/data/deployed_script/deployed_script-loader-abi.json @@ -251,62 +251,62 @@ { "name": "BOOL", "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", - "offset": 136 + "offset": 240 }, { "name": "U8", "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", - "offset": 248 + "offset": 352 }, { "name": "U16", "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", - "offset": 192 + "offset": 296 }, { "name": "U32", "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", - "offset": 232 + "offset": 336 }, { "name": "U64", "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", - "offset": 240 + "offset": 344 }, { "name": "U256", "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", - "offset": 200 + "offset": 304 }, { "name": "B256", "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", - "offset": 104 + "offset": 208 }, { "name": "STR_4", "concreteTypeId": "94f0fa95c830be5e4f711963e83259fe7e8bc723278ab6ec34449e791a99b53a", - "offset": 176 + "offset": 280 }, { "name": "TUPLE", "concreteTypeId": "e0128f7be9902d1fe16326cafe703b52038064a7997b03ebfc1c9dd607e1536c", - "offset": 184 + "offset": 288 }, { "name": "ARRAY", "concreteTypeId": "d9fac01ab38fe10950758ae9604da330d6406a71fda3ef1ea818121261132d56", - "offset": 88 + "offset": 192 }, { "name": "STRUCT", "concreteTypeId": "563310524b4f4447a10d0e50556310253dfb3b5eb4b29c3773222b737c8b7075", - "offset": 160 + "offset": 264 }, { "name": "ENUM", "concreteTypeId": "37cd1cba311039a851ac8bfa614cc41359b4ad95c8656fcef2e8f504fe7a1272", - "offset": 144 + "offset": 248 } ] } \ No newline at end of file diff --git a/forc-plugins/forc-client/tests/deploy.rs b/forc-plugins/forc-client/tests/deploy.rs index b06d6aa96ed..0784111e146 100644 --- a/forc-plugins/forc-client/tests/deploy.rs +++ b/forc-plugins/forc-client/tests/deploy.rs @@ -373,7 +373,7 @@ async fn test_simple_deploy() { node.kill().unwrap(); let expected = vec![DeployedPackage::Contract(DeployedContract { id: ContractId::from_str( - "5a4d19b92e784817f3e4f7d7c9961c5cba3069e53dcee2a93e8cd723e555c5f3", + "5c51b8904c539700852c646c6700fddab4b80477f66e56fb2515736facd84e69", ) .unwrap(), proxy: None, @@ -416,7 +416,7 @@ async fn test_deploy_submit_only() { node.kill().unwrap(); let expected = vec![DeployedPackage::Contract(DeployedContract { id: ContractId::from_str( - "5a4d19b92e784817f3e4f7d7c9961c5cba3069e53dcee2a93e8cd723e555c5f3", + "5c51b8904c539700852c646c6700fddab4b80477f66e56fb2515736facd84e69", ) .unwrap(), proxy: None, @@ -462,12 +462,12 @@ async fn test_deploy_fresh_proxy() { node.kill().unwrap(); let impl_contract = DeployedPackage::Contract(DeployedContract { id: ContractId::from_str( - "5a4d19b92e784817f3e4f7d7c9961c5cba3069e53dcee2a93e8cd723e555c5f3", + "5c51b8904c539700852c646c6700fddab4b80477f66e56fb2515736facd84e69", ) .unwrap(), proxy: Some( ContractId::from_str( - "f0641246d72044059de56248becf345bd8553c7892df8c12d7df23f461a7f95b", + "7a78517c2c3322028db65e54893dc97958fa3d7c846a66f5675859e64f927540", ) .unwrap(), ), diff --git a/forc-test/src/execute.rs b/forc-test/src/execute.rs index 3436261af94..76e89324903 100644 --- a/forc-test/src/execute.rs +++ b/forc-test/src/execute.rs @@ -9,7 +9,7 @@ use fuel_vm::{ self as vm, checked_transaction::builder::TransactionBuilderExt, interpreter::{Interpreter, NotSupportedEcal}, - prelude::{Instruction, SecretKey}, + prelude::SecretKey, storage::MemoryStorage, }; use rand::{Rng, SeedableRng}; @@ -246,18 +246,21 @@ impl TestExecutor { /// The following is how the beginning of the bytecode is laid out: /// /// ```ignore -/// [0] ji i4 ; Jumps to the data section setup. -/// [1] noop -/// [2] DATA_SECTION_OFFSET[0..32] -/// [3] DATA_SECTION_OFFSET[32..64] -/// [4] lw $ds $is 1 ; The data section setup, i.e. where the first ji lands. -/// [5] add $$ds $$ds $is -/// [6] ; This is where we want to jump from to our test code! +/// [ 0] ji i(4 + 2) ; Jumps to the data section setup. +/// [ 1] noop +/// [ 2] DATA_SECTION_OFFSET[0..32] +/// [ 3] DATA_SECTION_OFFSET[32..64] +/// [ 4] CONFIGURABLES_OFFSET[0..32] +/// [ 5] CONFIGURABLES_OFFSET[32..64] +/// [ 6] lw $ds $is 1 ; The data section setup, i.e. where the first ji lands. +/// [ 7] add $$ds $$ds $is +/// [ 8] ; This is where we want to jump from to our test code! /// ``` fn patch_test_bytecode(bytecode: &[u8], test_offset: u32) -> std::borrow::Cow<[u8]> { - // TODO: Standardize this or add metadata to bytecode. - const PROGRAM_START_INST_OFFSET: u32 = 6; - const PROGRAM_START_BYTE_OFFSET: usize = PROGRAM_START_INST_OFFSET as usize * Instruction::SIZE; + // Each instruction is 4 bytes, + // so we divide the total byte-size by 4 to get the instruction offset. + const PROGRAM_START_INST_OFFSET: u32 = (sway_core::PRELUDE_SIZE_IN_BYTES / 4) as u32; + const PROGRAM_START_BYTE_OFFSET: usize = sway_core::PRELUDE_SIZE_IN_BYTES; // If our desired entry point is the program start, no need to jump. if test_offset == PROGRAM_START_INST_OFFSET { diff --git a/forc/src/cli/commands/parse_bytecode.rs b/forc/src/cli/commands/parse_bytecode.rs index f4a30c82d6d..4d5ecf0bdb6 100644 --- a/forc/src/cli/commands/parse_bytecode.rs +++ b/forc/src/cli/commands/parse_bytecode.rs @@ -59,6 +59,14 @@ pub(crate) fn exec(command: Command) -> ForcResult<()> { parsed_raw ) } + Err(fuel_asm::InvalidOpcode) if word_ix == 4 || word_ix == 5 => { + let parsed_raw = u32::from_be_bytes([raw[0], raw[1], raw[2], raw[3]]); + format!( + "configurables offset {} ({})", + if word_ix == 4 { "lo" } else { "hi" }, + parsed_raw + ) + } Ok(_) | Err(fuel_asm::InvalidOpcode) => "".into(), }; table.add_row(Row::new(vec![ diff --git a/forc/tests/cli_integration.rs b/forc/tests/cli_integration.rs index 1f1248a2205..422e9f18f9c 100644 --- a/forc/tests/cli_integration.rs +++ b/forc/tests/cli_integration.rs @@ -49,10 +49,10 @@ fn test_forc_test_raw_logs() -> Result<(), rexpect::error::Error> { // Assert that the output is correct process.exp_string(" test test_log_4")?; process.exp_string("Raw logs:")?; - process.exp_string(r#"[{"LogData":{"data":"0000000000000004","digest":"8005f02d43fa06e7d0585fb64c961d57e318b27a145c857bcd3a6bdb413ff7fc","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12664,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; + process.exp_string(r#"[{"LogData":{"data":"0000000000000004","digest":"8005f02d43fa06e7d0585fb64c961d57e318b27a145c857bcd3a6bdb413ff7fc","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12672,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; process.exp_string(" test test_log_2")?; process.exp_string("Raw logs:")?; - process.exp_string(r#"[{"LogData":{"data":"0000000000000002","digest":"cd04a4754498e06db5a13c5f371f1f04ff6d2470f24aa9bd886540e5dce77f70","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12664,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; + process.exp_string(r#"[{"LogData":{"data":"0000000000000002","digest":"cd04a4754498e06db5a13c5f371f1f04ff6d2470f24aa9bd886540e5dce77f70","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12672,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; process.process.exit()?; Ok(()) @@ -74,11 +74,11 @@ fn test_forc_test_both_logs() -> Result<(), rexpect::error::Error> { process.exp_string(" test test_log_4")?; process.exp_string("Decoded log value: 4, log rb: 1515152261580153489")?; process.exp_string("Raw logs:")?; - process.exp_string(r#"[{"LogData":{"data":"0000000000000004","digest":"8005f02d43fa06e7d0585fb64c961d57e318b27a145c857bcd3a6bdb413ff7fc","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12664,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; + process.exp_string(r#"[{"LogData":{"data":"0000000000000004","digest":"8005f02d43fa06e7d0585fb64c961d57e318b27a145c857bcd3a6bdb413ff7fc","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12672,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; process.exp_string(" test test_log_2")?; process.exp_string("Decoded log value: 2, log rb: 1515152261580153489")?; process.exp_string("Raw logs:")?; - process.exp_string(r#"[{"LogData":{"data":"0000000000000002","digest":"cd04a4754498e06db5a13c5f371f1f04ff6d2470f24aa9bd886540e5dce77f70","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12664,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; + process.exp_string(r#"[{"LogData":{"data":"0000000000000002","digest":"cd04a4754498e06db5a13c5f371f1f04ff6d2470f24aa9bd886540e5dce77f70","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12672,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; process.process.exit()?; Ok(()) } diff --git a/sway-core/src/asm_generation/finalized_asm.rs b/sway-core/src/asm_generation/finalized_asm.rs index 1bb66535693..936127d7554 100644 --- a/sway-core/src/asm_generation/finalized_asm.rs +++ b/sway-core/src/asm_generation/finalized_asm.rs @@ -3,8 +3,8 @@ use super::{ fuel::{checks, data_section::DataSection}, ProgramABI, ProgramKind, }; -use crate::asm_generation::fuel::data_section::{DataId, Datum, Entry}; -use crate::asm_lang::allocated_ops::{AllocatedOp, AllocatedOpcode}; +use crate::asm_generation::fuel::data_section::{Datum, Entry, EntryName}; +use crate::asm_lang::allocated_ops::{AllocatedOp, AllocatedOpcode, FuelAsmData}; use crate::decl_engine::DeclRefFunction; use crate::source_map::SourceMap; use crate::BuildConfig; @@ -16,7 +16,6 @@ use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::span::Span; use sway_types::SourceEngine; -use either::Either; use std::{collections::BTreeMap, fmt}; /// Represents an ASM set which has had register allocation, jump elimination, and optimization @@ -130,6 +129,8 @@ fn to_bytecode_mut( { 8 } + AllocatedOpcode::AddrDataId(_, _data_id) => 8, + AllocatedOpcode::ConfigurablesOffsetPlaceholder => 8, AllocatedOpcode::DataSectionOffsetPlaceholder => 8, AllocatedOpcode::BLOB(count) => count.value as u64 * 4, AllocatedOpcode::CFEI(i) | AllocatedOpcode::CFSI(i) if i.value == 0 => 0, @@ -159,6 +160,29 @@ fn to_bytecode_mut( &ops_padded }; + let mut offset_from_instr_start = 0; + for op in ops.iter() { + match &op.opcode { + AllocatedOpcode::LoadDataId(_reg, data_label) + if !data_section + .has_copy_type(data_label) + .expect("data label references non existent data -- internal error") => + { + // For non-copy type loads, pre-insert pointers into the data_section so that + // from this point on, the data_section remains immutable. This is necessary + // so that when we take addresses of configurables, that address doesn't change + // later on if a non-configurable is added to the data-section. + let offset_bytes = data_section.data_id_to_offset(data_label) as u64; + // The -4 is because $pc is added in the *next* instruction. + let pointer_offset_from_current_instr = + offset_to_data_section_in_bytes - offset_from_instr_start + offset_bytes - 4; + data_section.append_pointer(pointer_offset_from_current_instr); + } + _ => (), + } + offset_from_instr_start += op_size_in_bytes(data_section, op); + } + let mut bytecode = Vec::with_capacity(offset_to_data_section_in_bytes as usize); if build_config.print_bytecode { @@ -184,7 +208,7 @@ fn to_bytecode_mut( offset_from_instr_start += op_size_in_bytes(data_section, op); match fuel_op { - Either::Right(data) => { + FuelAsmData::DatasectionOffset(data) => { if build_config.print_bytecode { print!("{}{:#010x} ", " ".repeat(indentation), bytecode.len()); println!( @@ -200,7 +224,23 @@ fn to_bytecode_mut( bytecode.extend(data.iter().cloned()); half_word_ix += 2; } - Either::Left(instructions) => { + FuelAsmData::ConfigurablesOffset(data) => { + if build_config.print_bytecode { + print!("{}{:#010x} ", " ".repeat(indentation), bytecode.len()); + println!( + " ;; {:?}", + data + ); + } + + // Static assert to ensure that we're only dealing with ConfigurablesOffsetPlaceholder, + // a 1-word (8 bytes) data within the code. No other uses are known. + let _: [u8; 8] = data; + + bytecode.extend(data.iter().cloned()); + half_word_ix += 2; + } + FuelAsmData::Instructions(instructions) => { for instruction in instructions { // Print original source span only once if build_config.print_bytecode_spans { @@ -313,9 +353,9 @@ fn to_bytecode_mut( }; } - for (i, entry) in data_section.value_pairs.iter().enumerate() { - let entry_offset = data_section.data_id_to_offset(&DataId(i as u32)); - print_entry(indentation, offset + entry_offset, entry); + for (i, entry) in data_section.iter_all_entries().enumerate() { + let entry_offset = data_section.absolute_idx_to_offset(i); + print_entry(indentation, offset + entry_offset, &entry); } println!(";; --- END OF TARGET BYTECODE ---\n"); @@ -324,16 +364,19 @@ fn to_bytecode_mut( assert_eq!(half_word_ix * 4, offset_to_data_section_in_bytes as usize); assert_eq!(bytecode.len(), offset_to_data_section_in_bytes as usize); + let num_nonconfigurables = data_section.non_configurables.len(); let named_data_section_entries_offsets = data_section - .value_pairs + .configurables .iter() .enumerate() - .filter(|entry| entry.1.name.is_some()) .map(|(id, entry)| { + let EntryName::Configurable(name) = &entry.name else { + panic!("Non-configurable in configurables part of datasection"); + }; ( - entry.name.as_ref().unwrap().clone(), + name.clone(), offset_to_data_section_in_bytes - + data_section.raw_data_id_to_offset(id as u32) as u64, + + data_section.absolute_idx_to_offset(id + num_nonconfigurables) as u64, ) }) .collect::>(); diff --git a/sway-core/src/asm_generation/fuel/allocated_abstract_instruction_set.rs b/sway-core/src/asm_generation/fuel/allocated_abstract_instruction_set.rs index 0865687f5c8..e939ef633a2 100644 --- a/sway-core/src/asm_generation/fuel/allocated_abstract_instruction_set.rs +++ b/sway-core/src/asm_generation/fuel/allocated_abstract_instruction_set.rs @@ -1,7 +1,10 @@ -use crate::asm_lang::{ - allocated_ops::{AllocatedOpcode, AllocatedRegister}, - AllocatedAbstractOp, ConstantRegister, ControlFlowOp, Label, RealizedOp, VirtualImmediate12, - VirtualImmediate18, VirtualImmediate24, +use crate::{ + asm_generation::fuel::data_section::EntryName, + asm_lang::{ + allocated_ops::{AllocatedOpcode, AllocatedRegister}, + AllocatedAbstractOp, ConstantRegister, ControlFlowOp, Label, RealizedOp, + VirtualImmediate12, VirtualImmediate18, VirtualImmediate24, + }, }; use super::{ @@ -348,6 +351,13 @@ impl AllocatedAbstractInstructionSet { comment: String::new(), }); } + ControlFlowOp::ConfigurablesOffsetPlaceholder => { + realized_ops.push(RealizedOp { + opcode: AllocatedOpcode::ConfigurablesOffsetPlaceholder, + owning_span: None, + comment: String::new(), + }); + } ControlFlowOp::LoadLabel(r1, ref lab) => { // LoadLabel ops are inserted by `rewrite_far_jumps`. // So the next instruction must be a relative jump. @@ -363,8 +373,11 @@ impl AllocatedAbstractInstructionSet { // We compute the relative offset w.r.t the actual jump. // Sub 1 because the relative jumps add a 1. let offset = rel_offset(curr_offset + 1, lab) - 1; - let data_id = - data_section.insert_data_value(Entry::new_word(offset, None, None)); + let data_id = data_section.insert_data_value(Entry::new_word( + offset, + EntryName::NonConfigurable, + None, + )); realized_ops.push(RealizedOp { opcode: AllocatedOpcode::LoadDataId(r1, data_id), owning_span, @@ -444,6 +457,8 @@ impl AllocatedAbstractInstructionSet { } } + Either::Left(AllocatedOpcode::AddrDataId(_, ref _data_id)) => 2, + // cfei 0 and cfsi 0 are omitted from asm emission, don't count them for offsets Either::Left(AllocatedOpcode::CFEI(ref op)) | Either::Left(AllocatedOpcode::CFSI(ref op)) @@ -473,6 +488,8 @@ impl AllocatedAbstractInstructionSet { 2 } + Either::Right(ConfigurablesOffsetPlaceholder) => 2, + Either::Right(PushAll(_)) | Either::Right(PopAll(_)) => unreachable!( "fix me, pushall and popall don't really belong in control flow ops \ since they're not about control flow" diff --git a/sway-core/src/asm_generation/fuel/data_section.rs b/sway-core/src/asm_generation/fuel/data_section.rs index 76f3300c705..86cb5a1133a 100644 --- a/sway-core/src/asm_generation/fuel/data_section.rs +++ b/sway-core/src/asm_generation/fuel/data_section.rs @@ -1,16 +1,30 @@ +use rustc_hash::FxHashMap; use sway_ir::{size_bytes_round_up_to_word_alignment, Constant, ConstantValue, Context, Padding}; use std::{fmt, iter::repeat}; +#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] +pub enum EntryName { + NonConfigurable, + Configurable(String), +} + +impl fmt::Display for EntryName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + EntryName::NonConfigurable => write!(f, "NonConfigurable"), + EntryName::Configurable(name) => write!(f, "", name), + } + } +} + // An entry in the data section. It's important for the size to be correct, especially for unions // where the size could be larger than the represented value. #[derive(Clone, Debug, serde::Serialize)] pub struct Entry { pub value: Datum, pub padding: Padding, - // It is assumed, for now, that only configuration-time constants have a name. Otherwise, this - // is `None`. - pub name: Option, + pub name: EntryName, } #[derive(Clone, Debug, serde::Serialize)] @@ -23,7 +37,7 @@ pub enum Datum { } impl Entry { - pub(crate) fn new_byte(value: u8, name: Option, padding: Option) -> Entry { + pub(crate) fn new_byte(value: u8, name: EntryName, padding: Option) -> Entry { Entry { value: Datum::Byte(value), padding: padding.unwrap_or(Padding::default_for_u8(value)), @@ -31,7 +45,7 @@ impl Entry { } } - pub(crate) fn new_word(value: u64, name: Option, padding: Option) -> Entry { + pub(crate) fn new_word(value: u64, name: EntryName, padding: Option) -> Entry { Entry { value: Datum::Word(value), padding: padding.unwrap_or(Padding::default_for_u64(value)), @@ -41,7 +55,7 @@ impl Entry { pub(crate) fn new_byte_array( bytes: Vec, - name: Option, + name: EntryName, padding: Option, ) -> Entry { Entry { @@ -51,11 +65,7 @@ impl Entry { } } - pub(crate) fn new_slice( - bytes: Vec, - name: Option, - padding: Option, - ) -> Entry { + pub(crate) fn new_slice(bytes: Vec, name: EntryName, padding: Option) -> Entry { Entry { padding: padding.unwrap_or(Padding::default_for_byte_array(&bytes)), value: Datum::Slice(bytes), @@ -65,7 +75,7 @@ impl Entry { pub(crate) fn new_collection( elements: Vec, - name: Option, + name: EntryName, padding: Option, ) -> Entry { Entry { @@ -80,7 +90,7 @@ impl Entry { pub(crate) fn from_constant( context: &Context, constant: &Constant, - name: Option, + name: EntryName, padding: Option, ) -> Entry { // We need a special handling in case of enums. @@ -89,8 +99,9 @@ impl Entry { .enum_tag_and_value_with_paddings(context) .expect("Constant is an enum."); - let tag_entry = Entry::from_constant(context, tag.0, None, tag.1); - let value_entry = Entry::from_constant(context, value.0, None, value.1); + let tag_entry = Entry::from_constant(context, tag.0, EntryName::NonConfigurable, tag.1); + let value_entry = + Entry::from_constant(context, value.0, EntryName::NonConfigurable, value.1); return Entry::new_collection(vec![tag_entry, value_entry], name, padding); } @@ -118,7 +129,9 @@ impl Entry { .array_elements_with_padding(context) .expect("Constant is an array.") .into_iter() - .map(|(elem, padding)| Entry::from_constant(context, elem, None, padding)) + .map(|(elem, padding)| { + Entry::from_constant(context, elem, EntryName::NonConfigurable, padding) + }) .collect(), name, padding, @@ -128,7 +141,9 @@ impl Entry { .struct_fields_with_padding(context) .expect("Constant is a struct.") .into_iter() - .map(|(elem, padding)| Entry::from_constant(context, elem, None, padding)) + .map(|(elem, padding)| { + Entry::from_constant(context, elem, EntryName::NonConfigurable, padding) + }) .collect(), name, padding, @@ -198,45 +213,92 @@ impl Entry { } } +#[derive(Clone, Debug)] +pub enum DataIdEntryKind { + NonConfigurable, + Configurable, +} + +impl fmt::Display for DataIdEntryKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DataIdEntryKind::NonConfigurable => write!(f, "NonConfigurable"), + DataIdEntryKind::Configurable => write!(f, "Configurable"), + } + } +} + /// An address which refers to a value in the data section of the asm. #[derive(Clone, Debug)] -pub(crate) struct DataId(pub(crate) u32); +pub(crate) struct DataId { + pub(crate) idx: u32, + pub(crate) kind: DataIdEntryKind, +} impl fmt::Display for DataId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "data_{}", self.0) + write!(f, "data_{}_{}", self.kind, self.idx) } } +/// The data to be put in the data section of the asm #[derive(Default, Clone, Debug)] pub struct DataSection { - /// the data to be put in the data section of the asm - pub value_pairs: Vec, + pub non_configurables: Vec, + pub configurables: Vec, + pub(crate) pointer_id: FxHashMap, } impl DataSection { + /// Get the number of entries + pub fn num_entries(&self) -> usize { + self.non_configurables.len() + self.configurables.len() + } + + /// Iterate over all entries, non-configurables followed by configurables + pub fn iter_all_entries(&self) -> impl Iterator + '_ { + self.non_configurables + .iter() + .chain(self.configurables.iter()) + .cloned() + } + + /// Get the absolute index of an id + fn absolute_idx(&self, id: &DataId) -> usize { + match id.kind { + DataIdEntryKind::NonConfigurable => id.idx as usize, + DataIdEntryKind::Configurable => id.idx as usize + self.non_configurables.len(), + } + } + + /// Get entry at id + fn get(&self, id: &DataId) -> Option<&Entry> { + match id.kind { + DataIdEntryKind::NonConfigurable => self.non_configurables.get(id.idx as usize), + DataIdEntryKind::Configurable => self.configurables.get(id.idx as usize), + } + } + /// Given a [DataId], calculate the offset _from the beginning of the data section_ to the data /// in bytes. pub(crate) fn data_id_to_offset(&self, id: &DataId) -> usize { - self.raw_data_id_to_offset(id.0) + let idx = self.absolute_idx(id); + self.absolute_idx_to_offset(idx) } - /// Given a [DataId], calculate the offset _from the beginning of the data section_ to the data + /// Given an absolute index, calculate the offset _from the beginning of the data section_ to the data /// in bytes. - pub(crate) fn raw_data_id_to_offset(&self, id: u32) -> usize { - self.value_pairs - .iter() - .take(id as usize) - .fold(0, |offset, entry| { - //entries must be word aligned - size_bytes_round_up_to_word_alignment!(offset + entry.to_bytes().len()) - }) + pub(crate) fn absolute_idx_to_offset(&self, idx: usize) -> usize { + self.iter_all_entries().take(idx).fold(0, |offset, entry| { + //entries must be word aligned + size_bytes_round_up_to_word_alignment!(offset + entry.to_bytes().len()) + }) } pub(crate) fn serialize_to_bytes(&self) -> Vec { // not the exact right capacity but serves as a lower bound - let mut buf = Vec::with_capacity(self.value_pairs.len()); - for entry in &self.value_pairs { + let mut buf = Vec::with_capacity(self.num_entries()); + for entry in self.iter_all_entries() { buf.append(&mut entry.to_bytes()); //entries must be word aligned @@ -248,16 +310,12 @@ impl DataSection { /// Returns whether a specific [DataId] value has a copy type (fits in a register). pub(crate) fn has_copy_type(&self, id: &DataId) -> Option { - self.value_pairs - .get(id.0 as usize) - .map(|entry| entry.has_copy_type()) + self.get(id).map(|entry| entry.has_copy_type()) } /// Returns whether a specific [DataId] value is a byte entry. pub(crate) fn is_byte(&self, id: &DataId) -> Option { - self.value_pairs - .get(id.0 as usize) - .map(|entry| entry.is_byte()) + self.get(id).map(|entry| entry.is_byte()) } /// When generating code, sometimes a hard-coded data pointer is needed to reference @@ -268,31 +326,57 @@ impl DataSection { /// relative to the current (load) instruction. pub(crate) fn append_pointer(&mut self, pointer_value: u64) -> DataId { // The 'pointer' is just a literal 64 bit address. - self.insert_data_value(Entry::new_word(pointer_value, None, None)) + let data_id = self.insert_data_value(Entry::new_word( + pointer_value, + EntryName::NonConfigurable, + None, + )); + self.pointer_id.insert(pointer_value, data_id.clone()); + data_id + } + + /// Get the [DataId] for a pointer, if it exists. + /// The pointer must've been inserted with append_pointer. + pub(crate) fn data_id_of_pointer(&self, pointer_value: u64) -> Option { + self.pointer_id.get(&pointer_value).cloned() } /// Given any data in the form of a [Literal] (using this type mainly because it includes type - /// information and debug spans), insert it into the data section and return its offset as a + /// information and debug spans), insert it into the data section and return its handle as /// [DataId]. pub(crate) fn insert_data_value(&mut self, new_entry: Entry) -> DataId { // if there is an identical data value, use the same id - match self - .value_pairs - .iter() - .position(|entry| entry.equiv(&new_entry)) - { - Some(num) => DataId(num as u32), + + let (value_pairs, kind) = match new_entry.name { + EntryName::NonConfigurable => ( + &mut self.non_configurables, + DataIdEntryKind::NonConfigurable, + ), + EntryName::Configurable(_) => (&mut self.configurables, DataIdEntryKind::Configurable), + }; + match value_pairs.iter().position(|entry| entry.equiv(&new_entry)) { + Some(num) => DataId { + idx: num as u32, + kind, + }, None => { - self.value_pairs.push(new_entry); + value_pairs.push(new_entry); // the index of the data section where the value is stored - DataId((self.value_pairs.len() - 1) as u32) + DataId { + idx: (value_pairs.len() - 1) as u32, + kind, + } } } } // If the stored data is Datum::Word, return the inner value. pub(crate) fn get_data_word(&self, data_id: &DataId) -> Option { - self.value_pairs.get(data_id.0 as usize).and_then(|entry| { + let value_pairs = match data_id.kind { + DataIdEntryKind::NonConfigurable => &self.non_configurables, + DataIdEntryKind::Configurable => &self.configurables, + }; + value_pairs.get(data_id.idx as usize).and_then(|entry| { if let Datum::Word(w) = entry.value { Some(w) } else { @@ -322,11 +406,12 @@ impl fmt::Display for DataSection { use std::fmt::Write; let mut data_buf = String::new(); - for (ix, entry) in self.value_pairs.iter().enumerate() { + for (ix, entry) in self.iter_all_entries().enumerate() { writeln!( data_buf, - "{} {}", - DataId(ix as u32), + "data_{}_{} {}", + entry.name, + ix, display_entry(&entry.value) )?; } diff --git a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs index 0e56e87d33f..5c98c09411e 100644 --- a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs +++ b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs @@ -1,4 +1,5 @@ use super::{ + data_section::EntryName, globals_section::GlobalsSection, programs::{AbstractEntry, AbstractProgram}, }; @@ -98,7 +99,12 @@ impl<'ir, 'eng> AsmBuilder for FuelAsmBuilder<'ir, 'eng> { fn compile_configurable(&mut self, config: &ConfigContent) { match config { ConfigContent::V0 { name, constant, .. } => { - let entry = Entry::from_constant(self.context, constant, Some(name.clone()), None); + let entry = Entry::from_constant( + self.context, + constant, + EntryName::Configurable(name.clone()), + None, + ); let dataid = self.data_section.insert_data_value(entry); self.configurable_v0_data_id.insert(name.clone(), dataid); } @@ -117,7 +123,7 @@ impl<'ir, 'eng> AsmBuilder for FuelAsmBuilder<'ir, 'eng> { let (decode_fn_label, _) = self.func_label_map.get(&decode_fn.get()).unwrap(); let dataid = self.data_section.insert_data_value(Entry::new_byte_array( encoded_bytes.clone(), - Some(name.clone()), + EntryName::Configurable(name.clone()), None, )); @@ -2057,6 +2063,11 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { _otherwise => { // Get the constant into the namespace. + let config_name = if let Some(name) = config_name { + EntryName::Configurable(name) + } else { + EntryName::NonConfigurable + }; let entry = Entry::from_constant(self.context, constant, config_name, None); let data_id = self.data_section.insert_data_value(entry); @@ -2177,9 +2188,11 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { } } else { let comment = comment.into(); - let data_id = self - .data_section - .insert_data_value(Entry::new_word(imm, None, None)); + let data_id = self.data_section.insert_data_value(Entry::new_word( + imm, + EntryName::NonConfigurable, + None, + )); self.cur_bytecode.push(Op { opcode: Either::Left(VirtualOp::LoadDataId(reg.clone(), data_id)), owning_span: span.clone(), diff --git a/sway-core/src/asm_generation/fuel/functions.rs b/sway-core/src/asm_generation/fuel/functions.rs index 42577c543d6..f217a4e8396 100644 --- a/sway-core/src/asm_generation/fuel/functions.rs +++ b/sway-core/src/asm_generation/fuel/functions.rs @@ -26,7 +26,7 @@ use sway_error::{ }; use sway_types::{Ident, Span}; -use super::compiler_constants::NUM_ARG_REGISTERS; +use super::{compiler_constants::NUM_ARG_REGISTERS, data_section::EntryName}; /// A summary of the adopted calling convention: /// @@ -830,9 +830,13 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { ); } _ => { - let data_id = self.data_section.insert_data_value( - Entry::from_constant(self.context, constant, None, None), - ); + let data_id = + self.data_section.insert_data_value(Entry::from_constant( + self.context, + constant, + EntryName::NonConfigurable, + None, + )); self.ptr_map.insert(*ptr, Storage::Data(data_id)); } } @@ -858,9 +862,13 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { }); } _ => { - let data_id = self.data_section.insert_data_value( - Entry::from_constant(self.context, constant, None, None), - ); + let data_id = + self.data_section.insert_data_value(Entry::from_constant( + self.context, + constant, + EntryName::NonConfigurable, + None, + )); init_mut_vars.push(InitMutVars { stack_base_words, diff --git a/sway-core/src/asm_generation/fuel/programs/abstract.rs b/sway-core/src/asm_generation/fuel/programs/abstract.rs index b5a8a12e302..3256da242bb 100644 --- a/sway-core/src/asm_generation/fuel/programs/abstract.rs +++ b/sway-core/src/asm_generation/fuel/programs/abstract.rs @@ -5,7 +5,7 @@ use crate::{ abstract_instruction_set::AbstractInstructionSet, allocated_abstract_instruction_set::AllocatedAbstractInstructionSet, compiler_constants, - data_section::{DataSection, Entry}, + data_section::{DataSection, Entry, EntryName}, globals_section::GlobalsSection, register_sequencer::RegisterSequencer, }, @@ -75,7 +75,7 @@ impl AbstractProgram { pub(crate) fn is_empty(&self) -> bool { self.non_entries.is_empty() && self.entries.is_empty() - && self.data_section.value_pairs.is_empty() + && self.data_section.iter_all_entries().next().is_none() } /// Adds prologue, globals allocation, before entries, contract method switch, and allocates virtual register. @@ -164,14 +164,28 @@ impl AbstractProgram { /// Right now, it looks like this: /// /// WORD OP - /// [1] MOV $scratch $pc - /// [-] JMPF $zero i2 - /// [2] DATA_START (0-32) (in bytes, offset from $is) - /// [-] DATA_START (32-64) - /// [3] LW $ds $scratch 1 - /// [-] ADD $ds $ds $scratch - /// [4] .program_start: + /// 1 MOV $scratch $pc + /// - JMPF $zero i10 + /// 2 DATA_START (0-32) (in bytes, offset from $is) + /// - DATA_START (32-64) + /// 3 CONFIGURABLES_OFFSET (0-32) + /// - CONFIGURABLES_OFFSET (32-64) + /// 4 LW $ds $scratch 1 + /// - ADD $ds $ds $scratch + /// 5 .program_start: fn build_prologue(&mut self) -> AllocatedAbstractInstructionSet { + const _: () = assert!( + crate::PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES == 16, + "Inconsistency in the assumption of prelude organisation" + ); + const _: () = assert!( + crate::PRELUDE_CONFIGURABLES_SIZE_IN_BYTES == 8, + "Inconsistency in the assumption of prelude organisation" + ); + const _: () = assert!( + crate::PRELUDE_SIZE_IN_BYTES == 32, + "Inconsistency in the assumption of prelude organisation" + ); let label = self.reg_seqr.get_label(); AllocatedAbstractInstructionSet { ops: [ @@ -195,12 +209,18 @@ impl AbstractProgram { comment: "data section offset".into(), owning_span: None, }, + // word 3 -- full word u64 placeholder + AllocatedAbstractOp { + opcode: Either::Right(ControlFlowOp::ConfigurablesOffsetPlaceholder), + comment: "configurables offset".into(), + owning_span: None, + }, AllocatedAbstractOp { opcode: Either::Right(ControlFlowOp::Label(label)), - comment: "end of metadata".into(), + comment: "end of configurables offset".into(), owning_span: None, }, - // word 3 -- load the data offset into $ds + // word 4 -- load the data offset into $ds AllocatedAbstractOp { opcode: Either::Left(AllocatedOpcode::LW( AllocatedRegister::Constant(ConstantRegister::DataSectionStart), @@ -210,7 +230,7 @@ impl AbstractProgram { comment: "".into(), owning_span: None, }, - // word 3.5 -- add $ds $ds $is + // word 4.5 -- add $ds $ds $is AllocatedAbstractOp { opcode: Either::Left(AllocatedOpcode::ADD( AllocatedRegister::Constant(ConstantRegister::DataSectionStart), @@ -281,7 +301,7 @@ impl AbstractProgram { // Put the selector in the data section. let data_label = self.data_section.insert_data_value(Entry::new_word( u32::from_be_bytes(selector) as u64, - None, + EntryName::NonConfigurable, None, )); diff --git a/sway-core/src/asm_lang/allocated_ops.rs b/sway-core/src/asm_lang/allocated_ops.rs index b78ba37b2db..b817afd3c32 100644 --- a/sway-core/src/asm_lang/allocated_ops.rs +++ b/sway-core/src/asm_lang/allocated_ops.rs @@ -17,8 +17,10 @@ use crate::{ }, fuel_prelude::fuel_asm::{self, op}, }; -use either::Either; -use fuel_vm::fuel_asm::{op::ADDI, Imm12}; +use fuel_vm::fuel_asm::{ + op::{ADD, MOVI}, + Imm18, +}; use std::fmt::{self, Write}; use sway_types::span::Span; @@ -273,6 +275,7 @@ pub(crate) enum AllocatedOpcode { /* Non-VM Instructions */ BLOB(VirtualImmediate24), + ConfigurablesOffsetPlaceholder, DataSectionOffsetPlaceholder, LoadDataId(AllocatedRegister, DataId), AddrDataId(AllocatedRegister, DataId), @@ -397,6 +400,7 @@ impl AllocatedOpcode { /* Non-VM Instructions */ BLOB(_imm) => vec![], + ConfigurablesOffsetPlaceholder => vec![], DataSectionOffsetPlaceholder => vec![], LoadDataId(r1, _i) => vec![r1], AddrDataId(r1, _i) => vec![r1], @@ -525,6 +529,10 @@ impl fmt::Display for AllocatedOpcode { /* Non-VM Instructions */ BLOB(a) => write!(fmtr, "blob {a}"), + ConfigurablesOffsetPlaceholder => write!( + fmtr, + "CONFIGURABLES_OFFSET[0..32]\nCONFIGURABLES_OFFSET[32..64]" + ), DataSectionOffsetPlaceholder => { write!( fmtr, @@ -562,17 +570,21 @@ impl fmt::Display for AllocatedOp { } } -type DoubleWideData = [u8; 8]; +pub(crate) enum FuelAsmData { + ConfigurablesOffset([u8; 8]), + DatasectionOffset([u8; 8]), + Instructions(Vec), +} impl AllocatedOp { pub(crate) fn to_fuel_asm( &self, offset_to_data_section: u64, offset_from_instr_start: u64, - data_section: &mut DataSection, - ) -> Either, DoubleWideData> { + data_section: &DataSection, + ) -> FuelAsmData { use AllocatedOpcode::*; - Either::Left(vec![match &self.opcode { + FuelAsmData::Instructions(vec![match &self.opcode { /* Arithmetic/Logic (ALU) Instructions */ ADD(a, b, c) => op::ADD::new(a.to_reg_id(), b.to_reg_id(), c.to_reg_id()).into(), ADDI(a, b, c) => op::ADDI::new(a.to_reg_id(), b.to_reg_id(), c.value.into()).into(), @@ -641,9 +653,9 @@ impl AllocatedOp { /* Memory Instructions */ ALOC(a) => op::ALOC::new(a.to_reg_id()).into(), - CFEI(a) if a.value == 0 => return Either::Left(vec![]), + CFEI(a) if a.value == 0 => return FuelAsmData::Instructions(vec![]), CFEI(a) => op::CFEI::new(a.value.into()).into(), - CFSI(a) if a.value == 0 => return Either::Left(vec![]), + CFSI(a) if a.value == 0 => return FuelAsmData::Instructions(vec![]), CFSI(a) => op::CFSI::new(a.value.into()).into(), CFE(a) => op::CFE::new(a.to_reg_id()).into(), CFS(a) => op::CFS::new(a.to_reg_id()).into(), @@ -727,17 +739,20 @@ impl AllocatedOp { /* Non-VM Instructions */ BLOB(a) => { - return Either::Left( + return FuelAsmData::Instructions( std::iter::repeat(op::NOOP::new().into()) .take(a.value as usize) .collect(), ) } + ConfigurablesOffsetPlaceholder => { + return FuelAsmData::ConfigurablesOffset([0, 0, 0, 0, 0, 0, 0, 0]) + } DataSectionOffsetPlaceholder => { - return Either::Right(offset_to_data_section.to_be_bytes()) + return FuelAsmData::DatasectionOffset(offset_to_data_section.to_be_bytes()) } LoadDataId(a, b) => { - return Either::Left(realize_load( + return FuelAsmData::Instructions(realize_load( a, b, data_section, @@ -745,7 +760,7 @@ impl AllocatedOp { offset_from_instr_start, )) } - AddrDataId(a, b) => return Either::Left(addr_of(a, b, data_section)), + AddrDataId(a, b) => return FuelAsmData::Instructions(addr_of(a, b, data_section)), Undefined => unreachable!("Sway cannot generate undefined ASM opcodes"), }]) } @@ -755,14 +770,20 @@ impl AllocatedOp { fn addr_of( dest: &AllocatedRegister, data_id: &DataId, - data_section: &mut DataSection, + data_section: &DataSection, ) -> Vec { let offset_bytes = data_section.data_id_to_offset(data_id) as u64; - vec![fuel_asm::Instruction::ADDI(ADDI::new( - dest.to_reg_id(), - fuel_asm::RegId::new(DATA_SECTION_REGISTER), - Imm12::new(offset_bytes as u16), - ))] + vec![ + fuel_asm::Instruction::MOVI(MOVI::new( + dest.to_reg_id(), + Imm18::new(offset_bytes.try_into().unwrap()), + )), + fuel_asm::Instruction::ADD(ADD::new( + dest.to_reg_id(), + dest.to_reg_id(), + fuel_asm::RegId::new(DATA_SECTION_REGISTER), + )), + ] } /// Converts a virtual load word instruction which uses data labels into one which uses @@ -772,7 +793,7 @@ fn addr_of( fn realize_load( dest: &AllocatedRegister, data_id: &DataId, - data_section: &mut DataSection, + data_section: &DataSection, offset_to_data_section: u64, offset_from_instr_start: u64, ) -> Vec { @@ -815,7 +836,9 @@ fn realize_load( offset_to_data_section - offset_from_instr_start + offset_bytes - 4; // insert the pointer as bytes as a new data section entry at the end of the data - let data_id_for_pointer = data_section.append_pointer(pointer_offset_from_current_instr); + let data_id_for_pointer = data_section + .data_id_of_pointer(pointer_offset_from_current_instr) + .expect("Pointer offset must be in data_section"); // now load the pointer we just created into the `dest`ination let mut buf = Vec::with_capacity(2); diff --git a/sway-core/src/asm_lang/mod.rs b/sway-core/src/asm_lang/mod.rs index 5e1bcaded52..71e09cc2290 100644 --- a/sway-core/src/asm_lang/mod.rs +++ b/sway-core/src/asm_lang/mod.rs @@ -1248,6 +1248,7 @@ impl fmt::Display for VirtualOp { /* Non-VM Instructions */ BLOB(a) => write!(fmtr, "blob {a}"), DataSectionOffsetPlaceholder => write!(fmtr, "data section offset placeholder"), + ConfigurablesOffsetPlaceholder => write!(fmtr, "configurables offset placeholder"), LoadDataId(a, b) => write!(fmtr, "load {a} {b}"), AddrDataId(a, b) => write!(fmtr, "addr {a} {b}"), Undefined => write!(fmtr, "undefined op"), @@ -1277,6 +1278,8 @@ pub(crate) enum ControlFlowOp { Call(Label), // Save a return label address in a register. SaveRetAddr(Reg, Label), + // Placeholder for the offset into the configurables section. + ConfigurablesOffsetPlaceholder, // placeholder for the DataSection offset DataSectionOffsetPlaceholder, // Placeholder for loading an address from the data section. @@ -1304,6 +1307,8 @@ impl fmt::Display for ControlFlowOp { SaveRetAddr(r1, lab) => format!("mova {r1} {lab}"), DataSectionOffsetPlaceholder => "DATA SECTION OFFSET[0..32]\nDATA SECTION OFFSET[32..64]".into(), + ConfigurablesOffsetPlaceholder => + "CONFIGURABLES_OFFSET[0..32]\nCONFIGURABLES_OFFSET[32..64]".into(), LoadLabel(r1, lab) => format!("lwlab {r1} {lab}"), PushAll(lab) => format!("pusha {lab}"), PopAll(lab) => format!("popa {lab}"), @@ -1321,6 +1326,7 @@ impl ControlFlowOp { | Jump(_) | Call(_) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | PushAll(_) | PopAll(_) => vec![], @@ -1339,6 +1345,7 @@ impl ControlFlowOp { | Call(_) | SaveRetAddr(..) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | LoadLabel(..) | PushAll(_) | PopAll(_) => vec![], @@ -1360,6 +1367,7 @@ impl ControlFlowOp { | JumpIfNotZero(..) | Call(_) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | PushAll(_) | PopAll(_) => vec![], }) @@ -1381,6 +1389,7 @@ impl ControlFlowOp { | Jump(_) | Call(_) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | PushAll(_) | PopAll(_) => self.clone(), @@ -1410,6 +1419,7 @@ impl ControlFlowOp { | Call(_) | SaveRetAddr(..) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | LoadLabel(..) | PushAll(_) | PopAll(_) => (), @@ -1466,6 +1476,7 @@ impl ControlFlowOp { Jump(label) => Jump(*label), Call(label) => Call(*label), DataSectionOffsetPlaceholder => DataSectionOffsetPlaceholder, + ConfigurablesOffsetPlaceholder => ConfigurablesOffsetPlaceholder, PushAll(label) => PushAll(*label), PopAll(label) => PopAll(*label), diff --git a/sway-core/src/asm_lang/virtual_ops.rs b/sway-core/src/asm_lang/virtual_ops.rs index ffe3509b7cd..3d041713a4f 100644 --- a/sway-core/src/asm_lang/virtual_ops.rs +++ b/sway-core/src/asm_lang/virtual_ops.rs @@ -226,6 +226,7 @@ pub(crate) enum VirtualOp { /* Non-VM Instructions */ BLOB(VirtualImmediate24), + ConfigurablesOffsetPlaceholder, DataSectionOffsetPlaceholder, // LoadDataId takes a virtual register and a DataId, which points to a labeled piece // of data in the data section. Note that the ASM op corresponding to a LW is @@ -347,6 +348,7 @@ impl VirtualOp { /* Non-VM Instructions */ BLOB(_imm) => vec![], DataSectionOffsetPlaceholder => vec![], + ConfigurablesOffsetPlaceholder => vec![], LoadDataId(r1, _i) => vec![r1], AddrDataId(r1, _) => vec![r1], @@ -465,6 +467,7 @@ impl VirtualOp { // Virtual OPs | BLOB(_) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | Undefined => true } } @@ -571,6 +574,7 @@ impl VirtualOp { | GTF(_, _, _) | BLOB(_) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | LoadDataId(_, _) | AddrDataId(_, _) | Undefined => vec![], @@ -692,6 +696,7 @@ impl VirtualOp { /* Non-VM Instructions */ BLOB(_imm) => vec![], DataSectionOffsetPlaceholder => vec![], + ConfigurablesOffsetPlaceholder => vec![], LoadDataId(_r1, _i) => vec![], AddrDataId(_r1, _i) => vec![], @@ -815,6 +820,7 @@ impl VirtualOp { LoadDataId(r1, _i) => vec![r1], AddrDataId(r1, _i) => vec![r1], DataSectionOffsetPlaceholder => vec![], + ConfigurablesOffsetPlaceholder => vec![], Undefined => vec![], }) .into_iter() @@ -1263,6 +1269,7 @@ impl VirtualOp { /* Non-VM Instructions */ BLOB(i) => Self::BLOB(i.clone()), DataSectionOffsetPlaceholder => Self::DataSectionOffsetPlaceholder, + ConfigurablesOffsetPlaceholder => Self::ConfigurablesOffsetPlaceholder, LoadDataId(r1, i) => Self::LoadDataId(update_reg(reg_to_reg_map, r1), i.clone()), AddrDataId(r1, i) => Self::AddrDataId(update_reg(reg_to_reg_map, r1), i.clone()), Undefined => Self::Undefined, @@ -1743,6 +1750,7 @@ impl VirtualOp { /* Non-VM Instructions */ BLOB(imm) => AllocatedOpcode::BLOB(imm.clone()), DataSectionOffsetPlaceholder => AllocatedOpcode::DataSectionOffsetPlaceholder, + ConfigurablesOffsetPlaceholder => AllocatedOpcode::ConfigurablesOffsetPlaceholder, LoadDataId(reg1, label) => { AllocatedOpcode::LoadDataId(map_reg(&mapping, reg1), label.clone()) } diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index d59970de1b0..402a81d1242 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -1000,6 +1000,28 @@ pub fn compile_to_bytecode( ) } +/// Size of the prelude's CONFIGURABLES_OFFSET section, in bytes. +pub const PRELUDE_CONFIGURABLES_SIZE_IN_BYTES: usize = 8; +/// Offset (in bytes) of the CONFIGURABLES_OFFSET section in the prelude. +pub const PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES: usize = 16; +/// Total size of the prelude in bytes. Instructions start right after. +pub const PRELUDE_SIZE_IN_BYTES: usize = 32; + +/// Given bytecode, overwrite the existing offset to configurables offset in the prelude with the given one. +pub fn set_bytecode_configurables_offset( + compiled_bytecode: &mut CompiledBytecode, + md: &[u8; PRELUDE_CONFIGURABLES_SIZE_IN_BYTES], +) { + assert!( + compiled_bytecode.bytecode.len() + >= PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES + PRELUDE_CONFIGURABLES_SIZE_IN_BYTES + ); + let code = &mut compiled_bytecode.bytecode; + for (index, byte) in md.iter().enumerate() { + code[index + PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES] = *byte; + } +} + /// Given the assembly (opcodes), compile to [CompiledBytecode], containing the asm in bytecode form. pub fn asm_to_bytecode( handler: &Handler, 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 2daeaffdc6a..82d1bf9734c 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 @@ -62,82 +62,82 @@ { "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", "name": "BOOL", - "offset": 6896 + "offset": 7120 }, { "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", "name": "U8", - "offset": 7088 + "offset": 7312 }, { "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", "name": "ANOTHER_U8", - "offset": 6824 + "offset": 7048 }, { "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", "name": "U16", - "offset": 7032 + "offset": 7256 }, { "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", "name": "U32", - "offset": 7072 + "offset": 7296 }, { "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", "name": "U64", - "offset": 7080 + "offset": 7304 }, { "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", "name": "U256", - "offset": 7040 + "offset": 7264 }, { "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", "name": "B256", - "offset": 6864 + "offset": 7088 }, { "concreteTypeId": "81fc10c4681a3271cf2d66b2ec6fbc8ed007a442652930844fcf11818c295bff", "name": "CONFIGURABLE_STRUCT", - "offset": 6984 + "offset": 7208 }, { "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", "name": "CONFIGURABLE_ENUM_A", - "offset": 6904 + "offset": 7128 }, { "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", "name": "CONFIGURABLE_ENUM_B", - "offset": 6944 + "offset": 7168 }, { "concreteTypeId": "4926d35d1a5157936b0a29bc126b8aace6d911209a5c130e9b716b0c73643ea6", "name": "ARRAY_BOOL", - "offset": 6832 + "offset": 7056 }, { "concreteTypeId": "776fb5a3824169d6736138565fdc20aad684d9111266a5ff6d5c675280b7e199", "name": "ARRAY_U64", - "offset": 6840 + "offset": 7064 }, { "concreteTypeId": "c998ca9a5f221fe7b5c66ae70c8a9562b86d964408b00d17f883c906bc1fe4be", "name": "TUPLE_BOOL_U64", - "offset": 7016 + "offset": 7240 }, { "concreteTypeId": "94f0fa95c830be5e4f711963e83259fe7e8bc723278ab6ec34449e791a99b53a", "name": "STR_4", - "offset": 7008 + "offset": 7232 }, { "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", "name": "NOT_USED", - "offset": 7000 + "offset": 7224 } ], "encodingVersion": "1", diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/stdout.snap b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/stdout.snap index 8e825421dd7..a8fe871947a 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/stdout.snap +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/stdout.snap @@ -1,5 +1,6 @@ --- source: test/tests/tests.rs +assertion_line: 115 snapshot_kind: text --- > forc build --path test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode --release --ir final @@ -361,4 +362,4 @@ script { !128 = fn_call_path_span !0 235 236 !129 = (!127 !128) - Finished release [optimized + fuel] target(s) [744 B] in ??? + Finished release [optimized + fuel] target(s) [760 B] in ??? diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json index 49a75d8d5c1..c58838960ad 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json @@ -9,7 +9,7 @@ { "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", "name": "SOME_U256", - "offset": 816 + "offset": 872 } ], "encodingVersion": "1", diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw index ffc9dcbe016..deee7c52ae5 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw @@ -6,7 +6,7 @@ use std::hash::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x14ed3cd06c2947248f69d54bfa681fe40d26267be84df7e19e253622b7921bbe; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xdf53a7533a12c5ee3df459fc424f51807fc9740f13080a725f5f66408ede1186; // AUTO-CONTRACT-ID ../../test_contracts/array_of_structs_contract --release +const CONTRACT_ID = 0x6b01f04c84ce955e8dfc6ed3611fd2518424ab757e5a540878f49fbd1bdec571; // AUTO-CONTRACT-ID ../../test_contracts/array_of_structs_contract --release fn get_address() -> Option { Some(CONTRACT_ID.into()) diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw index 5459da78f0c..1c2a953fc35 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw @@ -9,12 +9,12 @@ use test_fuel_coin_abi::*; #[cfg(experimental_new_encoding = false)] const FUEL_COIN_CONTRACT_ID = 0xec2277ebe007ade87e3d797c3b1e070dcd542d5ef8f038b471f262ef9cebc87c; #[cfg(experimental_new_encoding = true)] -const FUEL_COIN_CONTRACT_ID = 0xf2fecff29038dab2ef571397ea5507359265c9154608e7de36ccbea20ed5c8aa; +const FUEL_COIN_CONTRACT_ID = 0x19c0d374734bd8a92b776787e9dffa0f105a90e3c977626f93a1916de54dd714; #[cfg(experimental_new_encoding = false)] const BALANCE_CONTRACT_ID = 0xf6cd545152ac83225e8e7df2efb5c6fa6e37bc9b9e977b5ea8103d28668925df; #[cfg(experimental_new_encoding = true)] -const BALANCE_CONTRACT_ID = 0xaa4e3d9c953790384f76dcad07e21d6973ae8df79432e48bbed76ccb6437a9a7; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release +const BALANCE_CONTRACT_ID = 0xb770fa56f665d6fbdbdceecce21b7b61878f650981ac7f21c052613015937034; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release fn main() -> bool { let default_gas = 1_000_000_000_000; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw index 365a489a3dd..638541084b4 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw @@ -5,7 +5,7 @@ use balance_test_abi::BalanceTest; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xf6cd545152ac83225e8e7df2efb5c6fa6e37bc9b9e977b5ea8103d28668925df; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xaa4e3d9c953790384f76dcad07e21d6973ae8df79432e48bbed76ccb6437a9a7; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release +const CONTRACT_ID = 0xb770fa56f665d6fbdbdceecce21b7b61878f650981ac7f21c052613015937034; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release fn main() -> bool { let balance_test_contract = abi(BalanceTest, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw index b0a18868637..9a078ca2bbc 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw @@ -6,7 +6,7 @@ use abi_with_tuples::{MyContract, Location, Person}; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xfdc14550c8aee742cd556d0ab7f378b7be0d3b1e6e086c097352e94590d4ed02; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xe21bdb5e019c073978f5bd6eee1339a0e68ab38b913d8a00ff1286e9e5eb894d; // AUTO-CONTRACT-ID ../../test_contracts/abi_with_tuples_contract --release +const CONTRACT_ID = 0xcc679c89d2950879d4f8fb3b99770f93dfde3335fff574cbf0588691fbcefde3; // AUTO-CONTRACT-ID ../../test_contracts/abi_with_tuples_contract --release fn main() -> bool { let the_abi = abi(MyContract, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw index d7218234e92..f3096a559c9 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw @@ -4,7 +4,7 @@ use basic_storage_abi::{BasicStorage, Quad}; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x94db39f409a31b9f2ebcadeea44378e419208c20de90f5d8e1e33dc1523754cb; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x27857d650234acd05b5fa9a9bc34abf76fa66d2e6ce8c8b24416805b75005bd0; // AUTO-CONTRACT-ID ../../test_contracts/basic_storage --release +const CONTRACT_ID = 0x7d78bfaba7c715105ec3ec568b8c64dbb77491d45dec52b549e59c0cf5cf5c5e; // AUTO-CONTRACT-ID ../../test_contracts/basic_storage --release fn main() -> u64 { let addr = abi(BasicStorage, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw index eab00cc7b7c..dae00c1579b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw @@ -5,7 +5,7 @@ use contract_with_type_aliases_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x0cbeb6efe3104b460be769bdc4ea101ebf16ccc16f2d7b667ec3e1c7f5ce35b5; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x8b400005d6178d7ceaccac502a021abad28a899ab8692099c0bfa5e70853d573; // AUTO-CONTRACT-ID ../../test_contracts/contract_with_type_aliases --release +const CONTRACT_ID = 0x2e8efc627379d037c6ac70249d0bf0726f228ea6bade786e11639b878241f333; // AUTO-CONTRACT-ID ../../test_contracts/contract_with_type_aliases --release fn main() { let caller = abi(MyContract, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw index 28089f44fa3..28218e97054 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw @@ -6,7 +6,7 @@ use dynamic_contract_call::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xd1b4047af7ef111c023ab71069e01dc2abfde487c0a0ce1268e4f447e6c6e4c2; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xe1dbd25c5d2ccb547ce1f592d04a407dec80cc715255c358dfb32ccf9ca0f926; // AUTO-CONTRACT-ID ../../test_contracts/increment_contract --release +const CONTRACT_ID = 0xc2694e6a397883ae59ea2e807c0ba3714865d0c4bf16571893d632b3bd7ec6f7; // AUTO-CONTRACT-ID ../../test_contracts/increment_contract --release fn main() -> bool { let the_abi = abi(Incrementor, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw index 06673118a96..b8060557890 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw @@ -5,7 +5,7 @@ use storage_enum_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xc601d11767195485a6654d566c67774134668863d8c797a8c69e8778fb1f89e9; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x47084a8c1eb453b655842e1b3067ee1f0d9081052bd74ac606efa6ae9a56d901; // AUTO-CONTRACT-ID ../../test_contracts/storage_enum_contract --release +const CONTRACT_ID = 0xd9247267148944e3f541347c65705af8798b257e8acda1e89e220c4bdf9298fc; // AUTO-CONTRACT-ID ../../test_contracts/storage_enum_contract --release fn main() -> u64 { let caller = abi(StorageEnum, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw index ae8dc25bd57..ea5fb5c74e5 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw @@ -5,7 +5,7 @@ use auth_testing_abi::AuthTesting; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xc2eec20491b53aab7232cbd27c31d15417b4e9daf0b89c74cc242ef1295f681f; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x507e5e609fdb2a085da8d681519b6bb6b738f2beb0321600c1e3497db3114a37; // AUTO-CONTRACT-ID ../../test_contracts/auth_testing_contract --release +const CONTRACT_ID = 0xcdc67c314d13752e5c3e10aa1de6615e1ec6864e0461317b5f26eef3320a9a8e; // AUTO-CONTRACT-ID ../../test_contracts/auth_testing_contract --release // should be false in the case of a script fn main() -> bool { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw index 4a0c2e86a63..64dec655d14 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw @@ -6,7 +6,7 @@ use context_testing_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x6054c11cda000f5990373a4d61929396165be4dfdd61d5b7bd26da60ab0d8577; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xb80ada1b7018cd6cb45dac7e0dfc1b17fc2931439facc55bd784523410e31449; // AUTO-CONTRACT-ID ../../test_contracts/context_testing_contract --release +const CONTRACT_ID = 0xecf511a0e2f4022c17413625d69c390d51d0740424d6886cbbe9ca60acd0606b; // AUTO-CONTRACT-ID ../../test_contracts/context_testing_contract --release fn main() -> bool { let gas: u64 = u64::max(); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw index 69da3b33161..1364b7aa4b4 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw @@ -5,7 +5,7 @@ use nested_struct_args_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xe63d33a1b3a6903808b379f6a41a72fa8a370e8b76626775e7d9d2f9c4c5da40; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xc4f40cab476f1e705db3cdb22367eb20ebb180213801918db9b2030db56a0542; // AUTO-CONTRACT-ID ../../test_contracts/nested_struct_args_contract --release +const CONTRACT_ID = 0x27e6a749a1773f65f850b36e4e61afdbfe72ba4189cd518c16e06cf0c04a1fa9; // AUTO-CONTRACT-ID ../../test_contracts/nested_struct_args_contract --release fn main() -> bool { let caller = abi(NestedStructArgs, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw index 7850cbec2ad..12e4d20fdec 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw @@ -6,7 +6,7 @@ use std::hash::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x3bc28acd66d327b8c1b9624c1fabfc07e9ffa1b5d71c2832c3bfaaf8f4b805e9; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xa8eb4bf19964abcc5fdeac8daa1e5816326f728e9883f0287cf4c404527291a8; // AUTO-CONTRACT-ID ../../test_contracts/storage_access_contract --release +const CONTRACT_ID = 0xb509b52a765f2a8e97b29e4699d0ec8fa056b2bb649f785c75e36f868c318b98; // AUTO-CONTRACT-ID ../../test_contracts/storage_access_contract --release fn main() -> bool { let caller = abi(StorageAccess, CONTRACT_ID); diff --git a/test/src/sdk-harness/test_projects/auth/mod.rs b/test/src/sdk-harness/test_projects/auth/mod.rs index 2fefd28f8c8..5c167a1d927 100644 --- a/test/src/sdk-harness/test_projects/auth/mod.rs +++ b/test/src/sdk-harness/test_projects/auth/mod.rs @@ -624,7 +624,7 @@ async fn can_get_predicate_address() { // Setup predicate. let hex_predicate_address: &str = - "0x5dcc82a88eebb07fb628db93d11ec38f085cbf36453a7135fea41b93cc44e118"; + "0x8b300a68337368654e71c65ae93c3d9eb3b9837d0c11d770cbf8740a6a5a8631"; let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string"); let predicate_bech32_address = Bech32Address::from(predicate_address); @@ -750,7 +750,7 @@ async fn when_incorrect_predicate_address_passed() { async fn can_get_predicate_address_in_message() { // Setup predicate address. let hex_predicate_address: &str = - "0x5dcc82a88eebb07fb628db93d11ec38f085cbf36453a7135fea41b93cc44e118"; + "0x8b300a68337368654e71c65ae93c3d9eb3b9837d0c11d770cbf8740a6a5a8631"; let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string"); let predicate_bech32_address = Bech32Address::from(predicate_address); From 519f208a05dde5791ae54cc42fd916e9f72a4d50 Mon Sep 17 00:00:00 2001 From: zees-dev Date: Tue, 19 Nov 2024 16:48:32 +1300 Subject: [PATCH 19/52] `Forc.toml` metadata support (#6728) # Description Adds support for `metadata` as `[project.metadata]` or `[workspace.metadata]` in `Forc.toml` of value `toml::Value` - Addresses: https://github.com/FuelLabs/rfcs/blob/22bf3936a37b60bb496232c1b52bf59e204a0697/text/rfcs/0006-metadata-in-forc-manifest.md#reference-level-explanation - Resolves: https://github.com/FuelLabs/sway/issues/2180 ## Linked examples of usage - https://github.com/FuelLabs/example-forc-plugins/pull/1 --------- Co-authored-by: Sophie Dankel <47993817+sdankel@users.noreply.github.com> --- docs/book/src/forc/manifest_reference.md | 78 ++++++ forc-pkg/src/manifest/mod.rs | 291 ++++++++++++++++++++++- 2 files changed, 366 insertions(+), 3 deletions(-) diff --git a/docs/book/src/forc/manifest_reference.md b/docs/book/src/forc/manifest_reference.md index e9be681e5c8..0757f13e213 100644 --- a/docs/book/src/forc/manifest_reference.md +++ b/docs/book/src/forc/manifest_reference.md @@ -11,6 +11,7 @@ The `Forc.toml` (the _manifest_ file) is a compulsory file for each package and * For the recommended way of selecting an entry point of large libraries please take a look at: [Libraries](./../sway-program-types/libraries.md) * `implicit-std` - Controls whether provided `std` version (with the current `forc` version) will get added as a dependency _implicitly_. _Unless you know what you are doing, leave this as default._ * `forc-version` - The minimum forc version required for this project to work properly. + * `metadata` - Metadata for the project; can be used by tools which would like to store package configuration in `Forc.toml`. * [`[dependencies]`](#the-dependencies-section) — Defines the dependencies. * `[network]` — Defines a network for forc to interact with. @@ -41,8 +42,85 @@ entry = "main.sw" organization = "Fuel_Labs" license = "Apache-2.0" name = "wallet_contract" + +[project.metadata] +indexing = { namespace = "counter-contract", schema_path = "out/release/counter-contract-abi.json" } +``` + +### Metadata Section in `Forc.toml` + +The `[project.metadata]` section provides a dedicated space for external tools and plugins to store their configuration in `Forc.toml`. The metadata key names are arbitrary and do not need to match the tool's name. + +#### Workspace vs Project Metadata + +Metadata can be defined at two levels: + +Workspace level - defined in the workspace\'s root `Forc.toml`: + +```toml +[workspace.metadata] +my_tool = { shared_setting = "value" } +``` + +Project level - defined in individual project\'s `Forc.toml`: + +```toml +[project.metadata.any_name_here] +option1 = "value" +option2 = "value" + +[project.metadata.my_custom_config] +setting1 = "value" +setting2 = "value" +``` + +Example for an indexing tool: + +```toml +[project.metadata.indexing] +namespace = "counter-contract" +schema_path = "out/release/counter-contract-abi.json" ``` +When both workspace and project metadata exist: + +* Project-level metadata should take precedence over workspace metadata +* Tools can choose to merge workspace and project settings +* Consider documenting your tool's metadata inheritance behavior + +#### Guidelines for Plugin Developers + +Best Practices + +* Choose clear, descriptive metadata key names +* Document the exact metadata key name your tool expects +* Don't require `Forc.toml` if tool can function without it +* Consider using TOML format for dedicated config files +* Specify how your tool handles workspace vs project metadata + +Implementation Notes + +* The metadata section is optional +* Forc does not parse metadata contents +* Plugin developers handle their own configuration parsing +* Choose unique metadata keys to avoid conflicts with other tools + +#### Example Use Cases + +* Documentation generation settings +* Formatter configurations +* Debugger options +* Wallet integration +* Contract indexing +* Testing frameworks + +This allows for a streamlined developer experience while maintaining clear separation between core Forc functionality and third-party tools. + +#### External Tooling Examples + +* [forc-index-ts](https://github.com/FuelLabs/example-forc-plugins/tree/master/forc-index-ts): A TypeScript CLI tool for parsing `Forc.toml` metadata to read contract ABI JSON file. +* [forc-index-rs](https://github.com/FuelLabs/example-forc-plugins/tree/master/forc-index-rs): A Rust CLI tool for parsing `Forc.toml` metadata to read contract ABI JSON file. + ## The `[dependencies]` section The following fields can be provided with a dependency: diff --git a/forc-pkg/src/manifest/mod.rs b/forc-pkg/src/manifest/mod.rs index 5ce50d65804..c20effec0fb 100644 --- a/forc-pkg/src/manifest/mod.rs +++ b/forc-pkg/src/manifest/mod.rs @@ -166,7 +166,7 @@ impl TryInto for ManifestFile { type PatchMap = BTreeMap; /// A [PackageManifest] that was deserialized from a file at a particular path. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq)] pub struct PackageManifestFile { /// The deserialized `Forc.toml`. manifest: PackageManifest, @@ -175,7 +175,7 @@ pub struct PackageManifestFile { } /// A direct mapping to a `Forc.toml`. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "kebab-case")] pub struct PackageManifest { pub project: Project, @@ -189,7 +189,7 @@ pub struct PackageManifest { pub proxy: Option, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "kebab-case")] pub struct Project { pub authors: Option>, @@ -202,6 +202,7 @@ pub struct Project { pub forc_version: Option, #[serde(default)] pub experimental: HashMap, + pub metadata: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] @@ -850,6 +851,7 @@ pub struct WorkspaceManifest { #[serde(rename_all = "kebab-case")] pub struct Workspace { pub members: Vec, + pub metadata: Option, } impl WorkspaceManifestFile { @@ -1330,4 +1332,287 @@ mod tests { assert!(dependency_details_git_rev.validate().is_ok()); assert!(dependency_details_ipfs.validate().is_ok()); } + + #[test] + fn test_project_with_null_metadata() { + let project = Project { + authors: Some(vec!["Test Author".to_string()]), + name: "test-project".to_string(), + organization: None, + license: "Apache-2.0".to_string(), + entry: "main.sw".to_string(), + implicit_std: None, + forc_version: None, + experimental: HashMap::new(), + metadata: Some(toml::Value::from(toml::value::Table::new())), + }; + + let serialized = toml::to_string(&project).unwrap(); + let deserialized: Project = toml::from_str(&serialized).unwrap(); + + assert_eq!(project.name, deserialized.name); + assert_eq!(project.metadata, deserialized.metadata); + } + + #[test] + fn test_project_without_metadata() { + let project = Project { + authors: Some(vec!["Test Author".to_string()]), + name: "test-project".to_string(), + organization: None, + license: "Apache-2.0".to_string(), + entry: "main.sw".to_string(), + implicit_std: None, + forc_version: None, + experimental: HashMap::new(), + metadata: None, + }; + + let serialized = toml::to_string(&project).unwrap(); + let deserialized: Project = toml::from_str(&serialized).unwrap(); + + assert_eq!(project.name, deserialized.name); + assert_eq!(project.metadata, deserialized.metadata); + assert_eq!(project.metadata, None); + } + + #[test] + fn test_project_metadata_from_toml() { + let toml_str = r#" + name = "test-project" + license = "Apache-2.0" + entry = "main.sw" + authors = ["Test Author"] + + [metadata] + description = "A test project" + version = "1.0.0" + homepage = "https://example.com" + documentation = "https://docs.example.com" + repository = "https://github.com/example/test-project" + keywords = ["test", "project"] + categories = ["test"] + "#; + + let project: Project = toml::from_str(toml_str).unwrap(); + assert!(project.metadata.is_some()); + + let metadata = project.metadata.unwrap(); + let table = metadata.as_table().unwrap(); + + assert_eq!( + table.get("description").unwrap().as_str().unwrap(), + "A test project" + ); + assert_eq!(table.get("version").unwrap().as_str().unwrap(), "1.0.0"); + assert_eq!( + table.get("homepage").unwrap().as_str().unwrap(), + "https://example.com" + ); + + let keywords = table.get("keywords").unwrap().as_array().unwrap(); + assert_eq!(keywords[0].as_str().unwrap(), "test"); + assert_eq!(keywords[1].as_str().unwrap(), "project"); + } + + #[test] + fn test_project_with_invalid_metadata() { + // Test with invalid TOML syntax - unclosed table + let invalid_toml = r#" + name = "test-project" + license = "Apache-2.0" + entry = "main.sw" + + [metadata + description = "Invalid TOML" + "#; + + let result: Result = toml::from_str(invalid_toml); + assert!(result.is_err()); + + // Test with invalid TOML syntax - invalid key + let invalid_toml = r#" + name = "test-project" + license = "Apache-2.0" + entry = "main.sw" + + [metadata] + ] = "Invalid key" + "#; + + let result: Result = toml::from_str(invalid_toml); + assert!(result.is_err()); + + // Test with duplicate keys + let invalid_toml = r#" + name = "test-project" + license = "Apache-2.0" + entry = "main.sw" + + [metadata] + nested = { key = "value1" } + + [metadata.nested] + key = "value2" + "#; + + let result: Result = toml::from_str(invalid_toml); + assert!(result.is_err()); + assert!(result + .err() + .unwrap() + .to_string() + .contains("duplicate key `nested` in table `metadata`")); + } + + #[test] + fn test_metadata_roundtrip() { + let original_toml = r#" + name = "test-project" + license = "Apache-2.0" + entry = "main.sw" + + [metadata] + boolean = true + integer = 42 + float = 3.12 + string = "value" + array = [1, 2, 3] + mixed_array = [1, "two", true] + + [metadata.nested] + key = "value2" + "#; + + let project: Project = toml::from_str(original_toml).unwrap(); + let serialized = toml::to_string(&project).unwrap(); + let deserialized: Project = toml::from_str(&serialized).unwrap(); + + // Verify that the metadata is preserved + assert_eq!(project.metadata, deserialized.metadata); + + // Verify all types were preserved + let table_val = project.metadata.unwrap(); + let table = table_val.as_table().unwrap(); + assert!(table.get("boolean").unwrap().as_bool().unwrap()); + assert_eq!(table.get("integer").unwrap().as_integer().unwrap(), 42); + assert_eq!(table.get("float").unwrap().as_float().unwrap(), 3.12); + assert_eq!(table.get("string").unwrap().as_str().unwrap(), "value"); + assert_eq!(table.get("array").unwrap().as_array().unwrap().len(), 3); + assert!(table.get("nested").unwrap().as_table().is_some()); + } + + #[test] + fn test_workspace_with_metadata() { + let toml_str = r#" + [workspace] + members = ["package1", "package2"] + + [workspace.metadata] + description = "A test workspace" + version = "1.0.0" + authors = ["Test Author"] + homepage = "https://example.com" + + [workspace.metadata.ci] + workflow = "main" + timeout = 3600 + "#; + + let manifest: WorkspaceManifest = toml::from_str(toml_str).unwrap(); + assert!(manifest.workspace.metadata.is_some()); + + let metadata = manifest.workspace.metadata.unwrap(); + let table = metadata.as_table().unwrap(); + + assert_eq!( + table.get("description").unwrap().as_str().unwrap(), + "A test workspace" + ); + assert_eq!(table.get("version").unwrap().as_str().unwrap(), "1.0.0"); + + let ci = table.get("ci").unwrap().as_table().unwrap(); + assert_eq!(ci.get("workflow").unwrap().as_str().unwrap(), "main"); + assert_eq!(ci.get("timeout").unwrap().as_integer().unwrap(), 3600); + } + + #[test] + fn test_workspace_without_metadata() { + let toml_str = r#" + [workspace] + members = ["package1", "package2"] + "#; + + let manifest: WorkspaceManifest = toml::from_str(toml_str).unwrap(); + assert!(manifest.workspace.metadata.is_none()); + } + + #[test] + fn test_workspace_empty_metadata() { + let toml_str = r#" + [workspace] + members = ["package1", "package2"] + + [workspace.metadata] + "#; + + let manifest: WorkspaceManifest = toml::from_str(toml_str).unwrap(); + assert!(manifest.workspace.metadata.is_some()); + let metadata = manifest.workspace.metadata.unwrap(); + assert!(metadata.as_table().unwrap().is_empty()); + } + + #[test] + fn test_workspace_complex_metadata() { + let toml_str = r#" + [workspace] + members = ["package1", "package2"] + + [workspace.metadata] + numbers = [1, 2, 3] + strings = ["a", "b", "c"] + mixed = [1, "two", true] + + [workspace.metadata.nested] + key = "value" + + [workspace.metadata.nested.deep] + another = "value" + "#; + + let manifest: WorkspaceManifest = toml::from_str(toml_str).unwrap(); + let metadata = manifest.workspace.metadata.unwrap(); + let table = metadata.as_table().unwrap(); + + assert!(table.get("numbers").unwrap().as_array().is_some()); + assert!(table.get("strings").unwrap().as_array().is_some()); + assert!(table.get("mixed").unwrap().as_array().is_some()); + + let nested = table.get("nested").unwrap().as_table().unwrap(); + assert_eq!(nested.get("key").unwrap().as_str().unwrap(), "value"); + + let deep = nested.get("deep").unwrap().as_table().unwrap(); + assert_eq!(deep.get("another").unwrap().as_str().unwrap(), "value"); + } + + #[test] + fn test_workspace_metadata_roundtrip() { + let original = WorkspaceManifest { + workspace: Workspace { + members: vec![PathBuf::from("package1"), PathBuf::from("package2")], + metadata: Some(toml::Value::Table({ + let mut table = toml::value::Table::new(); + table.insert("key".to_string(), toml::Value::String("value".to_string())); + table + })), + }, + patch: None, + }; + + let serialized = toml::to_string(&original).unwrap(); + let deserialized: WorkspaceManifest = toml::from_str(&serialized).unwrap(); + + assert_eq!(original.workspace.members, deserialized.workspace.members); + assert_eq!(original.workspace.metadata, deserialized.workspace.metadata); + } } From 0969ff27579af1e0af20694348e66595636dee5e Mon Sep 17 00:00:00 2001 From: Marcos Henrich Date: Tue, 19 Nov 2024 09:14:13 +0000 Subject: [PATCH 20/52] Proof that #6324 is not a bug. (#6573) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description The reproduction presented in #6324 was missing loading the storage configuration properly. To do that we have to use the following in `test/src/sdk-harness/test_projects/run_external_proxy_with_storage/mod.rs`: ```rust StorageConfiguration::default().add_slot_overrides_from_file("test_projects/run_external_target_with_storage/out/release/run_external_target_with_storage-storage_slots.json").unwrap(); ``` This commit changes the presented reproduction to load the storage slots and the test runs without reverting. Closes #6324 ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. Co-authored-by: João Matos --- test/src/sdk-harness/Forc.lock | 10 ++ test/src/sdk-harness/Forc.toml | 2 + test/src/sdk-harness/test_projects/harness.rs | 1 + .../run_external_proxy_with_storage/Forc.lock | 13 +++ .../run_external_proxy_with_storage/Forc.toml | 8 ++ .../run_external_proxy_with_storage/mod.rs | 106 ++++++++++++++++++ .../src/main.sw | 29 +++++ .../Forc.lock | 13 +++ .../Forc.toml | 8 ++ .../src/main.sw | 38 +++++++ 10 files changed, 228 insertions(+) create mode 100644 test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.lock create mode 100644 test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.toml create mode 100644 test/src/sdk-harness/test_projects/run_external_proxy_with_storage/mod.rs create mode 100644 test/src/sdk-harness/test_projects/run_external_proxy_with_storage/src/main.sw create mode 100644 test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.lock create mode 100644 test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.toml create mode 100644 test/src/sdk-harness/test_projects/run_external_target_with_storage/src/main.sw diff --git a/test/src/sdk-harness/Forc.lock b/test/src/sdk-harness/Forc.lock index b05cb399826..6db035f3459 100644 --- a/test/src/sdk-harness/Forc.lock +++ b/test/src/sdk-harness/Forc.lock @@ -251,11 +251,21 @@ name = "run_external_proxy" source = "member" dependencies = ["std"] +[[package]] +name = "run_external_proxy_with_storage" +source = "member" +dependencies = ["std"] + [[package]] name = "run_external_target" source = "member" dependencies = ["std"] +[[package]] +name = "run_external_target_with_storage" +source = "member" +dependencies = ["std"] + [[package]] name = "script_bytecode" source = "member" diff --git a/test/src/sdk-harness/Forc.toml b/test/src/sdk-harness/Forc.toml index 97a7001d7da..e6b081c63d0 100644 --- a/test/src/sdk-harness/Forc.toml +++ b/test/src/sdk-harness/Forc.toml @@ -29,6 +29,8 @@ members = [ "test_projects/result_option_expect", "test_projects/run_external_proxy", "test_projects/run_external_target", + "test_projects/run_external_proxy_with_storage", + "test_projects/run_external_target_with_storage", "test_projects/script_bytecode", "test_projects/script_data", "test_projects/storage", diff --git a/test/src/sdk-harness/test_projects/harness.rs b/test/src/sdk-harness/test_projects/harness.rs index bc01e3cbc5b..6f297b67ad9 100644 --- a/test/src/sdk-harness/test_projects/harness.rs +++ b/test/src/sdk-harness/test_projects/harness.rs @@ -31,6 +31,7 @@ mod registers; mod result_in_abi; mod result_option_expect; mod run_external_proxy; +mod run_external_proxy_with_storage; mod script_data; mod storage; mod storage_access; diff --git a/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.lock b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.lock new file mode 100644 index 00000000000..c0e7ac7bd1a --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = 'core' +source = 'path+from-root-37E4B1588712FA61' + +[[package]] +name = 'std' +source = 'path+from-root-37E4B1588712FA61' +dependencies = ['core'] + +[[package]] +name = 'run_external_proxy' +source = 'member' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.toml b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.toml new file mode 100644 index 00000000000..77108416623 --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "run_external_proxy_with_storage" + +[dependencies] +std = { path = "../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/mod.rs b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/mod.rs new file mode 100644 index 00000000000..39e70a5fcc4 --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/mod.rs @@ -0,0 +1,106 @@ +use fuels::{prelude::*, types::Bits256}; + +abigen!(Contract( + name = "RunExternalProxyContract", + abi = "test_projects/run_external_proxy_with_storage/out/release/run_external_proxy_with_storage-abi.json", +)); + +#[tokio::test] +async fn run_external_can_proxy_call() { + let wallet = launch_provider_and_get_wallet().await.unwrap(); + + let storage_configuration = + StorageConfiguration::default().add_slot_overrides_from_file("test_projects/run_external_target_with_storage/out/release/run_external_target_with_storage-storage_slots.json").unwrap(); + + let target_id = Contract::load_from( + "test_projects/run_external_target_with_storage/out/release/run_external_target_with_storage.bin", + LoadConfiguration::default() + .with_storage_configuration(storage_configuration.clone()), + ) + .unwrap() + .deploy(&wallet, TxPolicies::default()) + .await + .unwrap(); + + let configurables = RunExternalProxyContractConfigurables::default() + .with_TARGET(target_id.clone().into()) + .unwrap(); + let id = Contract::load_from( + "test_projects/run_external_proxy_with_storage/out/release/run_external_proxy_with_storage.bin", + LoadConfiguration::default().with_configurables(configurables).with_storage_configuration(storage_configuration), + ) + .unwrap() + .deploy(&wallet, TxPolicies::default()) + .await + .unwrap(); + let instance = RunExternalProxyContract::new(id.clone(), wallet); + // Call "large_value" + // Will call run_external_proxy::large_value + // that will call run_external_target::large_value + // and return the value doubled. + let result = instance + .methods() + .large_value() + .with_contract_ids(&[target_id.clone().into()]) + .call() + .await + .unwrap(); + for r in result.receipts.iter() { + match r { + Receipt::LogData { data, .. } => { + if let Some(data) = data { + if data.len() > 8 { + if let Ok(s) = std::str::from_utf8(&data[8..]) { + print!("{:?} ", s); + } + } + println!("{:?}", data); + } + } + _ => {} + } + } + let expected_large = + Bits256::from_hex_str("0x00000000000000000000000059F2f1fCfE2474fD5F0b9BA1E73ca90b143Eb8d0") + .unwrap(); + assert_eq!(result.value, expected_large); + // Call "double_value" + // Will call run_external_proxy::double_value + // that will call run_external_target::double_value + // and return the value doubled. + let result = instance + .methods() + .double_value(42) + .with_contract_ids(&[target_id.clone().into()]) + .call() + .await + .unwrap(); + for r in result.receipts.iter() { + match r { + Receipt::LogData { data, .. } => { + if let Some(data) = data { + if data.len() > 8 { + if let Ok(s) = std::str::from_utf8(&data[8..]) { + print!("{:?} ", s); + } + } + println!("{:?}", data); + } + } + _ => {} + } + } + assert_eq!(result.value, 84); + // Call "does_not_exist_in_the_target" + // Will call run_external_proxy::does_not_exist_in_the_target + // it will proxy the call to run_external_target, + // and endup in the fallback, fn that will triple the input value + let result = instance + .methods() + .does_not_exist_in_the_target(42) + .with_contract_ids(&[target_id.into()]) + .call() + .await + .unwrap(); + assert_eq!(result.value, 126); +} diff --git a/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/src/main.sw b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/src/main.sw new file mode 100644 index 00000000000..05dc44f0473 --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/src/main.sw @@ -0,0 +1,29 @@ +contract; + +use std::execution::run_external; + +configurable { + TARGET: ContractId = ContractId::zero(), +} + +abi RunExternalTest { + fn double_value(foo: u64) -> u64; + fn large_value() -> b256; + fn does_not_exist_in_the_target(foo: u64) -> u64; +} +impl RunExternalTest for Contract { + fn double_value(_foo: u64) -> u64 { + __log(1); + run_external(TARGET) + } + + fn large_value() -> b256 { + run_external(TARGET) + } + + // ANCHOR: does_not_exist_in_the_target + fn does_not_exist_in_the_target(_foo: u64) -> u64 { + run_external(TARGET) + } + // ANCHOR_END: does_not_exist_in_the_target +} \ No newline at end of file diff --git a/test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.lock b/test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.lock new file mode 100644 index 00000000000..05131a01155 --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = 'core' +source = 'path+from-root-37E4B1588712FA61' + +[[package]] +name = 'std' +source = 'path+from-root-37E4B1588712FA61' +dependencies = ['core'] + +[[package]] +name = 'run_external_target' +source = 'member' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.toml b/test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.toml new file mode 100644 index 00000000000..130715dae8c --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "run_external_target_with_storage" + +[dependencies] +std = { path = "../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_projects/run_external_target_with_storage/src/main.sw b/test/src/sdk-harness/test_projects/run_external_target_with_storage/src/main.sw new file mode 100644 index 00000000000..ab7d770ccef --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_target_with_storage/src/main.sw @@ -0,0 +1,38 @@ +contract; + +use std::constants::ZERO_B256; + +storage { + owner: Identity = Identity::Address(Address::from(ZERO_B256)), + simple_value: u64 = 0, +} + +abi RunExternalTest { + fn double_value(foo: u64) -> u64; + fn large_value() -> b256; +} + +impl RunExternalTest for Contract { + fn double_value(foo: u64) -> u64 { + __log(2); + foo * 2 + } + fn large_value() -> b256 { + 0x00000000000000000000000059F2f1fCfE2474fD5F0b9BA1E73ca90b143Eb8d0 + } +} + +// ANCHOR: fallback +#[fallback, storage(read, write)] +fn fallback() -> u64 { + let iden = storage.owner.read(); + + use std::call_frames::*; + __log(3); + __log(called_method()); + __log("double_value"); + __log(called_method() == "double_value"); + let foo = called_args::(); + foo * 3 +} +// ANCHOR_END: fallback From b823691349fc9f65f3e89b12413a36e12deed111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Matos?= Date: Tue, 19 Nov 2024 11:13:54 +0000 Subject: [PATCH 21/52] Add repro for issue #6335. (#6730) Closes https://github.com/FuelLabs/sway/issues/6335. ## 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). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --- .../test_contracts/issue_6335_repro/Forc.lock | 13 ++++++++++ .../test_contracts/issue_6335_repro/Forc.toml | 9 +++++++ .../issue_6335_repro/src/main.sw | 25 +++++++++++++++++++ .../test_contracts/issue_6335_repro/test.toml | 4 +++ 4 files changed, 51 insertions(+) create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/test.toml diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.lock new file mode 100644 index 00000000000..efaec2f6f2a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-2A7B279266ACFF97" + +[[package]] +name = "issue_6335_repro" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-2A7B279266ACFF97" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.toml new file mode 100644 index 00000000000..5f7f8ed6230 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +implicit-std = false +license = "Apache-2.0" +name = "issue_6335_repro" + +[dependencies] +std = { path = "../../../../reduced_std_libs/sway-lib-std-conversions" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/src/main.sw new file mode 100644 index 00000000000..36c95885603 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/src/main.sw @@ -0,0 +1,25 @@ +contract; + +use std::bytes::*; + +abi MyAbi { + fn test() -> u64; +} + +abi FakeAbi { + fn test() -> Bytes; +} + +impl MyAbi for Contract { + fn test() -> u64 { + 64 + } +} + +#[test] +fn test() { + let caller = abi(FakeAbi, CONTRACT_ID); + let res = caller.test(); + assert(res.len() == 64); + let s: str[30] = abi_decode(res.as_raw_slice()); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/test.toml new file mode 100644 index 00000000000..526e7df8fdb --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/test.toml @@ -0,0 +1,4 @@ +category = "compile" +validate_abi = false +validate_storage_slots = false +expected_warnings = 0 From 6245ee60187291c8614dfd564cc9a6d684dea0e5 Mon Sep 17 00:00:00 2001 From: Sophie Dankel <47993817+sdankel@users.noreply.github.com> Date: Tue, 19 Nov 2024 08:49:41 -0800 Subject: [PATCH 22/52] feat: add function for generating bytecode identifier (#6674) ## Description Depends on https://github.com/FuelLabs/sway/pull/6522 Related https://github.com/FuelLabs/forc.pub/issues/16 Adds a function, `get_bytecode_id` that generates a sha256 hash of the bytecode with the configurables section of the bytecode removed. This will be used for indexing and lookups of the corresponding ABIs for contracts, predicates, and scripts in the package registry (forc.pub). ## Checklist - [ ] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] 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). - [ ] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: Vaivaswatha Nagaraj Co-authored-by: IGI-111 Co-authored-by: Marcos Henrich Co-authored-by: Joshua Batty --- Cargo.lock | 2 + forc-util/Cargo.toml | 2 + forc-util/src/bytecode.rs | 170 ++++++++++++++++++ forc-util/src/lib.rs | 1 + ...-configurable_constants-missing-offset.bin | Bin 0 -> 5328 bytes .../bytecode/debug-configurable_constants.bin | Bin 0 -> 5336 bytes .../tests/fixtures/bytecode/debug-counter.bin | Bin 0 -> 4488 bytes .../release-configurable_constants.bin | Bin 0 -> 4328 bytes .../fixtures/bytecode/release-counter.bin | Bin 0 -> 3456 bytes forc/src/cli/commands/parse_bytecode.rs | 14 +- 10 files changed, 177 insertions(+), 12 deletions(-) create mode 100644 forc-util/src/bytecode.rs create mode 100644 forc-util/tests/fixtures/bytecode/debug-configurable_constants-missing-offset.bin create mode 100644 forc-util/tests/fixtures/bytecode/debug-configurable_constants.bin create mode 100644 forc-util/tests/fixtures/bytecode/debug-counter.bin create mode 100644 forc-util/tests/fixtures/bytecode/release-configurable_constants.bin create mode 100644 forc-util/tests/fixtures/bytecode/release-counter.bin diff --git a/Cargo.lock b/Cargo.lock index 159d6d5f8cd..00233a2c23b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2958,6 +2958,7 @@ dependencies = [ "dirs 5.0.1", "fd-lock", "forc-tracing 0.66.4", + "fuel-asm", "fuel-tx", "hex", "paste", @@ -2965,6 +2966,7 @@ dependencies = [ "serde", "serde_json", "serial_test", + "sha2 0.10.8", "sway-core", "sway-error", "sway-types", diff --git a/forc-util/Cargo.toml b/forc-util/Cargo.toml index b2b5cdded43..a7bd7364a7f 100644 --- a/forc-util/Cargo.toml +++ b/forc-util/Cargo.toml @@ -16,6 +16,7 @@ clap = { workspace = true, features = ["cargo", "derive", "env"] } dirs.workspace = true fd-lock.workspace = true forc-tracing.workspace = true +fuel-asm.workspace = true fuel-tx = { workspace = true, optional = true } hex.workspace = true paste.workspace = true @@ -23,6 +24,7 @@ regex.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true serial_test.workspace = true +sha2.workspace = true sway-core.workspace = true sway-error.workspace = true sway-types.workspace = true diff --git a/forc-util/src/bytecode.rs b/forc-util/src/bytecode.rs new file mode 100644 index 00000000000..7bf71cc2302 --- /dev/null +++ b/forc-util/src/bytecode.rs @@ -0,0 +1,170 @@ +use anyhow::anyhow; +use sha2::{Digest, Sha256}; +use std::fs::File; +use std::io::{BufReader, Read}; +use std::path::Path; + +// The index of the beginning of the half-word (4 bytes) that contains the configurables section offset. +const CONFIGURABLES_OFFSET_INSTR_LO: usize = 4; +// The index of the end of the half-word (4 bytes) that contains the configurables section offset. +const CONFIGURABLES_OFFSET_INSTR_HI: usize = 5; +// The count of the beginning half-words that contain the configurables section offset. +const CONFIGURABLES_OFFSET_PREAMBLE: usize = CONFIGURABLES_OFFSET_INSTR_HI + 1; + +/// A tuple of an instruction and its corresponding bytes. Useful when needing to access the raw bytes +/// of an instruction that is parsed as [fuel_asm::InvalidOpcode], such as metadata in the preamble. +pub type InstructionWithBytes = ( + Result, + Vec, +); + +/// An iterator over each [fuel_asm::Instruction] or [fuel_asm::InvalidOpcode] with its corresponding bytes. +pub struct InstructionWithBytesIterator { + buf_reader: BufReader, +} + +impl InstructionWithBytesIterator { + /// Return a new iterator for each instruction parsed from raw bytes. + pub fn new(buf_reader: BufReader) -> Self { + InstructionWithBytesIterator { buf_reader } + } +} + +impl Iterator for InstructionWithBytesIterator { + type Item = InstructionWithBytes; + + fn next(&mut self) -> Option { + let mut buffer = [0; fuel_asm::Instruction::SIZE]; + // Read the next instruction into the buffer + match self.buf_reader.read_exact(&mut buffer) { + Ok(_) => fuel_asm::from_bytes(buffer) + .next() + .map(|inst| (inst, buffer.to_vec())), + Err(_) => None, + } + } +} + +/// Parses a bytecode file into an iterator of instructions and their corresponding bytes. +pub fn parse_bytecode_to_instructions

(path: P) -> anyhow::Result +where + P: AsRef + Clone, +{ + let f = File::open(path.clone()) + .map_err(|_| anyhow!("{}: file not found", path.as_ref().to_string_lossy()))?; + let buf_reader = BufReader::new(f); + + Ok(InstructionWithBytesIterator::new(buf_reader)) +} + +/// Gets the bytecode ID from a bytecode file. The bytecode ID is the hash of the bytecode after removing the +/// condigurables section, if any. +pub fn get_bytecode_id

(path: P) -> anyhow::Result +where + P: AsRef + Clone, +{ + let mut instructions = parse_bytecode_to_instructions(path.clone())?; + + // Collect the first six instructions into a temporary vector + let mut first_six_instructions = Vec::with_capacity(CONFIGURABLES_OFFSET_PREAMBLE); + for _ in 0..CONFIGURABLES_OFFSET_PREAMBLE { + if let Some(instruction) = instructions.next() { + first_six_instructions.push(instruction); + } else { + return Err(anyhow!("Incomplete bytecode")); + } + } + + let (lo_instr, low_raw) = &first_six_instructions[CONFIGURABLES_OFFSET_INSTR_LO]; + let (hi_instr, hi_raw) = &first_six_instructions[CONFIGURABLES_OFFSET_INSTR_HI]; + + if let Err(fuel_asm::InvalidOpcode) = lo_instr { + if let Err(fuel_asm::InvalidOpcode) = hi_instr { + // Now assemble the configurables offset. + let configurables_offset = usize::from_be_bytes([ + low_raw[0], low_raw[1], low_raw[2], low_raw[3], hi_raw[0], hi_raw[1], hi_raw[2], + hi_raw[3], + ]); + + // Hash the first six instructions + let mut hasher = Sha256::new(); + for (_, raw) in first_six_instructions { + hasher.update(raw); + } + + // Continue hashing the remaining instructions up to the configurables section offset. + instructions + .take( + configurables_offset / fuel_asm::Instruction::SIZE + - CONFIGURABLES_OFFSET_PREAMBLE, + ) // Minus 6 because we already hashed the first six + .for_each(|(_, raw)| { + hasher.update(raw); + }); + + let hash_result = hasher.finalize(); + let bytecode_id = format!("{:x}", hash_result); + return Ok(bytecode_id); + } + } + + Err(anyhow!("Configurables section offset not found")) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_get_bytecode_id_happy() { + let bytecode_id: String = + get_bytecode_id("tests/fixtures/bytecode/debug-counter.bin").expect("bytecode id"); + assert_eq!( + bytecode_id, + "e65aa988cae1041b64dc2d85e496eed0e8a1d8105133bd313c17645a1859d53b".to_string() + ); + + let bytecode_id = + get_bytecode_id("tests/fixtures/bytecode/release-counter.bin").expect("bytecode id"); + assert_eq!( + bytecode_id, + "42ae8352cbc892d7c7621f1d6fb42b072a08ba5968508d49f54991668d4ea141".to_string() + ); + + let bytecode_id = + get_bytecode_id("tests/fixtures/bytecode/debug-configurable_constants.bin") + .expect("bytecode id"); + assert_eq!( + bytecode_id, + "babc3d9dcac8d48dee1e5aeb3340ff098d3c1ab8b0a28341d9291d8ff757199e".to_string() + ); + + let bytecode_id = + get_bytecode_id("tests/fixtures/bytecode/release-configurable_constants.bin") + .expect("bytecode id"); + assert_eq!( + bytecode_id, + "2adfb515b66763fd29391bdba012921d045a0be83d89be5492bcaacc429695e9".to_string() + ); + } + + #[test] + fn test_get_bytecode_id_missing_configurable_offset() { + let result = get_bytecode_id( + "tests/fixtures/bytecode/debug-configurable_constants-missing-offset.bin", + ); + assert_eq!( + result.unwrap_err().to_string().as_str(), + "Configurables section offset not found" + ); + } + + #[test] + fn test_get_bytecode_id_bad_path() { + let result = get_bytecode_id("tests/fixtures/bytecode/blahblahblahblah.bin"); + assert_eq!( + result.unwrap_err().to_string().as_str(), + "tests/fixtures/bytecode/blahblahblahblah.bin: file not found" + ); + } +} diff --git a/forc-util/src/lib.rs b/forc-util/src/lib.rs index 003d50898ad..03775dcf8f1 100644 --- a/forc-util/src/lib.rs +++ b/forc-util/src/lib.rs @@ -23,6 +23,7 @@ use sway_error::{ use sway_types::{LineCol, LineColRange, SourceEngine, Span}; use sway_utils::constants; +pub mod bytecode; pub mod fs_locking; pub mod restricted; diff --git a/forc-util/tests/fixtures/bytecode/debug-configurable_constants-missing-offset.bin b/forc-util/tests/fixtures/bytecode/debug-configurable_constants-missing-offset.bin new file mode 100644 index 0000000000000000000000000000000000000000..cedfa0b99ae3d6b709335b707dfec5162b423aea GIT binary patch literal 5328 zcmbVQO>9%y6+Vug;V~uRc49{Ei-vJgK#x^j3N-Xbb6;)u*>R%W6et-H$7%UXrO`BU zA&S%mUPkIBt<-jQWyzw8mp`XVFOj+^OVmo0k;(#{OTowY z+`sdE-#PbQ?Cl)gBw)@m>J9U%# z*eBpiz?XU5mmGvI1K&aTz83Q-_?*CZGUodud?WCsFz#H;_gDC2u%7$6FExt&ll??t z&z4n}G+NuDge_+Y-(OVo{ufoxPt;3f4Hbu_a8nZPFVOzNeoV2rQZ+k&pU1s||CRDq zmSBHV<=1z3yyK=D%4<$(yO?TVtup)+thI|VyI6~2YrRDK%N}bLg0=SG-@{t>G1qrg zenXEB)@p@oseH4we~#p+?eTua4%XdKmGunwu^$PtA7*2*CI8IpDbE*}Q#jba%5UD$ zHpc~9dFvdT_Sug`eEb75ezT=2E6dpHDdlFZ`k2P0rSg8ZUcgv)SSoMB3gXP;shtYR^G3;wUj>nYhw=0NgVtuKu zFyHtQvLEN-`+i|h+^50vaBHxfC3}o$p+v_p@7=e|Yw^6bt*;aM{mJx81ONE?$yWjX z&w<@%Vaz?S`&+>E=hgfQfve}$ivRh^@zjqN#;6ZE`sG=5kRynqe(agrZuzk9y7@vEjVW1Dt?f!A!S%G$D-Gu?t-+uGJzSYa-(R=QO^?|-{G;g0~z zbD}Kd5%3FM6Q~9Kn6qza{B+|4xOP4$NL$U5C>P{RnMk-oA|AiCC4XGo%3VUdQ;2n^ zvkz~Lw5|8I(cPc7>2%twN+4ex?A44zUtsnOdHf7`C*MbnS&+oq-a#MEw*b4%sm?m! z3^~ugtsobt5O=GK<%-m{%Q>*}AZ$n6-$mTt!&=|R*pw)z8gGf6ICfQ8y${`3PWebf z6bl49p$u^;82hkfju_jOjdK@ zIAHQaVB$dwCG5!(<@DPy>FA+`{UY});ij?I)d#@fGBB71232Un#I0jp<9P!Pn^M~b z17mA!Hi6?trrU3GsnajNxdfldCxhd?uCI9y_-}W|`O6)jw`zF681Ox&iUN47ZexEl zvD$mreyERyxKD=I*Pe(0 z;68x(lkXSPjfDd4fO#MK_6=5A!~T2+pFC_ni#|?C``^U(Nzr5P*&yE~cpc!q4vn87 zF+SX?jYBI~4|fCLDh7b-(cciTe6Hv-VEcPuJi0>!tPe!6whY$5xzgryOXsrVt&{y! z5XM{f^K3Z&KrsGrWPH|)Z{yAoKdUHb&i`yL-^sw2=rQhC;Opz*8w&0KNoa@|yQ41h zy0U%ntNI&vROH!FoMY7qwBh>$)85A%_h?VD-+oFQYu0`)!dMUYjJ0xy>0} z&3hPxj&V*Ms=C=AH+?ZvB-mN4$)Q5p+?Tno=Y7HFGq`=1{pPIpGhzRsf{6CbMEkN< z!+zkIV)N>AzZ*v`9><6KIYWL`8af_z-nSTQbLW+>-Tk1WU&Zo^?@X3s@~f9d51G1W z;zGEe-l3m$)o;V~D%W3Gp0PX+ZxfWro`cIp>^-{cVq9>ri0`z_D_ zwA3GHN$;I;gU*r|GlD$FS=3J$TS5&M&SaW3G{Bm`ooQbV0jKktgGq6CW)ixKjKjQK zA90=)xE9TK<~H?*-xDEEs2v@iKI)MVLG5T$722+rv#1})0obOVqHZGpYMd9~D$pkC zNr#It$D-OSb!vZ?i^zK{uFb@$7#DnR54EW|jJ|V$%fFb5I7etdqwzu>%uEWdgMGj$ zc#CPAx*X)e2jkbpsT9E})N?eZ`5rN4->k31jaW=75|aXFcpvCGow6T6;}7F^LOP~n zfi@!CPHEf4eUkUjdV(Ft0h-DMV>9T3J2f;xOL>hiIN*?mOmO z?{X_lF7)%6m4q#vt)hfpv)VqtA*;}@u64zNtl>VS^@TT2svk8%6fT6&8Te+c>D+K>JI zPqj3R9cR@6#A)H}F7dwW<2xj{P6X$R&do@iVU3KQ^CRJ0QJf+;W;-|nQ}p5cE;NI4 zIPWI{EJq@1gt`BJufg#!Z;{&4YyR7jI=|dQe~ZvrhHEi$EaPnHT+cz{8OPh8>Sh0( z>LvdG>a-;$@jjj`$^{j?kNN(0@gkkL!0+R$(w@Tmc=D>`dTZXtKK?&o_F!#Gy^DJC z73NOQYw~DT+sH3q$Zzpb&&v@#-{zX@;T*%~CH`LFZ;yW@_@Brp{Ecg#{)piF`mJl9 nuo7&-6@HYcc#~T2q^1IPg*dDs8|zb9*LLmxAhRXeB}EAu)pn)8rl{6`DiEXs zYY75+FpmOyQ46%qtv>qD!|IRfkw*bN)JLNQ3L1zHMl3);Ye$NI)bGvglIs<%v?U;O zIB(v}yzl$on;F~NS-MS>B>hRv1m8=Qy=Fq}?a^WnG~xTpO3weX;`xbMk*vYOkQ8oGqW=Z@U)YZ+7FV)r=kBxL zE7)HtZ+Q{zZ>!we4*NT9s;<1oq;40Ib*xo_or1NV!{<5HqS#t5(f_i`TKQnDJ=piK z)_u(NJ(XM6{=r(!a4nT33(P4T z>|fzjg|_n6I5uswAB(vE1LMEZRORI*?De#AGgfUxn|#~Wdc{bm9qcEsnO(5=0~UpI{NiFNu;E7RbHl5QIZ;w z7nG8x)Wq_3ZITks<-WRdm8IM60JjD3N^87b<)96Ho{{L!8Xocz*e{|j9rqGAY0P4O zQu986woKAVtZBUef?|9&flu0S zx#n=}_9Ni@FrHg&{TY9)zeX#Zi(|X$0t2tnQsvbpGiRy^y|#2)YhjtWz*?zh<)Z)H z%9wv1SY8k%AqT)Ocuk-d^kL4P!O=7Ili=EUKQC=HOQMvQQzatd3W<39>X!Uzbt^l8 zcqb9-PJ18TD(SY~-+E_%-iFieuPA|haj;k8hq1uy8S?lU@a}yNHD+ECYkLP{INt*7 zHYVHafHUMg|F(i$oJ8Es4wlPOw_VPGs{`z~dJ1m{Gaq>GnRo)dk%)d>IV1CN@}4CN5}B zc^k7=fiH5ggnhJ1 zaM+N#Z7?uxjm-vdTu*n#Z7jCO!Gx=n2-0avIo4|j&M#dwH)xeP3sNp(b+&*q4p|DNd1A1u^SegB|EJ9n3CZ;9+Hb+RW~tnbX5&txhy&fv~+ zwvdN8e^R$|Yr4Jvyr;3?yg7`zXkl*72WxO7*%YIxCi2d5Mo;jXL4T@iKgOXx=HoUQ zVqbkC`hj~t;_rR0kgCt;aR+xX@Y;%60Q&H10{W;+$w5?%a`2ezIrw!z>I&F;5VyY%<6-F`|OYsTIcVXQ~G##+8h_84$_ zB50n-<~XH+?ZxAha`DlY{w`xi52F&-sGSXK?!t+s#?+r^E4sc@Z6( zj*exmhU369#pc!LekYD>JdO|cbB6pX*L6JVqHi(Q=FTf$yZb>$zlr4+-viD z_M4}EXsIvIlHNPx2A%c7=REQpXHg%)w}=`nobeQEsGl`~JJY@#0!|k-2jk+%)Hrk( z@x#1aA90@Lxfac~=Qj0+-xDEEs2y#dKJ1bYLG5T!1=_BZGN>QO0klm$McqXHRXH!f zRiI7OlQtJ&jzzUuY}ft{7m@c^T$_p0F)sMt9%@r_7=7mgmwz!AagNY`R^x>{m>L&c z2YY~1@D|fJbvVd@55}*9Q!#>5sOM-*vt44!yjfp~Td|l_BqjyU@IKIWI%z+G#vjJ- zgmhfT0&PUNoz!g?_etJA>j~{R4$xFK@J(Y3?$pp+4w~aO`+ELNq~GYigTrhW9HM!K zx$l~Dy~C|AxzNXFRxjGZ*(ylrHKW@X*JTCz)wQmWmsQ+{wEoL{KIz=fM%L`6Q5l|3 ze23t(f!|nqj;$e%EsHZmpqABP=R1_PL$7ZIdX-^Q3qAx;Z#cZv6158oldbs{)lbZ$oC3~OZcoIfAV6~!rnW2TKGFvS?Y z??N*;hjV@+!18=#jWGBB?=?6c<}FfNy3KzlQsJneYv zRJr26RhjS)p-x+39Pi`tf}B^u`o)QW81h>@)bmnA&v&@ydN{}UvxiUZ#_hS7&-6@H{io0T1VY*DGQLaI$dshgl}*hDt$xPW#+Zb@1uxUOPHC_+;}Y9Kk- zVTo99;w0XnK%ql{G6mY|=pty~tPW_ISy`17dr~bIcTMaUMJH!BjqE;6r;O)PwlDp^a*xKPFs( z^Xp5}$5Nu>Ro0iFFF>3RBL7L~{ic^|6(hPlrEAXj7TU|G=BIq2_5Jx&I`wChSIVkoqIIY;h{O%wWe<={_R|6|a9AfkT* zdY{qyPeOk;qQ4o@fBg&ezo+%bq3h}~dl=7qp3--)dfsK663y(AiT_v2`2R=dk1PY9 zF9IVM8~Fsy=AkcNC*;b+U1WF-<4o-i&7y9y@O#p7IbSWlyGg4g^VN^6tGQecii7pw zlTg087(8691m6O#r*Wq#QA+z0rA%j~NHNrW5^M3P@|-_=n#g)MZyR2nL@96AN<_#< zifbKpRj>8z@6~$QC*gkY*6XlohuoI+2b>PuNzJ$tepz*?aU$+PA zt>bcz`#>(OBd)M#96`S(+V`6j?h)K+;4s=ALu`% z_0LE2zo_&#$yn%;Jl{k8{W}=0?PEp-{Iduf&%*YZ3ESAThh@HNEN;+v`6&LgWOzg? zr|D7fW)@s2m^Y2h?C_ZrtQUAX06AO9O^lLz(kQT;*pGTpd5}D@iz5!`+8P6f4&Z+F z1M_2#pGhnlpW2*{7maN*%=i3=d>@bGdnccfd@HwgNfln$5L^yj%7|eW&;v zJizkmy^w2X^_mr~AulQTV@{#Z?tT~0-!&cztRHwNpqD$|V(Sy&*tE_h?GtYD2zu6D z+-Dtpdk~zX_@$JvQLBfU<7#&VV~NlHko*2rDKFm%!}+;PG1NV9>WElW4{~~4V#v*K z{U@Q*gRL>SzQbREkC^0p05Q#tJ7mMJ*fAombKi3a`9N>uT!1?vb6DXG_r0AR#`Lv8 zjmK~8)cA8g8H=cM=&1F~b39I=51>ZQ3G@Qg|Fj;H)A)u=1u}_;+_aC{JB!@+&!boI z_&n|(7_fnXeUWc6iV_$5(W8^c&>xYvv(gT9Ab;oheTDC7J;Dy_Ha+NIESMY{a>ZCg z+~8W=E%0xH!&k$7+~q3tR#1OiqcKe`--G5%lldI-o>ys2D)|vS#PZBROR!g-@R93V za_-K6TieIwymZuuj;(jf>EB_0N%=E}{nl;d4tDUS%C)&iGlo0xdGZ}MVh9rpyKOvHctH&EN6O&6=142T9-}YjHhVPR2&wvewx-@Pr4h!@Y0Y zAug_IuA3g6PQfkKZ*an=)3!XJLY8gbd)h@%ec@V_u#a{cKMdQ^?)uvx%YJx<~sJt&5bDf37KO z0{G**2)R=8*u5NfndsXZSKJ#Uu7HC{%=w(;*XVB`$j=V(?QpZZsO19@jDItGmm{6_ES^(_nCa}sNTT55U)8N^IhV+8siG5&)P$}1IfkZqPD)tj(){NSGB z&e+-y%;$XUJ>ZpaKN3&*4mhhR@dVD|-$D1{DYnf%n&4f?G3OMmg_}}t`1ca-@_j?* z5WWs#3Ew=UVj0)5q;)J4I+h2&o>=1F;aFhv%f!;VUo0=YeEAYEMnAdmLgT{43v!N6 zdg;==-yh3AieLJ{)yhjB-2LfOAAR($^|N<>{>wt};S<*$S*|_4=NEtdeYeJEi4Oin kk99qoYK&WY)Zei{eaCL-@wy(@)JXr-7&-6@HXfG2J-O1d>{M6+0{-yK5kA+4!e&eei5acF9nzMi5=gwdkdj$W_ra z6&Ohn&_ju$2LrvRMbrAI{v2{Cu#!l_M;>$3r9IO~)L4iK=uiVTf>iz9>@G=>j1m)| z_;%jDnfHC~XP(Uc1T7O8q(5RU_}wTT)Fa~Hfc`-AL-pytr9P$;sv#-<^gPXd))-Kq zHH>A7{0F*8=pxX?4(kSf37v%QICLkwbbp0T1-f%xx=)}hL1)13@?qWJi_k3w=h

qE>n$ zw99;f-Ev@8hux%dYAUp2x%ZrbznM9lGhL0c&fJZY`7qJ#%P{YWeT3B!fnRCryNg|Gk8CJp`voteZ5zf_pR;&@1onJZUnb4z9U93_)JL+wIYqRZp;xf)y(9L$ z672iI5&OPwCN+n5kKo}X^KdRd@$%{v4FKP-FG(ULrL9sjrZSS$l)S8zJg2U2Hp+7p zv91kOl&zv#w#Qf&ceR{0D)V*;xmSGvUSgIXo0z$WeRO{G?PwV}jktdht{1O+7mKsrrK00~Uu1IywTv-?LX0~q`yOd7y9;IcF9uCW(NDA9*qk0kATbb{Wt0=xykjxabjE_ zhU>s}8MuB>OnO&fYly5-IRYCoHZ{FfFVEwg{8(Ms1&*zuW1ifO1MAzsx&W+q;E!r! z-Ck^Cy^kIPU)WE(ltAs$d=^|yS9g%BF|JwEU4rY$+)beNyJI`>d%vG}lRgfv)7plX z5x1g^{)%Vd4{);HQ=wkvw&I~3@TY)3jkx{@K1D@#^eFtT*t&jfKLp+z!246+y@@k? zjGF)L$u{2FP780cwgbGe_VfK1e4T4Q*XES7-Dp316)pR<(Bc#EdPAj!0G0;oW?tFx zC@`V+fHmpe^J@<^>C`0b(bsfN;JM0Y>F3_Q8~L|iGc^hBo?<`Y*O|w402|Jot;KL1 zoc;KWEjTZu4|Bk>t;mo_R=l&Jc=_dDS#9QaydbkemUkCT+vCjqggxvdb?vZ;B zfcHAi#C>%^*BSORfDgF0qlm|C#N$oG<1OT02hZC+cbdm`U5SNtxkB`>_lbV<=O}uK zz7I*7$qh1{bux1mGG`m;+tBUeF8avp>hW}*Ib+=L%TPDHxVcyAe&-VRc*G@&xJ1WO zh7@T-y6FVh4xUF_&u%j@Xcjc5sPzKZ`f;{HZdpEuj1w~V+^iwZ{}L?|z0~K-lR^K} zc`=?Z)J1-@?&gWaHN}{}@kavAXOiv#_g{ejji*H5;aJFn&jIk~8pQc-J^}t`@$mg) z!TVPazwdK(c-EkA@qNV{cCCMtdFiu0ZqD{yA7f1A0>w^e&&cBSeR>(ccowJg7yW1a zp2A%UuA-;&sd{l1@8mBMubr|dfB`t3i4eop0K;%Mh9dgWJnrKn^Oa9X*G|AT-f27B zZHw72b|`PAeJ=Xt4fwy&kv9>JaUUK|1Thr;UE&EdB`AzL;ukZYB|p)mD6LsYM z3HLF4-Rn6^`ty-Dd@CO(ZNoipwpzhH61joCmO?KJWZa2dN8nR+V16}-ZwqtCC+7y^ z;M~A{6&1*@KKapO56O z404aLnrR6R;#!`q$>I!pLpp`tp!>D3a#h_Uz-^-Ays*c#`YO&7VJ_*rxM@_(q^Iu? z?oY569eEh`*;bE&{d4r0$a@`e>Dy-zyQ?~1z~^)HnZd9Zgjo0v?CP(BK@EKs?2#j| ze-(Ru_7`w>5c&%4*89YI4Ka;bGh-5Y6SJE5pT$A`@hs}psOWkx6mNRRFsDSt3}*jp z>B?#$nEeZw{ckMDvvWNAFH3WtXaD73_V+SwbLqI-EPV|#$&1)CruX#owWMX_t3H!+ z^+}v#zuu8M2h5*?e$1Z(e98;UE9H0Hw|@2RouB_~rF{F%cNX6BwfuMZANcb*zW>Ab a0AGsmpN>!X91Ye)@Ox)v;T;yk_5TB0wCCvn literal 0 HcmV?d00001 diff --git a/forc-util/tests/fixtures/bytecode/release-counter.bin b/forc-util/tests/fixtures/bytecode/release-counter.bin new file mode 100644 index 0000000000000000000000000000000000000000..9f504b1c6876c0967d4336304e452a097a7fbd8b GIT binary patch literal 3456 zcmcImU1(cn7=F{8xOD66r%Sbd-RzmBT{irQTQ^n|cS0JHn1!6ujaek5I0x>+S%VwG zE*22P3&C!n?!t?RIC^!`|0%u%^v$f(*XS+GSwhE<2dCOJz=L7YLzTS;>l=L^JO>SThe@O@I4K_8$KWJ zOBrXnlonLVJJXdT6cM?YTW*=tcHX(c=XlP*S;&e-BHoG-c2R^YFV? zZdp;>g<;=-ov$DAWJg`lT56wGdTq5&#$351NZwu(N0;@UwdmDSs=Y-diTURt?_=2U z68!ANy3bD49bXRomwjN^0w&qYhKGYA%AN?KH^A+wES_%Zv^C51M=toM*f_Z z-ve3a4qDy*^}H!@H?sDA&j$BldAvat%b-#4NNW}~Ru{1K8NS2%Z22z5kQ)=RALM#N ztg^_{Ao6U%kEYtIoH>USjmnvG)2A;@IYXtQvjg?A6SNVLHmreM)IFP}5b8P%x}KrJ zSatLWQGDkFNqd$=a)Qc98}(M7LEfJ$w-V2zMqWT2*c~19OTG@|u+h0+Xut=q)4{lB z%iA3~XZ0TT4BKfT;Liu}^F=#pMi6`MDb%l14bgc@2TcaLge(GorqH8D5sS$I zV3gHOvs+FzXnWxR{t4uf=+bziqi}`f)q_FX9&Bm~Rlb{~GtHnGr&L1vrY|O^=i=Jo-pH?Mf9vw_3=>NS|fX0({qm}ygIMXsXh05st$}) z{cm#rqi-Up+g_GElrtE+B11X!Zx*$hoh7?icgJ%^0~q@V`e+9D(TAG%`U#kUp6|!K zUA`-}DBkp#CDJkE^xeE+<7O$PeCGzc*n^VtbM-=n5SqBAolZ{2{)}mY@G& zo&WQJ__tT<{*5Zh>Iq()kUG8SgQn_fU_(y!6ZhQmn zh|Xh8(HFmExwa=4{c>xKZ1sMC9VX}#$_~ye?~~A#s#o# z;g<64Z6as7Dj%&V>V*v81J5)wp2mF3I9b$TmT_loPlqh-X`TByxlDdd`MD3~#?*Qr z)q49`Z>iW8qL6U$Zhnm4&F~F9IAE>X!RPddrR~6etcq{j?40my%uTqceV)hJINl-M zZ__grI>k1cX<>oxrlQL)D!T6X9`bup$IuM;;?JA)e0f~^vR(TU)xHe;PriJ~zChh#0s)32N>p89^}y?xiNU5XdZ2IJvZ<=N1A?mBCg|;TVbxYG*drZ9!dTVH2uQk11((9bJ(yw~`S+76p_4=P# CXaaQr literal 0 HcmV?d00001 diff --git a/forc/src/cli/commands/parse_bytecode.rs b/forc/src/cli/commands/parse_bytecode.rs index 4d5ecf0bdb6..0ffa6f0ba4a 100644 --- a/forc/src/cli/commands/parse_bytecode.rs +++ b/forc/src/cli/commands/parse_bytecode.rs @@ -1,8 +1,6 @@ -use anyhow::anyhow; use clap::Parser; +use forc_util::bytecode::parse_bytecode_to_instructions; use forc_util::ForcResult; -use std::fs::{self, File}; -use std::io::Read; use term_table::row::Row; use term_table::table_cell::{Alignment, TableCell}; use tracing::info; @@ -21,15 +19,7 @@ pub(crate) struct Command { } pub(crate) fn exec(command: Command) -> ForcResult<()> { - let mut f = File::open(&command.file_path) - .map_err(|_| anyhow!("{}: file not found", command.file_path))?; - let metadata = fs::metadata(&command.file_path) - .map_err(|_| anyhow!("{}: file not found", command.file_path))?; - let mut buffer = vec![0; metadata.len() as usize]; - f.read_exact(&mut buffer).expect("buffer overflow"); - - let instructions = fuel_asm::from_bytes(buffer.iter().cloned()) - .zip(buffer.chunks(fuel_asm::Instruction::SIZE)); + let instructions = parse_bytecode_to_instructions(&command.file_path)?; let mut table = term_table::Table::new(); table.separate_rows = false; From 3639c542f2d8be9fd98f611ff6a3b9752bec93ba Mon Sep 17 00:00:00 2001 From: Sophie Dankel <47993817+sdankel@users.noreply.github.com> Date: Tue, 19 Nov 2024 20:11:55 -0800 Subject: [PATCH 23/52] Add comments about bytecode test files (#6741) ## Description Adding comments per https://github.com/FuelLabs/sway/pull/6674#issuecomment-2485688098 ## Checklist - [ ] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] 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). - [ ] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: JoshuaBatty --- forc-util/src/bytecode.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/forc-util/src/bytecode.rs b/forc-util/src/bytecode.rs index 7bf71cc2302..7f73f39969e 100644 --- a/forc-util/src/bytecode.rs +++ b/forc-util/src/bytecode.rs @@ -117,6 +117,8 @@ mod test { #[test] fn test_get_bytecode_id_happy() { + // These binary files were generated from `examples/configurable_constants` and `examples/counter` + // using `forc build` and `forc build --release` respectively. let bytecode_id: String = get_bytecode_id("tests/fixtures/bytecode/debug-counter.bin").expect("bytecode id"); assert_eq!( @@ -150,6 +152,8 @@ mod test { #[test] fn test_get_bytecode_id_missing_configurable_offset() { + // This bytecode file was generated from `examples/configurable_constants` using an older version of the + // compiler that did not include the configurables section offset in the preamble. let result = get_bytecode_id( "tests/fixtures/bytecode/debug-configurable_constants-missing-offset.bin", ); From 94a066652468b4afa3bd396dacef482ed590976b Mon Sep 17 00:00:00 2001 From: Sophie Dankel <47993817+sdankel@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:15:14 -0800 Subject: [PATCH 24/52] chore: bump version to 0.66.5 (#6743) ## Description Bumped versions and ran `cargo update`. ## Checklist - [ ] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] 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). - [ ] I have requested a review from the relevant team or maintainers. --- Cargo.lock | 195 +++++++++++++++++++++++++++-------------------------- Cargo.toml | 50 +++++++------- 2 files changed, 123 insertions(+), 122 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 00233a2c23b..d6df20e9c24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,9 +102,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd58d377699e6cfeab52c4a9d28bdc4ef37e2bd235ff2db525071fe37a2e9af5" +checksum = "9fce5dbd6a4f118eecc4719eaa9c7ffc31c315e6c5ccde3642db927802312425" dependencies = [ "alloy-rlp", "bytes", @@ -612,9 +612,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.49.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53dcf5e7d9bd1517b8b998e170e650047cea8a2b85fe1835abe3210713e541b7" +checksum = "6ada54e5f26ac246dc79727def52f7f8ed38915cb47781e2a72213957dc3a7d5" dependencies = [ "aws-credential-types", "aws-runtime", @@ -965,9 +965,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5327f6c99920069d1fe374aa743be1af0031dea9f250852cdf1ae6a0861ee24" +checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03" dependencies = [ "borsh-derive", "cfg_aliases", @@ -975,9 +975,9 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10aedd8f1a81a8aafbfde924b0e3061cd6fedd6f6bbcfc6a76e6fd426d7bfe26" +checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" dependencies = [ "once_cell", "proc-macro-crate 3.2.0", @@ -998,9 +998,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", "regex-automata 0.4.9", @@ -1113,9 +1113,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.37" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ "jobserver", "libc", @@ -1206,9 +1206,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -1216,9 +1216,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -1229,9 +1229,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11611dca53440593f38e6b25ec629de50b14cdfa63adc0fb856115a2c6d97595" +checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" dependencies = [ "clap", ] @@ -1260,9 +1260,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "clipboard-win" @@ -2640,9 +2640,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -2662,7 +2662,7 @@ checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" [[package]] name = "forc" -version = "0.66.4" +version = "0.66.5" dependencies = [ "annotate-snippets", "ansiterm", @@ -2673,7 +2673,7 @@ dependencies = [ "completest-pty", "forc-pkg", "forc-test", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-util", "fs_extra", "fuel-asm", @@ -2699,7 +2699,7 @@ dependencies = [ [[package]] name = "forc-client" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "async-trait", @@ -2711,7 +2711,7 @@ dependencies = [ "dialoguer", "forc", "forc-pkg", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-tx", "forc-util", "forc-wallet", @@ -2747,13 +2747,13 @@ dependencies = [ [[package]] name = "forc-crypto" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "async-trait", "clap", "criterion", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-util", "fuel-core-types", "fuel-crypto", @@ -2777,7 +2777,7 @@ dependencies = [ [[package]] name = "forc-debug" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "clap", @@ -2785,7 +2785,7 @@ dependencies = [ "escargot", "forc-pkg", "forc-test", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "fuel-core-client", "fuel-types", "fuel-vm", @@ -2804,7 +2804,7 @@ dependencies = [ [[package]] name = "forc-doc" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "clap", @@ -2812,7 +2812,7 @@ dependencies = [ "dir_indexer", "expect-test", "forc-pkg", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-util", "horrorshow", "include_dir", @@ -2830,12 +2830,12 @@ dependencies = [ [[package]] name = "forc-fmt" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "clap", "forc-pkg", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-util", "prettydiff", "sway-core", @@ -2847,7 +2847,7 @@ dependencies = [ [[package]] name = "forc-lsp" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "clap", @@ -2858,13 +2858,13 @@ dependencies = [ [[package]] name = "forc-pkg" -version = "0.66.4" +version = "0.66.5" dependencies = [ "ansiterm", "anyhow", "byte-unit", "cid", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-util", "fuel-abi-types", "futures", @@ -2896,7 +2896,7 @@ dependencies = [ [[package]] name = "forc-test" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "forc-pkg", @@ -2924,7 +2924,7 @@ dependencies = [ [[package]] name = "forc-tracing" -version = "0.66.4" +version = "0.66.5" dependencies = [ "ansiterm", "tracing", @@ -2934,7 +2934,7 @@ dependencies = [ [[package]] name = "forc-tx" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "clap", @@ -2949,7 +2949,7 @@ dependencies = [ [[package]] name = "forc-util" -version = "0.66.4" +version = "0.66.5" dependencies = [ "annotate-snippets", "ansiterm", @@ -2957,7 +2957,7 @@ dependencies = [ "clap", "dirs 5.0.1", "fd-lock", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "fuel-asm", "fuel-tx", "hex", @@ -3798,9 +3798,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" dependencies = [ "atomic-waker", "bytes", @@ -4094,14 +4094,14 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.6", + "h2 0.4.7", "http 1.1.0", "http-body 1.0.1", "httparse", @@ -4150,9 +4150,9 @@ checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.5.0", + "hyper 1.5.1", "hyper-util", - "rustls 0.23.16", + "rustls 0.23.17", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -4179,7 +4179,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.5.0", + "hyper 1.5.1", "hyper-util", "native-tls", "tokio", @@ -4198,7 +4198,7 @@ dependencies = [ "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.5.0", + "hyper 1.5.1", "pin-project-lite", "socket2", "tokio", @@ -4661,9 +4661,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "7a73e9fe3c49d7afb2ace819fa181a287ce54a0983eda4e0eb05c22f82ffe534" [[package]] name = "jobserver" @@ -4747,9 +4747,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.162" +version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" +checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" [[package]] name = "libdbus-sys" @@ -5551,9 +5551,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.4.0+3.4.0" +version = "300.4.1+3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a709e02f2b4aca747929cca5ed248880847c650233cf8b8cdc48f40aaf4898a6" +checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" dependencies = [ "cc", ] @@ -5628,28 +5628,29 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.12" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +checksum = "8be4817d39f3272f69c59fe05d0535ae6456c2dc2fa1ba02910296c7e0a5c590" dependencies = [ "arrayvec", "bitvec", "byte-slice-cast", "impl-trait-for-tuples", "parity-scale-codec-derive", + "rustversion", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.6.12" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +checksum = "8781a75c6205af67215f382092b6e0a4ff3734798523e69073d4bcd294ec767b" dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] @@ -6168,11 +6169,11 @@ dependencies = [ [[package]] name = "publicsuffix" -version = "2.2.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" +checksum = "6f42ea446cab60335f76979ec15e12619a2165b5ae2c12166bef27d283a9fadf" dependencies = [ - "idna 0.3.0", + "idna 1.0.3", "psl-types", ] @@ -6470,11 +6471,11 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.4.6", + "h2 0.4.7", "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.0", + "hyper 1.5.1", "hyper-rustls 0.27.3", "hyper-tls", "hyper-util", @@ -6808,9 +6809,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.40" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags 2.6.0", "errno", @@ -6833,9 +6834,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.16" +version = "0.23.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" +checksum = "7f1a745511c54ba6d4465e8d5dfbd81b45791756de28d4981af70d6dca128f1e" dependencies = [ "once_cell", "rustls-pki-types", @@ -6976,18 +6977,18 @@ dependencies = [ [[package]] name = "scc" -version = "2.2.4" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8d25269dd3a12467afe2e510f69fb0b46b698e5afb296b59f2145259deaf8e8" +checksum = "66b202022bb57c049555430e11fc22fea12909276a80a4c3d368da36ac1d88ed" dependencies = [ "sdd", ] [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -7143,9 +7144,9 @@ dependencies = [ [[package]] name = "semver-parser" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" dependencies = [ "pest", ] @@ -7181,9 +7182,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "indexmap 2.6.0", "itoa", @@ -7635,7 +7636,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sway-ast" -version = "0.66.4" +version = "0.66.5" dependencies = [ "extension-trait", "num-bigint", @@ -7647,7 +7648,7 @@ dependencies = [ [[package]] name = "sway-core" -version = "0.66.4" +version = "0.66.5" dependencies = [ "clap", "derivative", @@ -7693,7 +7694,7 @@ dependencies = [ [[package]] name = "sway-error" -version = "0.66.4" +version = "0.66.5" dependencies = [ "either", "in_definite", @@ -7706,7 +7707,7 @@ dependencies = [ [[package]] name = "sway-features" -version = "0.66.4" +version = "0.66.5" dependencies = [ "clap", "paste", @@ -7714,7 +7715,7 @@ dependencies = [ [[package]] name = "sway-ir" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "downcast-rs", @@ -7735,7 +7736,7 @@ dependencies = [ [[package]] name = "sway-ir-macros" -version = "0.66.4" +version = "0.66.5" dependencies = [ "itertools 0.13.0", "proc-macro2", @@ -7745,7 +7746,7 @@ dependencies = [ [[package]] name = "sway-lsp" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "assert-json-diff", @@ -7756,7 +7757,7 @@ dependencies = [ "dirs 4.0.0", "fd-lock", "forc-pkg", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-util", "futures", "indexmap 2.6.0", @@ -7796,7 +7797,7 @@ dependencies = [ [[package]] name = "sway-lsp-test-utils" -version = "0.66.4" +version = "0.66.5" dependencies = [ "assert-json-diff", "futures", @@ -7811,7 +7812,7 @@ dependencies = [ [[package]] name = "sway-parse" -version = "0.66.4" +version = "0.66.5" dependencies = [ "assert_matches", "extension-trait", @@ -7829,7 +7830,7 @@ dependencies = [ [[package]] name = "sway-types" -version = "0.66.4" +version = "0.66.5" dependencies = [ "bytecount", "fuel-asm", @@ -7848,7 +7849,7 @@ dependencies = [ [[package]] name = "sway-utils" -version = "0.66.4" +version = "0.66.5" dependencies = [ "serde", "walkdir", @@ -7856,10 +7857,10 @@ dependencies = [ [[package]] name = "swayfmt" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "indoc", "paste", "prettydiff", @@ -8157,7 +8158,7 @@ dependencies = [ "forc-client", "forc-pkg", "forc-test", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "fuel-vm", "futures", "gag", @@ -8427,7 +8428,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.16", + "rustls 0.23.17", "rustls-pki-types", "tokio", ] @@ -8751,9 +8752,9 @@ checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-linebreak" diff --git a/Cargo.toml b/Cargo.toml index 31bc6386951..402b7679c42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ exclude = ["examples/*", "swayfmt/test_macros", "forc-test/test_data"] [workspace.package] edition = "2021" -version = "0.66.4" +version = "0.66.5" authors = ["Fuel Labs "] homepage = "https://fuel.network/" license = "Apache-2.0" @@ -42,35 +42,35 @@ repository = "https://github.com/FuelLabs/sway" # Internal dependencies in order to propagate `workspace.version` # -forc = { path = "forc/", version = "0.66.4" } -forc-pkg = { path = "forc-pkg/", version = "0.66.4" } -forc-test = { path = "forc-test/", version = "0.66.4" } -forc-tracing = { path = "forc-tracing/", version = "0.66.4" } -forc-util = { path = "forc-util/", version = "0.66.4" } +forc = { path = "forc/", version = "0.66.5" } +forc-pkg = { path = "forc-pkg/", version = "0.66.5" } +forc-test = { path = "forc-test/", version = "0.66.5" } +forc-tracing = { path = "forc-tracing/", version = "0.66.5" } +forc-util = { path = "forc-util/", version = "0.66.5" } # Forc plugins -forc-plugins = { path = "forc-plugins/", version = "0.66.4" } -forc-client = { path = "forc-plugins/forc-client/", version = "0.66.4" } -forc-crypto = { path = "forc-plugins/forc-crypto/", version = "0.66.4" } -forc-debug = { path = "forc-plugins/forc-debug/", version = "0.66.4" } -forc-doc = { path = "forc-plugins/forc-doc/", version = "0.66.4" } -forc-fmt = { path = "forc-plugins/forc-fmt/", version = "0.66.4" } -forc-lsp = { path = "forc-plugins/forc-lsp/", version = "0.66.4" } -forc-tx = { path = "forc-plugins/forc-tx/", version = "0.66.4" } +forc-plugins = { path = "forc-plugins/", version = "0.66.5" } +forc-client = { path = "forc-plugins/forc-client/", version = "0.66.5" } +forc-crypto = { path = "forc-plugins/forc-crypto/", version = "0.66.5" } +forc-debug = { path = "forc-plugins/forc-debug/", version = "0.66.5" } +forc-doc = { path = "forc-plugins/forc-doc/", version = "0.66.5" } +forc-fmt = { path = "forc-plugins/forc-fmt/", version = "0.66.5" } +forc-lsp = { path = "forc-plugins/forc-lsp/", version = "0.66.5" } +forc-tx = { path = "forc-plugins/forc-tx/", version = "0.66.5" } -sway-ast = { path = "sway-ast/", version = "0.66.4" } -sway-core = { path = "sway-core/", version = "0.66.4" } -sway-error = { path = "sway-error/", version = "0.66.4" } -sway-features = { path = "sway-features/", version = "0.66.4" } -sway-lsp = { path = "sway-lsp/", version = "0.66.4" } -sway-parse = { path = "sway-parse/", version = "0.66.4" } -sway-types = { path = "sway-types/", version = "0.66.4" } -sway-utils = { path = "sway-utils/", version = "0.66.4" } -swayfmt = { path = "swayfmt/", version = "0.66.4" } +sway-ast = { path = "sway-ast/", version = "0.66.5" } +sway-core = { path = "sway-core/", version = "0.66.5" } +sway-error = { path = "sway-error/", version = "0.66.5" } +sway-features = { path = "sway-features/", version = "0.66.5" } +sway-lsp = { path = "sway-lsp/", version = "0.66.5" } +sway-parse = { path = "sway-parse/", version = "0.66.5" } +sway-types = { path = "sway-types/", version = "0.66.5" } +sway-utils = { path = "sway-utils/", version = "0.66.5" } +swayfmt = { path = "swayfmt/", version = "0.66.5" } # Sway IR -sway-ir = { path = "sway-ir/", version = "0.66.4" } -sway-ir-macros = { path = "sway-ir/sway-ir-macros", version = "0.66.4" } +sway-ir = { path = "sway-ir/", version = "0.66.5" } +sway-ir-macros = { path = "sway-ir/sway-ir-macros", version = "0.66.5" } # # External Fuel dependencies From 278bb8cd19837898d3750918f0be30a85af916d9 Mon Sep 17 00:00:00 2001 From: Daniel Frederico Lins Leite Date: Fri, 22 Nov 2024 08:02:21 -0300 Subject: [PATCH 25/52] forc test single-step until jump point instead of patching binary (#6731) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Fixes https://github.com/FuelLabs/sway/issues/6720. Since configurables started to use encoding v1, it is not possible to use configurables inside tests, because `forc test` patches the binary forcing a jump into the test function before configurables are initialized. This PR fixes this changing the approach from patching the binary, to single-stepping the initialization and them manually changing the `PC` register to the first instruction of the test. Performance is acceptable, a test with a lot of configurables takes `572.382µs`. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] 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. --------- Co-authored-by: Joshua Batty Co-authored-by: Kaya Gökalp Co-authored-by: IGI-111 --- forc-test/src/execute.rs | 157 ++++++---- .../language/configurable_tests/Forc.lock | 13 + .../language/configurable_tests/Forc.toml | 8 + .../configurable_tests/json_abi_oracle.json | 284 ++++++++++++++++++ .../json_abi_oracle_new_encoding.json | 228 ++++++++++++++ .../language/configurable_tests/src/main.sw | 83 +++++ .../language/configurable_tests/test.toml | 1 + 7 files changed, 721 insertions(+), 53 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle_new_encoding.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/test.toml diff --git a/forc-test/src/execute.rs b/forc-test/src/execute.rs index 76e89324903..a0423caba12 100644 --- a/forc-test/src/execute.rs +++ b/forc-test/src/execute.rs @@ -5,6 +5,9 @@ use crate::TEST_METADATA_SEED; use forc_pkg::PkgTestEntry; use fuel_tx::{self as tx, output::contract::Contract, Chargeable, Finalizable}; use fuel_vm::error::InterpreterError; +use fuel_vm::fuel_asm; +use fuel_vm::prelude::Instruction; +use fuel_vm::prelude::RegId; use fuel_vm::{ self as vm, checked_transaction::builder::TransactionBuilderExt, @@ -27,6 +30,8 @@ pub struct TestExecutor { pub tx: vm::checked_transaction::Ready, pub test_entry: PkgTestEntry, pub name: String, + pub jump_instruction_index: usize, + pub relative_jump_in_bytes: u32, } /// The result of executing a test with breakpoints enabled. @@ -41,15 +46,16 @@ pub enum DebugResult { impl TestExecutor { pub fn build( bytecode: &[u8], - test_offset: u32, + test_instruction_index: u32, test_setup: TestSetup, test_entry: &PkgTestEntry, name: String, ) -> anyhow::Result { let storage = test_setup.storage().clone(); - // Patch the bytecode to jump to the relevant test. - let bytecode = patch_test_bytecode(bytecode, test_offset).into_owned(); + // Find the instruction which we will jump into the + // specified test + let jump_instruction_index = find_jump_instruction_index(bytecode); // Create a transaction to execute the test function. let script_input_data = vec![]; @@ -68,7 +74,7 @@ impl TestExecutor { let block_height = (u32::MAX >> 1).into(); let gas_price = 0; - let mut tx_builder = tx::TransactionBuilder::script(bytecode, script_input_data); + let mut tx_builder = tx::TransactionBuilder::script(bytecode.to_vec(), script_input_data); let params = maxed_consensus_params(); @@ -126,23 +132,72 @@ impl TestExecutor { tx, test_entry: test_entry.clone(), name, + jump_instruction_index, + relative_jump_in_bytes: (test_instruction_index - jump_instruction_index as u32) + * Instruction::SIZE as u32, }) } + // single-step until the jump-to-test instruction, then + // jump into the first instruction of the test + fn single_step_until_test(&mut self) -> ProgramState { + let jump_pc = (self.jump_instruction_index * Instruction::SIZE) as u64; + + let old_single_stepping = self.interpreter.single_stepping(); + self.interpreter.set_single_stepping(true); + let mut state = { + let transition = self.interpreter.transact(self.tx.clone()); + Ok(*transition.unwrap().state()) + }; + + loop { + match state { + // if the VM fails, we interpret as a revert + Err(_) => { + break ProgramState::Revert(0); + } + Ok( + state @ ProgramState::Return(_) + | state @ ProgramState::ReturnData(_) + | state @ ProgramState::Revert(_), + ) => break state, + Ok( + s @ ProgramState::RunProgram(eval) | s @ ProgramState::VerifyPredicate(eval), + ) => { + // time to jump into the specified test + if let Some(b) = eval.breakpoint() { + if b.pc() == jump_pc { + self.interpreter.registers_mut()[RegId::PC] += + self.relative_jump_in_bytes as u64; + self.interpreter.set_single_stepping(old_single_stepping); + break s; + } + } + + state = self.interpreter.resume(); + } + } + } + } + /// Execute the test with breakpoints enabled. pub fn start_debugging(&mut self) -> anyhow::Result { let start = std::time::Instant::now(); - let transition = self + + let _ = self.single_step_until_test(); + let state = self .interpreter - .transact(self.tx.clone()) - .map_err(|err: InterpreterError<_>| anyhow::anyhow!(err))?; - let state = *transition.state(); + .resume() + .map_err(|err: InterpreterError<_>| { + anyhow::anyhow!("VM failed to resume. {:?}", err) + })?; if let ProgramState::RunProgram(DebugEval::Breakpoint(breakpoint)) = state { // A breakpoint was hit, so we tell the client to stop. return Ok(DebugResult::Breakpoint(breakpoint.pc())); } + let duration = start.elapsed(); - let (gas_used, logs) = Self::get_gas_and_receipts(transition.receipts().to_vec())?; + let (gas_used, logs) = Self::get_gas_and_receipts(self.interpreter.receipts().to_vec())?; let span = self.test_entry.span.clone(); let file_path = self.test_entry.file_path.clone(); let condition = self.test_entry.pass_condition.clone(); @@ -192,14 +247,27 @@ impl TestExecutor { pub fn execute(&mut self) -> anyhow::Result { let start = std::time::Instant::now(); - let transition = self - .interpreter - .transact(self.tx.clone()) - .map_err(|err: InterpreterError<_>| anyhow::anyhow!(err))?; - let state = *transition.state(); + + let mut state = Ok(self.single_step_until_test()); + + // Run test until its end + loop { + match state { + Err(_) => { + state = Ok(ProgramState::Revert(0)); + break; + } + Ok( + ProgramState::Return(_) | ProgramState::ReturnData(_) | ProgramState::Revert(_), + ) => break, + Ok(ProgramState::RunProgram(_) | ProgramState::VerifyPredicate(_)) => { + state = self.interpreter.resume(); + } + } + } let duration = start.elapsed(); - let (gas_used, logs) = Self::get_gas_and_receipts(transition.receipts().to_vec())?; + let (gas_used, logs) = Self::get_gas_and_receipts(self.interpreter.receipts().to_vec())?; let span = self.test_entry.span.clone(); let file_path = self.test_entry.file_path.clone(); let condition = self.test_entry.pass_condition.clone(); @@ -209,7 +277,7 @@ impl TestExecutor { file_path, duration, span, - state, + state: state.unwrap(), condition, logs, gas_used, @@ -237,42 +305,25 @@ impl TestExecutor { } } -/// Given some bytecode and an instruction offset for some test's desired entry point, patch the -/// bytecode with a `JI` (jump) instruction to jump to the desired test. -/// -/// We want to splice in the `JI` only after the initial data section setup is complete, and only -/// if the entry point doesn't begin exactly after the data section setup. -/// -/// The following is how the beginning of the bytecode is laid out: -/// -/// ```ignore -/// [ 0] ji i(4 + 2) ; Jumps to the data section setup. -/// [ 1] noop -/// [ 2] DATA_SECTION_OFFSET[0..32] -/// [ 3] DATA_SECTION_OFFSET[32..64] -/// [ 4] CONFIGURABLES_OFFSET[0..32] -/// [ 5] CONFIGURABLES_OFFSET[32..64] -/// [ 6] lw $ds $is 1 ; The data section setup, i.e. where the first ji lands. -/// [ 7] add $$ds $$ds $is -/// [ 8] ; This is where we want to jump from to our test code! -/// ``` -fn patch_test_bytecode(bytecode: &[u8], test_offset: u32) -> std::borrow::Cow<[u8]> { - // Each instruction is 4 bytes, - // so we divide the total byte-size by 4 to get the instruction offset. - const PROGRAM_START_INST_OFFSET: u32 = (sway_core::PRELUDE_SIZE_IN_BYTES / 4) as u32; - const PROGRAM_START_BYTE_OFFSET: usize = sway_core::PRELUDE_SIZE_IN_BYTES; - - // If our desired entry point is the program start, no need to jump. - if test_offset == PROGRAM_START_INST_OFFSET { - return std::borrow::Cow::Borrowed(bytecode); - } +fn find_jump_instruction_index(bytecode: &[u8]) -> usize { + // Search first `move $$locbase $sp` + // This will be `__entry` for script/predicate/contract using encoding v1; + // `main` for script/predicate using encoding v0; + // or the first function for libraries + // MOVE R59 $sp ;; [26, 236, 80, 0] + let a = vm::fuel_asm::op::move_(59, fuel_asm::RegId::SP).to_bytes(); - // Create the jump instruction and splice it into the bytecode. - let ji = vm::fuel_asm::op::ji(test_offset); - let ji_bytes = ji.to_bytes(); - let start = PROGRAM_START_BYTE_OFFSET; - let end = start + ji_bytes.len(); - let mut patched = bytecode.to_vec(); - patched.splice(start..end, ji_bytes); - std::borrow::Cow::Owned(patched) + // for contracts using encoding v0 + // search the first `lw $r0 $fp i73` + // which is the start of the fn selector + // LW $writable $fp 0x49 ;; [93, 64, 96, 73] + let b = vm::fuel_asm::op::lw(fuel_asm::RegId::WRITABLE, fuel_asm::RegId::FP, 73).to_bytes(); + + bytecode + .chunks(Instruction::SIZE) + .position(|instruction| { + let instruction: [u8; 4] = instruction.try_into().unwrap(); + instruction == a || instruction == b + }) + .unwrap() } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.lock new file mode 100644 index 00000000000..688eb152964 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "configurable_tests" +source = "member" +dependencies = ["std"] + +[[package]] +name = "core" +source = "path+from-root-CEAD1EF3DC39BB76" + +[[package]] +name = "std" +source = "path+from-root-CEAD1EF3DC39BB76" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.toml new file mode 100644 index 00000000000..7fff3f8b575 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "configurable_tests" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle.json new file mode 100644 index 00000000000..096b1d487c9 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle.json @@ -0,0 +1,284 @@ +{ + "configurables": [ + { + "configurableType": { + "name": "", + "type": 5, + "typeArguments": null + }, + "name": "BOOL", + "offset": 3392 + }, + { + "configurableType": { + "name": "", + "type": 13, + "typeArguments": null + }, + "name": "U8", + "offset": 3528 + }, + { + "configurableType": { + "name": "", + "type": 13, + "typeArguments": null + }, + "name": "ANOTHER_U8", + "offset": 3320 + }, + { + "configurableType": { + "name": "", + "type": 9, + "typeArguments": null + }, + "name": "U16", + "offset": 3472 + }, + { + "configurableType": { + "name": "", + "type": 11, + "typeArguments": null + }, + "name": "U32", + "offset": 3512 + }, + { + "configurableType": { + "name": "", + "type": 11, + "typeArguments": null + }, + "name": "U64", + "offset": 3520 + }, + { + "configurableType": { + "name": "", + "type": 10, + "typeArguments": null + }, + "name": "U256", + "offset": 3480 + }, + { + "configurableType": { + "name": "", + "type": 4, + "typeArguments": null + }, + "name": "B256", + "offset": 3360 + }, + { + "configurableType": { + "name": "", + "type": 8, + "typeArguments": [] + }, + "name": "CONFIGURABLE_STRUCT", + "offset": 3432 + }, + { + "configurableType": { + "name": "", + "type": 6, + "typeArguments": [] + }, + "name": "CONFIGURABLE_ENUM_A", + "offset": 3400 + }, + { + "configurableType": { + "name": "", + "type": 6, + "typeArguments": [] + }, + "name": "CONFIGURABLE_ENUM_B", + "offset": 3416 + }, + { + "configurableType": { + "name": "", + "type": 2, + "typeArguments": null + }, + "name": "ARRAY_BOOL", + "offset": 3328 + }, + { + "configurableType": { + "name": "", + "type": 3, + "typeArguments": null + }, + "name": "ARRAY_U64", + "offset": 3336 + }, + { + "configurableType": { + "name": "", + "type": 1, + "typeArguments": null + }, + "name": "TUPLE_BOOL_U64", + "offset": 3456 + }, + { + "configurableType": { + "name": "", + "type": 7, + "typeArguments": null + }, + "name": "STR_4", + "offset": 3448 + } + ], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": [], + "type": "()", + "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, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle_new_encoding.json new file mode 100644 index 00000000000..2daeaffdc6a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle_new_encoding.json @@ -0,0 +1,228 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d", + "type": "()" + }, + { + "concreteTypeId": "c998ca9a5f221fe7b5c66ae70c8a9562b86d964408b00d17f883c906bc1fe4be", + "metadataTypeId": 0, + "type": "(bool, u64)" + }, + { + "concreteTypeId": "4926d35d1a5157936b0a29bc126b8aace6d911209a5c130e9b716b0c73643ea6", + "metadataTypeId": 1, + "type": "[bool; 3]" + }, + { + "concreteTypeId": "776fb5a3824169d6736138565fdc20aad684d9111266a5ff6d5c675280b7e199", + "metadataTypeId": 2, + "type": "[u64; 3]" + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "type": "b256" + }, + { + "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", + "type": "bool" + }, + { + "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", + "metadataTypeId": 3, + "type": "enum ConfigurableEnum" + }, + { + "concreteTypeId": "94f0fa95c830be5e4f711963e83259fe7e8bc723278ab6ec34449e791a99b53a", + "type": "str[4]" + }, + { + "concreteTypeId": "81fc10c4681a3271cf2d66b2ec6fbc8ed007a442652930844fcf11818c295bff", + "metadataTypeId": 4, + "type": "struct ConfigurableStruct" + }, + { + "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", + "type": "u16" + }, + { + "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", + "type": "u256" + }, + { + "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", + "type": "u32" + }, + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "type": "u8" + } + ], + "configurables": [ + { + "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", + "name": "BOOL", + "offset": 6896 + }, + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "name": "U8", + "offset": 7088 + }, + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "name": "ANOTHER_U8", + "offset": 6824 + }, + { + "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", + "name": "U16", + "offset": 7032 + }, + { + "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", + "name": "U32", + "offset": 7072 + }, + { + "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", + "name": "U64", + "offset": 7080 + }, + { + "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", + "name": "U256", + "offset": 7040 + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "B256", + "offset": 6864 + }, + { + "concreteTypeId": "81fc10c4681a3271cf2d66b2ec6fbc8ed007a442652930844fcf11818c295bff", + "name": "CONFIGURABLE_STRUCT", + "offset": 6984 + }, + { + "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", + "name": "CONFIGURABLE_ENUM_A", + "offset": 6904 + }, + { + "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", + "name": "CONFIGURABLE_ENUM_B", + "offset": 6944 + }, + { + "concreteTypeId": "4926d35d1a5157936b0a29bc126b8aace6d911209a5c130e9b716b0c73643ea6", + "name": "ARRAY_BOOL", + "offset": 6832 + }, + { + "concreteTypeId": "776fb5a3824169d6736138565fdc20aad684d9111266a5ff6d5c675280b7e199", + "name": "ARRAY_U64", + "offset": 6840 + }, + { + "concreteTypeId": "c998ca9a5f221fe7b5c66ae70c8a9562b86d964408b00d17f883c906bc1fe4be", + "name": "TUPLE_BOOL_U64", + "offset": 7016 + }, + { + "concreteTypeId": "94f0fa95c830be5e4f711963e83259fe7e8bc723278ab6ec34449e791a99b53a", + "name": "STR_4", + "offset": 7008 + }, + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "name": "NOT_USED", + "offset": 7000 + } + ], + "encodingVersion": "1", + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + } + ], + "loggedTypes": [], + "messagesTypes": [], + "metadataTypes": [ + { + "components": [ + { + "name": "__tuple_element", + "typeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + }, + { + "name": "__tuple_element", + "typeId": 5 + } + ], + "metadataTypeId": 0, + "type": "(_, _)" + }, + { + "components": [ + { + "name": "__array_element", + "typeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + } + ], + "metadataTypeId": 1, + "type": "[_; 3]" + }, + { + "components": [ + { + "name": "__array_element", + "typeId": 5 + } + ], + "metadataTypeId": 2, + "type": "[_; 3]" + }, + { + "components": [ + { + "name": "A", + "typeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + }, + { + "name": "B", + "typeId": 5 + }, + { + "name": "C", + "typeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b" + } + ], + "metadataTypeId": 3, + "type": "enum ConfigurableEnum" + }, + { + "components": [ + { + "name": "a", + "typeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + }, + { + "name": "b", + "typeId": 5 + } + ], + "metadataTypeId": 4, + "type": "struct ConfigurableStruct" + }, + { + "metadataTypeId": 5, + "type": "u64" + } + ], + "programType": "script", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/src/main.sw new file mode 100644 index 00000000000..a0e5d11a345 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/src/main.sw @@ -0,0 +1,83 @@ +script; + +use std::hash::*; + +struct ConfigurableStruct { + a: bool, + b: u64, +} + +enum ConfigurableEnum { + A: bool, + B: u64, + C: b256 +} + +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, + } + } +} + +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"), + + NOT_USED: u8 = 1 +} + +fn main() { +} + +#[test] +fn t() { + assert(BOOL == true); + assert(U8 == 1); + assert(ANOTHER_U8 == 3); + assert(U16 == 2); + assert(U32 == 3); + 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); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/test.toml new file mode 100644 index 00000000000..0f3f6d7e866 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/test.toml @@ -0,0 +1 @@ +category = "unit_tests_pass" From 64d1c6ec2bc458f3e36ca7562d0770212b55099c Mon Sep 17 00:00:00 2001 From: Daniel Frederico Lins Leite Date: Fri, 22 Nov 2024 08:22:50 -0300 Subject: [PATCH 26/52] Support for aliased import for encoding v1 (#6628) ## Description Fixes https://github.com/FuelLabs/sway/issues/6569 ## Checklist - [ ] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] 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). - [ ] I have requested a review from the relevant team or maintainers. --- .../ast_node/declaration/auto_impl.rs | 118 +++--------------- .../main_args_various_types/Forc.toml | 2 +- .../json_abi_oracle_new_encoding.json | 14 ++- .../main_args_various_types/src/main.sw | 10 +- .../main_args_various_types/src/types.sw | 5 + 5 files changed, 43 insertions(+), 106 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/types.sw diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs index 98def2c187f..9efcc2392d3 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs @@ -8,14 +8,14 @@ use crate::{ Purity, }, semantic_analysis::TypeCheckContext, - Engines, TypeId, TypeInfo, TypeParameter, + Engines, TypeArgument, TypeInfo, TypeParameter, }; use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, }; use sway_parse::Parse; -use sway_types::{integer_bits::IntegerBits, BaseIdent, Named, ProgramId, Span, Spanned}; +use sway_types::{BaseIdent, Named, ProgramId, Span, Spanned}; /// Contains all information needed to implement AbiEncode pub struct EncodingAutoImplContext<'a, 'b> @@ -38,7 +38,7 @@ where T: Parse, { // Uncomment this to see what is being generated - //println!("{}", input); + // println!("{}", input); let handler = <_>::default(); let source_id = @@ -195,7 +195,7 @@ where code.push_str(&format!( "{field_name}: buffer.decode::<{field_type_name}>(),", field_name = f.name.as_str(), - field_type_name = Self::generate_type(engines, f.type_argument.type_id)?, + field_type_name = Self::generate_type(engines, &f.type_argument)?, )); } @@ -217,7 +217,7 @@ where format!("{} => {}::{}, \n", x.tag, enum_name, name) }, _ => { - let variant_type_name = Self::generate_type(engines, x.type_argument.type_id)?; + let variant_type_name = Self::generate_type(engines, &x.type_argument)?; format!("{tag_value} => {enum_name}::{variant_name}(buffer.decode::<{variant_type}>()), \n", tag_value = x.tag, enum_name = enum_name, @@ -496,92 +496,15 @@ where } } - fn generate_type(engines: &Engines, type_id: TypeId) -> Option { - let name = match &*engines.te().get(type_id) { - TypeInfo::UnknownGeneric { name, .. } => name.to_string(), - TypeInfo::Placeholder(type_param) => type_param.name.to_string(), - TypeInfo::StringSlice => "str".into(), - TypeInfo::StringArray(x) => format!("str[{}]", x.val()), - TypeInfo::UnsignedInteger(x) => match x { - IntegerBits::Eight => "u8", - IntegerBits::Sixteen => "u16", - IntegerBits::ThirtyTwo => "u32", - IntegerBits::SixtyFour => "u64", - IntegerBits::V256 => "u256", - } - .into(), - TypeInfo::Boolean => "bool".into(), - TypeInfo::Custom { - qualified_call_path: call_path, - .. - } => call_path.call_path.suffix.to_string(), - TypeInfo::Tuple(fields) => { - if fields.is_empty() { - return Some("()".into()); - } - let field_strs = fields - .iter() - .map(|field| Self::generate_type(engines, field.type_id)) - .collect::>>()?; - format!("({},)", field_strs.join(", ")) - } - TypeInfo::B256 => "b256".into(), - TypeInfo::Enum(decl_id) => { - let decl = engines.de().get_enum(decl_id); - - let type_parameters = decl - .type_parameters - .iter() - .map(|x| Self::generate_type(engines, x.type_id)) - .collect::>>()? - .join(", "); - - let type_parameters = if !type_parameters.is_empty() { - format!("<{type_parameters}>") - } else { - type_parameters - }; - - format!("{}{type_parameters}", decl.call_path.suffix.as_str()) - } - TypeInfo::Struct(decl_id) => { - let decl = engines.de().get(decl_id); - - let type_parameters = decl - .type_parameters - .iter() - .map(|x| Self::generate_type(engines, x.type_id)) - .collect::>>()? - .join(", "); - - let type_parameters = if !type_parameters.is_empty() { - format!("<{type_parameters}>") - } else { - type_parameters - }; - - format!("{}{type_parameters}", decl.call_path.suffix.as_str()) - } - TypeInfo::Array(elem_ty, count) => { - format!( - "[{}; {}]", - Self::generate_type(engines, elem_ty.type_id)?, - count.val() - ) - } - TypeInfo::Slice(elem_ty) => { - format!( - "__slice[{}]", - Self::generate_type(engines, elem_ty.type_id)? - ) - } - TypeInfo::RawUntypedPtr => "raw_ptr".into(), - TypeInfo::RawUntypedSlice => "raw_slice".into(), - TypeInfo::Alias { name, .. } => name.to_string(), - _ => return None, - }; - - Some(name) + // The safest way would be to return a canonical fully qualified type path. + // We do not have a way to do this at the moment, so the best way is to use + // exactly what was typed by the user, to accommodate aliased imports. + fn generate_type(engines: &Engines, t: &TypeArgument) -> Option { + match &*engines.te().get(t.type_id) { + // when a function does not define a return type, the span points to the whole signature. + TypeInfo::Tuple(v) if v.is_empty() => Some("()".into()), + _ => Some(t.span().as_str().to_string()), + } } pub(crate) fn generate_contract_entry( @@ -613,7 +536,7 @@ where let Some(args_types) = decl .parameters .iter() - .map(|x| Self::generate_type(engines, x.type_argument.type_id)) + .map(|x| Self::generate_type(engines, &x.type_argument)) .collect::>>() else { let err = handler.emit_err(CompileError::UnknownType { @@ -638,7 +561,7 @@ where ) .collect::(); - let Some(return_type) = Self::generate_type(engines, decl.return_type.type_id) else { + let Some(return_type) = Self::generate_type(engines, &decl.return_type) else { let err = handler.emit_err(CompileError::UnknownType { span: Span::dummy(), }); @@ -674,8 +597,7 @@ where let fallback = if let Some(fallback_fn) = fallback_fn { let fallback_fn = engines.de().get(&fallback_fn); - let Some(return_type) = Self::generate_type(engines, fallback_fn.return_type.type_id) - else { + let Some(return_type) = Self::generate_type(engines, &fallback_fn.return_type) else { let err = handler.emit_err(CompileError::UnknownType { span: Span::dummy(), }); @@ -743,7 +665,7 @@ where let Some(args_types) = decl .parameters .iter() - .map(|x| Self::generate_type(engines, x.type_argument.type_id)) + .map(|x| Self::generate_type(engines, &x.type_argument)) .collect::>>() else { let err = handler.emit_err(CompileError::UnknownType { @@ -836,7 +758,7 @@ where let Some(args_types) = decl .parameters .iter() - .map(|x| Self::generate_type(engines, x.type_argument.type_id)) + .map(|x| Self::generate_type(engines, &x.type_argument)) .collect::>>() else { let err = handler.emit_err(CompileError::UnknownType { @@ -860,7 +782,7 @@ where ) .collect::(); - let Some(return_type) = Self::generate_type(engines, decl.return_type.type_id) else { + let Some(return_type) = Self::generate_type(engines, &decl.return_type) else { let err = handler.emit_err(CompileError::UnknownType { span: Span::dummy(), }); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/Forc.toml index a06f647ef58..79e3031d8bd 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/Forc.toml @@ -5,4 +5,4 @@ license = "Apache-2.0" name = "main_args_various_types" [dependencies] -std = { path = "../../../../../reduced_std_libs/sway-lib-std-assert" } +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle_new_encoding.json index 6d95b04580f..ee7cb119623 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle_new_encoding.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle_new_encoding.json @@ -6,8 +6,8 @@ "type": "[(struct OpName, enum SignedNum); 2]" }, { - "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", - "type": "u64" + "concreteTypeId": "d489af6a272dc02bb98c58446e5250345c65721ecfef3f43b26c263819725668", + "type": "generic AliasedS" } ], "configurables": [], @@ -22,7 +22,7 @@ } ], "name": "main", - "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + "output": "d489af6a272dc02bb98c58446e5250345c65721ecfef3f43b26c263819725668" } ], "loggedTypes": [ @@ -61,11 +61,11 @@ "components": [ { "name": "Positive", - "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + "typeId": 5 }, { "name": "Negative", - "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + "typeId": 5 } ], "metadataTypeId": 2, @@ -84,6 +84,10 @@ ], "metadataTypeId": 4, "type": "struct OpName" + }, + { + "metadataTypeId": 5, + "type": "u64" } ], "programType": "script", diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/main.sw index cf8cb142ee1..55cf6bae4d3 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/main.sw @@ -1,5 +1,9 @@ script; +mod types; + +use types::{S as AliasedS}; + fn eq_str_3(a: str[3], b: str) -> bool { let ptr_b = b.as_ptr(); asm(a: a, b: ptr_b, len: 3, r) { @@ -17,7 +21,7 @@ struct OpName { val: str[3] } -fn main(ops: [(OpName, SignedNum); 2]) -> u64 { +fn main(ops: [(OpName, SignedNum); 2]) -> AliasedS { __log(ops); assert(eq_str_3(ops[0].0.val, "set")); assert(match ops[0].1 { @@ -31,5 +35,7 @@ fn main(ops: [(OpName, SignedNum); 2]) -> u64 { _ => revert(2), } == 1); - 1 + AliasedS{ + v: 1 + } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/types.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/types.sw new file mode 100644 index 00000000000..8e5e9741521 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/types.sw @@ -0,0 +1,5 @@ +library; + +pub struct S { + pub v: u64 +} \ No newline at end of file From bcd15c3d6e5c6420c9faa98cbf5446bd0af6ece6 Mon Sep 17 00:00:00 2001 From: Daniel Frederico Lins Leite Date: Mon, 25 Nov 2024 16:48:14 -0300 Subject: [PATCH 27/52] improve asm copy propagation for MOVE instruction (#6641) ## Description This PR improve value propagation optimization in two ways: 1 - First, when the optimizer knows that both source and destination registers of the `MOVE` instruct have the same value and version; it will remove the instruction as it is useless; 2 - Otherwise, we propagate the value saying that destination now have the same value and version of the source register for other optimizations. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] 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. --- forc-plugins/forc-client/tests/deploy.rs | 8 +- .../src/asm_generation/fuel/optimizations.rs | 286 +++++++++++------- .../json_abi_oracle_new_encoding.json | 32 +- .../configurable_dedup_decode/snapshot.toml | 2 +- .../configurable_dedup_decode/stdout.snap | 195 +++++++++++- .../array_of_structs_caller/src/main.sw | 2 +- .../asset_ops_test/src/main.sw | 2 +- .../asset_ops_test/test.toml | 7 +- .../call_basic_storage/src/main.sw | 2 +- .../src/main.sw | 2 +- .../storage_access_caller/src/main.sw | 2 +- 11 files changed, 392 insertions(+), 148 deletions(-) diff --git a/forc-plugins/forc-client/tests/deploy.rs b/forc-plugins/forc-client/tests/deploy.rs index 0784111e146..aeb1e45bf52 100644 --- a/forc-plugins/forc-client/tests/deploy.rs +++ b/forc-plugins/forc-client/tests/deploy.rs @@ -373,7 +373,7 @@ async fn test_simple_deploy() { node.kill().unwrap(); let expected = vec![DeployedPackage::Contract(DeployedContract { id: ContractId::from_str( - "5c51b8904c539700852c646c6700fddab4b80477f66e56fb2515736facd84e69", + "02a7e78ef0514b80ab56b409f06f895d8939640b6f6d746fcbb15d3e0c6a1a3b", ) .unwrap(), proxy: None, @@ -416,7 +416,7 @@ async fn test_deploy_submit_only() { node.kill().unwrap(); let expected = vec![DeployedPackage::Contract(DeployedContract { id: ContractId::from_str( - "5c51b8904c539700852c646c6700fddab4b80477f66e56fb2515736facd84e69", + "02a7e78ef0514b80ab56b409f06f895d8939640b6f6d746fcbb15d3e0c6a1a3b", ) .unwrap(), proxy: None, @@ -462,12 +462,12 @@ async fn test_deploy_fresh_proxy() { node.kill().unwrap(); let impl_contract = DeployedPackage::Contract(DeployedContract { id: ContractId::from_str( - "5c51b8904c539700852c646c6700fddab4b80477f66e56fb2515736facd84e69", + "02a7e78ef0514b80ab56b409f06f895d8939640b6f6d746fcbb15d3e0c6a1a3b", ) .unwrap(), proxy: Some( ContractId::from_str( - "7a78517c2c3322028db65e54893dc97958fa3d7c846a66f5675859e64f927540", + "6eb0db0e120222a4ac3ced8dfbf15ae56753b852aa7989849fa20e5aca47af44", ) .unwrap(), ), diff --git a/sway-core/src/asm_generation/fuel/optimizations.rs b/sway-core/src/asm_generation/fuel/optimizations.rs index 4800ba6906f..7fa0da2356c 100644 --- a/sway-core/src/asm_generation/fuel/optimizations.rs +++ b/sway-core/src/asm_generation/fuel/optimizations.rs @@ -27,7 +27,7 @@ impl AbstractInstructionSet { } // What does a register contain? - #[derive(Debug)] + #[derive(Debug, PartialEq, Eq)] enum RegContents { Constant(u64), BaseOffset(VRegDef, u64), @@ -57,145 +57,184 @@ impl AbstractInstructionSet { latest_version.get(reg).cloned().unwrap_or(0) } - for op in &mut self.ops { + fn process_add( + reg_contents: &mut FxHashMap, + latest_version: &mut FxHashMap, + dest: &VirtualRegister, + opd1: &VirtualRegister, + c2: u64, + ) { + match reg_contents.get(opd1) { + Some(RegContents::Constant(c1)) if c1.checked_add(c2).is_some() => { + reg_contents.insert(dest.clone(), RegContents::Constant(c1 + c2)); + record_new_def(latest_version, dest); + } + Some(RegContents::BaseOffset(base_reg, offset)) + if get_def_version(latest_version, &base_reg.reg) == base_reg.ver + && offset.checked_add(c2).is_some() => + { + reg_contents.insert( + dest.clone(), + RegContents::BaseOffset(base_reg.clone(), offset + c2), + ); + record_new_def(latest_version, dest); + } + _ => { + let base = VRegDef { + reg: opd1.clone(), + ver: get_def_version(latest_version, opd1), + }; + reg_contents.insert(dest.clone(), RegContents::BaseOffset(base, c2)); + record_new_def(latest_version, dest); + } + } + } + + self.ops.retain_mut(|op| { + let mut retain = true; + let mut clear_state = false; + // Uncomment to debug what this optimization is doing // let op_before = op.clone(); - fn process_add( - reg_contents: &mut FxHashMap, - latest_version: &mut FxHashMap, - dest: &VirtualRegister, - opd1: &VirtualRegister, - c2: u64, - ) { - match reg_contents.get(opd1) { - Some(RegContents::Constant(c1)) if c1.checked_add(c2).is_some() => { - reg_contents.insert(dest.clone(), RegContents::Constant(c1 + c2)); - record_new_def(latest_version, dest); - } - Some(RegContents::BaseOffset(base_reg, offset)) - if get_def_version(latest_version, &base_reg.reg) == base_reg.ver - && offset.checked_add(c2).is_some() => - { - reg_contents.insert( - dest.clone(), - RegContents::BaseOffset(base_reg.clone(), offset + c2), - ); - record_new_def(latest_version, dest); - } - _ => { - let base = VRegDef { - reg: opd1.clone(), - ver: get_def_version(latest_version, opd1), - }; - reg_contents.insert(dest.clone(), RegContents::BaseOffset(base, c2)); - record_new_def(latest_version, dest); - } - } - } match &mut op.opcode { - either::Either::Left(op) => match op { - VirtualOp::ADD(dest, opd1, opd2) => { - // We don't look for the first operand being a constant and the second - // one a base register. Such patterns must be canonicalised prior. - let Some(&RegContents::Constant(c2)) = reg_contents.get(opd2) else { - reg_contents.remove(dest); - record_new_def(&mut latest_version, dest); - continue; - }; - process_add(&mut reg_contents, &mut latest_version, dest, opd1, c2); - } - VirtualOp::ADDI(dest, opd1, opd2) => { - let c2 = opd2.value as u64; - process_add(&mut reg_contents, &mut latest_version, dest, opd1, c2); - } - VirtualOp::MUL(dest, opd1, opd2) => { - match (reg_contents.get(opd1), reg_contents.get(opd2)) { - (Some(RegContents::Constant(c1)), Some(RegContents::Constant(c2))) => { - reg_contents.insert(dest.clone(), RegContents::Constant(c1 * c2)); + either::Either::Left(op) => { + match op { + VirtualOp::ADD(dest, opd1, opd2) => { + // We don't look for the first operand being a constant and the second + // one a base register. Such patterns must be canonicalised prior. + if let Some(&RegContents::Constant(c2)) = reg_contents.get(opd2) { + process_add(&mut reg_contents, &mut latest_version, dest, opd1, c2); + } else { + reg_contents.remove(dest); record_new_def(&mut latest_version, dest); + }; + } + VirtualOp::ADDI(dest, opd1, opd2) => { + let c2 = opd2.value as u64; + process_add(&mut reg_contents, &mut latest_version, dest, opd1, c2); + } + VirtualOp::MUL(dest, opd1, opd2) => { + match (reg_contents.get(opd1), reg_contents.get(opd2)) { + ( + Some(RegContents::Constant(c1)), + Some(RegContents::Constant(c2)), + ) => { + reg_contents + .insert(dest.clone(), RegContents::Constant(c1 * c2)); + record_new_def(&mut latest_version, dest); + } + _ => { + reg_contents.remove(dest); + record_new_def(&mut latest_version, dest); + } } - _ => { + } + VirtualOp::LoadDataId(dest, data_id) => { + if let Some(c) = data_section.get_data_word(data_id) { + reg_contents.insert(dest.clone(), RegContents::Constant(c)); + } else { reg_contents.remove(dest); - record_new_def(&mut latest_version, dest); } + record_new_def(&mut latest_version, dest); } - } - VirtualOp::LoadDataId(dest, data_id) => { - if let Some(c) = data_section.get_data_word(data_id) { - reg_contents.insert(dest.clone(), RegContents::Constant(c)); - } else { - reg_contents.remove(dest); + VirtualOp::MOVI(dest, imm) => { + reg_contents + .insert(dest.clone(), RegContents::Constant(imm.value as u64)); + record_new_def(&mut latest_version, dest); } - record_new_def(&mut latest_version, dest); - } - VirtualOp::MOVI(dest, imm) => { - reg_contents.insert(dest.clone(), RegContents::Constant(imm.value as u64)); - record_new_def(&mut latest_version, dest); - } - VirtualOp::LW(dest, addr_reg, imm) => match reg_contents.get(addr_reg) { - Some(RegContents::BaseOffset(base_reg, offset)) - if get_def_version(&latest_version, &base_reg.reg) == base_reg.ver - && ((offset / 8) + imm.value as u64) - < compiler_constants::TWELVE_BITS => - { - // bail if LW cannot read where this memory is - if offset % 8 == 0 { + VirtualOp::LW(dest, addr_reg, imm) => match reg_contents.get(addr_reg) { + Some(RegContents::BaseOffset(base_reg, offset)) + if get_def_version(&latest_version, &base_reg.reg) + == base_reg.ver + && ((offset / 8) + imm.value as u64) + < compiler_constants::TWELVE_BITS => + { + // bail if LW cannot read where this memory is + if offset % 8 == 0 { + let new_imm = VirtualImmediate12::new_unchecked( + (offset / 8) + imm.value as u64, + "Immediate offset too big for LW", + ); + let new_lw = + VirtualOp::LW(dest.clone(), base_reg.reg.clone(), new_imm); + // The register defined is no more useful for us. Forget anything from its past. + reg_contents.remove(dest); + record_new_def(&mut latest_version, dest); + // Replace the LW with a new one in-place. + *op = new_lw; + } + } + _ => { + reg_contents.remove(dest); + record_new_def(&mut latest_version, dest); + } + }, + VirtualOp::SW(addr_reg, src, imm) => match reg_contents.get(addr_reg) { + Some(RegContents::BaseOffset(base_reg, offset)) + if get_def_version(&latest_version, &base_reg.reg) + == base_reg.ver + && ((offset / 8) + imm.value as u64) + < compiler_constants::TWELVE_BITS => + { let new_imm = VirtualImmediate12::new_unchecked( (offset / 8) + imm.value as u64, - "Immediate offset too big for LW", + "Immediate offset too big for SW", + ); + let new_sw = + VirtualOp::SW(base_reg.reg.clone(), src.clone(), new_imm); + // Replace the SW with a new one in-place. + *op = new_sw; + } + _ => (), + }, + VirtualOp::MOVE(dest, src) => { + let ver = get_def_version(&latest_version, src); + if let Some(RegContents::BaseOffset(src, 0)) = reg_contents.get(src) { + if dest == &src.reg && src.ver == ver { + retain = false; + } + } else { + reg_contents.insert( + dest.clone(), + RegContents::BaseOffset( + VRegDef { + reg: src.clone(), + ver, + }, + 0, + ), ); - let new_lw = - VirtualOp::LW(dest.clone(), base_reg.reg.clone(), new_imm); - // The register defined is no more useful for us. Forget anything from its past. - reg_contents.remove(dest); - record_new_def(&mut latest_version, dest); - // Replace the LW with a new one in-place. - *op = new_lw; } } _ => { - reg_contents.remove(dest); - record_new_def(&mut latest_version, dest); - } - }, - VirtualOp::SW(addr_reg, src, imm) => match reg_contents.get(addr_reg) { - Some(RegContents::BaseOffset(base_reg, offset)) - if get_def_version(&latest_version, &base_reg.reg) == base_reg.ver - && ((offset / 8) + imm.value as u64) - < compiler_constants::TWELVE_BITS => - { - let new_imm = VirtualImmediate12::new_unchecked( - (offset / 8) + imm.value as u64, - "Immediate offset too big for SW", - ); - let new_sw = VirtualOp::SW(base_reg.reg.clone(), src.clone(), new_imm); - // Replace the SW with a new one in-place. - *op = new_sw; - } - _ => (), - }, - _ => { - // For every Op that we don't know about, - // forget everything we know about its def registers. - for def_reg in op.def_registers() { - reg_contents.remove(def_reg); - record_new_def(&mut latest_version, def_reg); + // For every Op that we don't know about, + // forget everything we know about its def registers. + for def_reg in op.def_registers() { + reg_contents.remove(def_reg); + record_new_def(&mut latest_version, def_reg); + } } } - }, + } + either::Either::Right(ControlFlowOp::SaveRetAddr(..)) => {} either::Either::Right(_) => { - // Reset state. - latest_version.clear(); - reg_contents.clear(); + clear_state = true; } } // Uncomment to debug what this optimization is doing - // let before = op_before.opcode.to_string(); - // let after = op.opcode.to_string(); - + //let before = op_before.opcode.to_string(); + //let after = op.opcode.to_string(); // println!("{}", before); + + if clear_state { + latest_version.clear(); + reg_contents.clear(); + // println!(" state cleared"); + } + + // Uncomment to debug what this optimization is doing // if before != after { // println!(" optimized to"); // println!(" {}", after); @@ -204,7 +243,20 @@ impl AbstractInstructionSet { // println!(" - {:?} -> {:?}", k, v); // } // } - } + // if !retain { + // println!(" removed"); + // for (k, v) in reg_contents.iter() { + // println!(" - {:?} -> {:?}", k, v); + // } + // } + // if forget_def_registers { + // for def_reg in op.def_registers() { + // println!(" forget {}", def_reg.to_string()); + // } + // } + + retain + }); self } 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 82d1bf9734c..71cf1f22ff7 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 @@ -62,82 +62,82 @@ { "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", "name": "BOOL", - "offset": 7120 + "offset": 7048 }, { "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", "name": "U8", - "offset": 7312 + "offset": 7240 }, { "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", "name": "ANOTHER_U8", - "offset": 7048 + "offset": 6976 }, { "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", "name": "U16", - "offset": 7256 + "offset": 7184 }, { "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", "name": "U32", - "offset": 7296 + "offset": 7224 }, { "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", "name": "U64", - "offset": 7304 + "offset": 7232 }, { "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", "name": "U256", - "offset": 7264 + "offset": 7192 }, { "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", "name": "B256", - "offset": 7088 + "offset": 7016 }, { "concreteTypeId": "81fc10c4681a3271cf2d66b2ec6fbc8ed007a442652930844fcf11818c295bff", "name": "CONFIGURABLE_STRUCT", - "offset": 7208 + "offset": 7136 }, { "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", "name": "CONFIGURABLE_ENUM_A", - "offset": 7128 + "offset": 7056 }, { "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", "name": "CONFIGURABLE_ENUM_B", - "offset": 7168 + "offset": 7096 }, { "concreteTypeId": "4926d35d1a5157936b0a29bc126b8aace6d911209a5c130e9b716b0c73643ea6", "name": "ARRAY_BOOL", - "offset": 7056 + "offset": 6984 }, { "concreteTypeId": "776fb5a3824169d6736138565fdc20aad684d9111266a5ff6d5c675280b7e199", "name": "ARRAY_U64", - "offset": 7064 + "offset": 6992 }, { "concreteTypeId": "c998ca9a5f221fe7b5c66ae70c8a9562b86d964408b00d17f883c906bc1fe4be", "name": "TUPLE_BOOL_U64", - "offset": 7240 + "offset": 7168 }, { "concreteTypeId": "94f0fa95c830be5e4f711963e83259fe7e8bc723278ab6ec34449e791a99b53a", "name": "STR_4", - "offset": 7232 + "offset": 7160 }, { "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", "name": "NOT_USED", - "offset": 7224 + "offset": 7152 } ], "encodingVersion": "1", diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/snapshot.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/snapshot.toml index 784ff71e177..adfffceffad 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/snapshot.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/snapshot.toml @@ -1 +1 @@ -cmds = ["forc build --path {root} --release --ir final"] +cmds = ["forc build --path {root} --release --ir final --asm final"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/stdout.snap b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/stdout.snap index a8fe871947a..6af5fcc2f13 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/stdout.snap +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/stdout.snap @@ -1,9 +1,8 @@ --- source: test/tests/tests.rs -assertion_line: 115 snapshot_kind: text --- -> forc build --path test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode --release --ir final +> forc build --path test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode --release --ir final --asm final exit status: 0 output: Building test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode @@ -362,4 +361,194 @@ script { !128 = fn_call_path_span !0 235 236 !129 = (!127 !128) - Finished release [optimized + fuel] target(s) [760 B] in ??? +;; ASM: Final program +;; Program kind: Script +.program: +move $$tmp $pc +jmpf $zero i4 +DATA_SECTION_OFFSET[0..32] +DATA_SECTION_OFFSET[32..64] +CONFIGURABLES_OFFSET[0..32] +CONFIGURABLES_OFFSET[32..64] +lw $$ds $$tmp i1 +add $$ds $$ds $$tmp +cfei i16 ; allocate stack space for globals +addr $$arg0 data_Configurable_0; get pointer to configurable TUPLE default value +addi $$arg1 $zero i8 ; get length of configurable TUPLE default value +addi $$arg2 $ssp i0 ; get pointer to configurable TUPLE stack address +sub $$reta $pc $is ; get current instruction offset from instructions start ($is) +srli $$reta $$reta i2 ; get current instruction offset in 32-bit words +addi $$reta $$reta i4 ; set new return address +jmpf $zero i93 ; decode configurable TUPLE +addr $$arg0 data_Configurable_1; get pointer to configurable WRAPPED default value +addi $$arg1 $zero i8 ; get length of configurable WRAPPED default value +addi $$arg2 $ssp i8 ; get pointer to configurable WRAPPED stack address +sub $$reta $pc $is ; get current instruction offset from instructions start ($is) +srli $$reta $$reta i2 ; get current instruction offset in 32-bit words +addi $$reta $$reta i4 ; set new return address +jmpf $zero i85 ; decode configurable WRAPPED +move $$locbase $sp ; save locals base register for function __entry +cfei i360 ; allocate 360 bytes for locals and 0 slots for call arguments +addi $r6 $$locbase i320 ; get offset to local +sub $$reta $pc $is ; get current instruction offset from instructions start ($is) +srli $$reta $$reta i2 ; get current instruction offset in 32-bit words +addi $$reta $$reta i4 ; [call]: set new return address +jmpf $zero i140 ; [call]: call main_8 +move $r0 $$retv ; [call]: copy the return value +movi $r1 i1024 ; initialize constant into register +aloc $r1 +move $r1 $hp ; return value from ASM block with return register hp +addi $r2 $$locbase i112 ; get offset to local +sw $$locbase $r1 i14 ; store word +movi $r1 i1024 ; initialize constant into register +sw $$locbase $r1 i15 ; store word +sw $$locbase $zero i16 ; store word +movi $r1 i24 ; get data length for memory copy +mcp $$locbase $r2 $r1 ; copy memory +addi $r1 $$locbase i184 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r1 $$locbase $r2 ; copy memory +addi $r2 $$locbase i272 ; get offset to local +movi $r3 i24 ; get data length for memory copy +mcp $r2 $r1 $r3 ; copy memory +addi $r1 $$locbase i24 ; get offset to local +movi $r3 i24 ; get data length for memory copy +mcp $r1 $r2 $r3 ; copy memory +addi $r2 $$locbase i136 ; get offset to local +movi $r3 i24 ; get data length for memory copy +mcp $r2 $r1 $r3 ; copy memory +lw $r5 $$locbase i17 ; load word +lw $r4 $$locbase i18 ; load word +lw $r1 $$locbase i19 ; load word +movi $r2 i8 ; initialize constant into register +add $r2 $r1 $r2 +gt $r3 $r2 $r4 +jnzf $r3 $zero i1 +jmpf $zero i7 +movi $r3 i2 ; initialize constant into register +mul $r3 $r4 $r3 +movi $r4 i8 ; initialize constant into register +add $r4 $r3 $r4 +aloc $r4 +mcp $hp $r5 $r1 +move $r5 $hp ; return value from ASM block with return register hp +add $r1 $r5 $r1 +sw $r1 $r0 i0 ; store word +addi $r0 $$locbase i208 ; get offset to local +sw $$locbase $r5 i26 ; store word +sw $$locbase $r4 i27 ; store word +sw $$locbase $r2 i28 ; store word +addi $r1 $$locbase i48 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r1 $r0 $r2 ; copy memory +addi $r0 $$locbase i248 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r0 $r1 $r2 ; copy memory +addi $r1 $$locbase i336 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r1 $r0 $r2 ; copy memory +addi $r0 $$locbase i336 ; get offset to local +addi $r1 $$locbase i296 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r1 $r0 $r2 ; copy memory +addi $r0 $$locbase i72 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r0 $r1 $r2 ; copy memory +addi $r1 $$locbase i160 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r1 $r0 $r2 ; copy memory +lw $r0 $$locbase i20 ; load word +addi $r1 $r1 i16 ; get offset to aggregate element +addi $r2 $$locbase i232 ; get offset to local +sw $$locbase $r0 i29 ; store word +addi $r0 $r2 i8 ; get offset to aggregate element +movi $r3 i8 ; get data length for memory copy +mcp $r0 $r1 $r3 ; copy memory +addi $r0 $$locbase i96 ; get offset to local +movi $r1 i16 ; get data length for memory copy +mcp $r0 $r2 $r1 ; copy memory +movi $r1 i16 ; get data length for memory copy +mcp $r6 $r0 $r1 ; copy memory +lw $r0 $r6 i1 ; load size of returned slice +lw $r6 $r6 i0 ; load pointer to returned slice +retd $r6 $r0 +pshl i15 ; save registers 16..40 +pshh i524288 ; save registers 40..64 +move $$locbase $sp ; save locals base register for function abi_decode_in_place_0 +cfei i24 ; allocate 24 bytes for locals and 0 slots for call arguments +move $r0 $$arg0 ; save argument 0 (ptr) +move $r1 $$arg1 ; save argument 1 (len) +move $r2 $$arg2 ; save argument 2 (target) +move $r3 $$reta ; save return address +move $$arg0 $r0 ; [call]: pass argument 0 +move $$arg1 $r1 ; [call]: pass argument 1 +move $$arg2 $$locbase ; [call]: pass argument 2 +sub $$reta $pc $is ; get current instruction offset from instructions start ($is) +srli $$reta $$reta i2 ; get current instruction offset in 32-bit words +addi $$reta $$reta i4 ; [call]: set new return address +jmpf $zero i19 ; [call]: call from_parts_1 +lw $r0 $$retv i0 ; load word +sw $$locbase $r0 i1 ; store word +addi $r0 $$locbase i8 ; get offset to local +move $$arg0 $r0 ; [call]: pass argument 0 +sub $$reta $pc $is ; get current instruction offset from instructions start ($is) +srli $$reta $$reta i2 ; get current instruction offset in 32-bit words +addi $$reta $$reta i4 ; [call]: set new return address +jmpf $zero i23 ; [call]: call abi_decode_3 +move $r0 $$retv ; [call]: copy the return value +sw $$locbase $r0 i2 ; store word +addi $r0 $$locbase i16 ; get offset to local +movi $r1 i8 ; initialize constant into register +mcp $r2 $r0 $r1 ; mcp target temp size +move $$retv $zero ; set return value +cfsi i24 ; free 24 bytes for locals and 0 slots for extra call arguments +move $$reta $r3 ; restore return address +poph i524288 ; restore registers 40..64 +popl i15 ; restore registers 16..40 +jmp $$reta ; return from call +pshl i7 ; save registers 16..40 +pshh i524288 ; save registers 40..64 +move $$locbase $sp ; save locals base register for function from_parts_1 +move $r0 $$arg0 ; save argument 0 (ptr) +move $r1 $$arg2 ; save argument 2 (__ret_value) +move $r2 $$reta ; save return address +sw $r1 $r0 i0 ; store word +move $$retv $r1 ; set return value +move $$reta $r2 ; restore return address +poph i524288 ; restore registers 40..64 +popl i7 ; restore registers 16..40 +jmp $$reta ; return from call +pshl i31 ; save registers 16..40 +pshh i524288 ; save registers 40..64 +move $$locbase $sp ; save locals base register for function abi_decode_3 +move $r0 $$arg0 ; save argument 0 (buffer) +move $r1 $$reta ; save return address +lw $r2 $r0 i0 ; load word +lw $r2 $r2 i0 ; lw val ptr i0 +lw $r3 $r0 i0 ; load word +movi $r4 i8 ; initialize constant into register +add $r3 $r3 $r4 +sw $r0 $r3 i0 ; store word +move $$retv $r2 ; set return value +move $$reta $r1 ; restore return address +poph i524288 ; restore registers 40..64 +popl i31 ; restore registers 16..40 +jmp $$reta ; return from call +pshl i7 ; save registers 16..40 +pshh i524288 ; save registers 40..64 +move $$locbase $sp ; save locals base register for function main_8 +move $r2 $$reta ; save return address +lw $r0 $ssp i1 ; load word +lw $r1 $ssp i0 ; load word +add $r0 $r0 $r1 +move $$retv $r0 ; set return value +move $$reta $r2 ; restore return address +poph i524288 ; restore registers 40..64 +popl i7 ; restore registers 16..40 +jmp $$reta ; return from call +.data: +data__0 .bytes[8] 00 00 00 00 00 00 00 02 ........ +data__1 .bytes[8] 00 00 00 00 00 00 00 01 ........ + + + Finished release [optimized + fuel] target(s) [752 B] in ??? diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw index deee7c52ae5..8d0a9e93e2c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw @@ -6,7 +6,7 @@ use std::hash::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x14ed3cd06c2947248f69d54bfa681fe40d26267be84df7e19e253622b7921bbe; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x6b01f04c84ce955e8dfc6ed3611fd2518424ab757e5a540878f49fbd1bdec571; // AUTO-CONTRACT-ID ../../test_contracts/array_of_structs_contract --release +const CONTRACT_ID = 0xe0c85555f3d94e58cc23830deb6dc193e1f173761a4fc5d56d3e07a5a1db0378; // AUTO-CONTRACT-ID ../../test_contracts/array_of_structs_contract --release fn get_address() -> Option { Some(CONTRACT_ID.into()) diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw index 1c2a953fc35..6da541af0b8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw @@ -9,7 +9,7 @@ use test_fuel_coin_abi::*; #[cfg(experimental_new_encoding = false)] const FUEL_COIN_CONTRACT_ID = 0xec2277ebe007ade87e3d797c3b1e070dcd542d5ef8f038b471f262ef9cebc87c; #[cfg(experimental_new_encoding = true)] -const FUEL_COIN_CONTRACT_ID = 0x19c0d374734bd8a92b776787e9dffa0f105a90e3c977626f93a1916de54dd714; +const FUEL_COIN_CONTRACT_ID = 0xcdb572031a0779e09beea1e93e21630d104766c90cc8ce90c8dfd0abdd0ce5b2; // AUTO-CONTRACT-ID ../../test_contracts/test_fuel_coin_contract --release #[cfg(experimental_new_encoding = false)] const BALANCE_CONTRACT_ID = 0xf6cd545152ac83225e8e7df2efb5c6fa6e37bc9b9e977b5ea8103d28668925df; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/test.toml index a653725436b..ebf2e18c854 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/test.toml @@ -1,5 +1,8 @@ category = "run_on_node" expected_result = { action = "result", value = 1 } expected_result_new_encoding = { action = "return_data", value = "01" } -contracts = ["should_pass/test_contracts/balance_test_contract", "should_pass/test_contracts/test_fuel_coin_contract"] -unsupported_profiles = ["debug"] \ No newline at end of file +contracts = [ + "should_pass/test_contracts/balance_test_contract", + "should_pass/test_contracts/test_fuel_coin_contract", +] +unsupported_profiles = ["debug"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw index f3096a559c9..d6a56b1b07e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw @@ -4,7 +4,7 @@ use basic_storage_abi::{BasicStorage, Quad}; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x94db39f409a31b9f2ebcadeea44378e419208c20de90f5d8e1e33dc1523754cb; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x7d78bfaba7c715105ec3ec568b8c64dbb77491d45dec52b549e59c0cf5cf5c5e; // AUTO-CONTRACT-ID ../../test_contracts/basic_storage --release +const CONTRACT_ID = 0x52954afa6e6020d78b4daa89bc2bfceb31a7b85a97f55a49946f67d4e03b66c0; // AUTO-CONTRACT-ID ../../test_contracts/basic_storage --release fn main() -> u64 { let addr = abi(BasicStorage, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw index dae00c1579b..7dc873bf458 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw @@ -5,7 +5,7 @@ use contract_with_type_aliases_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x0cbeb6efe3104b460be769bdc4ea101ebf16ccc16f2d7b667ec3e1c7f5ce35b5; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x2e8efc627379d037c6ac70249d0bf0726f228ea6bade786e11639b878241f333; // AUTO-CONTRACT-ID ../../test_contracts/contract_with_type_aliases --release +const CONTRACT_ID = 0x5f2d9be937ca4a0de3404d1165d0faed6f8c440ab9ba7c6c046904e28761f7f7; // AUTO-CONTRACT-ID ../../test_contracts/contract_with_type_aliases --release fn main() { let caller = abi(MyContract, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw index 12e4d20fdec..181a7fd980a 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw @@ -6,7 +6,7 @@ use std::hash::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x3bc28acd66d327b8c1b9624c1fabfc07e9ffa1b5d71c2832c3bfaaf8f4b805e9; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xb509b52a765f2a8e97b29e4699d0ec8fa056b2bb649f785c75e36f868c318b98; // AUTO-CONTRACT-ID ../../test_contracts/storage_access_contract --release +const CONTRACT_ID = 0x03ad85f37b515247a0481ba4d1448a5592b8684312e7f2626d4403ab9fec2acc; // AUTO-CONTRACT-ID ../../test_contracts/storage_access_contract --release fn main() -> bool { let caller = abi(StorageAccess, CONTRACT_ID); From a02e8ead10b2c545a4f0aea591e457ac2f0150da Mon Sep 17 00:00:00 2001 From: Marcos Henrich Date: Thu, 28 Nov 2024 01:52:09 +0000 Subject: [PATCH 28/52] Error on use of self intead of Self in return type (#6763) ## Description With this PR we no longer support using `self` instead of `Self` when referring to the Self Type. Fixes #6396 ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --- .../transform/to_parsed_lang/convert_parse_tree.rs | 7 +++++-- sway-error/src/convert_parse_tree_error.rs | 3 +++ sway-lib-std/src/bytes.sw | 2 +- .../should_fail/self_return_type/Forc.lock | 8 ++++++++ .../should_fail/self_return_type/Forc.toml | 9 +++++++++ .../should_fail/self_return_type/src/main.sw | 13 +++++++++++++ .../should_fail/self_return_type/test.toml | 4 ++++ 7 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/test.toml 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 0cbf326b070..fd3fb725089 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 @@ -1446,7 +1446,7 @@ pub(crate) fn type_name_to_type_info_opt(name: &Ident) -> Option { "str" => Some(TypeInfo::StringSlice), "raw_ptr" => Some(TypeInfo::RawUntypedPtr), "raw_slice" => Some(TypeInfo::RawUntypedSlice), - "Self" | "self" => Some(TypeInfo::new_self_type(name.span())), + "Self" => Some(TypeInfo::new_self_type(name.span())), "Contract" => Some(TypeInfo::Contract), _other => None, } @@ -4598,7 +4598,10 @@ fn path_type_to_type_info( } } None => { - if name.as_str() == "ContractCaller" { + if name.as_str() == "self" { + let error = ConvertParseTreeError::UnknownTypeNameSelf { span }; + return Err(handler.emit_err(error.into())); + } else if name.as_str() == "ContractCaller" { if root_opt.is_some() || !suffix.is_empty() { let error = ConvertParseTreeError::FullySpecifiedTypesNotSupported { span }; return Err(handler.emit_err(error.into())); diff --git a/sway-error/src/convert_parse_tree_error.rs b/sway-error/src/convert_parse_tree_error.rs index 8b8a96528a0..fc95d213b37 100644 --- a/sway-error/src/convert_parse_tree_error.rs +++ b/sway-error/src/convert_parse_tree_error.rs @@ -121,6 +121,8 @@ pub enum ConvertParseTreeError { UnexpectedValueForCfgExperimental { span: Span }, #[error("Unexpected attribute value: \"{value}\" for attribute: \"cfg\"")] InvalidCfgArg { span: Span, value: String }, + #[error("Unknown type name \"self\". A self type with a similar name exists (notice the capitalization): `Self`")] + UnknownTypeNameSelf { span: Span }, } impl Spanned for ConvertParseTreeError { @@ -185,6 +187,7 @@ impl Spanned for ConvertParseTreeError { ConvertParseTreeError::ExpectedCfgProgramTypeArgValue { span } => span.clone(), ConvertParseTreeError::UnexpectedValueForCfgExperimental { span } => span.clone(), ConvertParseTreeError::InvalidCfgArg { span, .. } => span.clone(), + ConvertParseTreeError::UnknownTypeNameSelf { span } => span.clone(), } } } diff --git a/sway-lib-std/src/bytes.sw b/sway-lib-std/src/bytes.sw index c02b097811f..cb6a8edb521 100644 --- a/sway-lib-std/src/bytes.sw +++ b/sway-lib-std/src/bytes.sw @@ -692,7 +692,7 @@ impl Bytes { /// assert(bytes.capacity() == first_cap + second_cap); /// } /// ``` - pub fn append(ref mut self, ref mut other: self) { + pub fn append(ref mut self, ref mut other: Self) { let other_len = other.len(); if other_len == 0 { return diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.lock new file mode 100644 index 00000000000..58699a84e7e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "core" +source = "path+from-root-722DFCAB6A209427" + +[[package]] +name = "self_return_type" +source = "member" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.toml new file mode 100644 index 00000000000..40a91e8b7b5 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.toml @@ -0,0 +1,9 @@ +[project] +name = "self_return_type" +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +implicit-std = false + +[dependencies] +core = { path = "../../../../../../sway-lib-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/src/main.sw new file mode 100644 index 00000000000..659207244d6 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/src/main.sw @@ -0,0 +1,13 @@ +script; +trait MyTrait { + fn foo(self, other: Self) -> Self; +} +impl MyTrait for u8 { + fn foo(self, other: Self) -> self { + self + } +} +fn main() -> () { + let a = 1u8; + let _ = a.foo(2u8); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/test.toml new file mode 100644 index 00000000000..3bd3d799fb2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/test.toml @@ -0,0 +1,4 @@ +category = "fail" + +# check: $()fn foo(self, other: Self) -> self { +# nextln: $()Unknown type name "self". A self type with a similar name exists (notice the capitalization): `Self` \ No newline at end of file From 33d367497eb165176fa114df5951cca4e7021052 Mon Sep 17 00:00:00 2001 From: Marcos Henrich Date: Thu, 28 Nov 2024 15:28:30 +0000 Subject: [PATCH 29/52] Fixes `for` specific error message. (#6758) The added test case was emitting a wrong/confusing error message, because a for loop only gets type-checked in its desugared form, as a while loop. The error message was `A while loop's loop body cannot implicitly return a value. Try assigning it to a mutable variable declared outside of the loop instead.` Corrected to: `A for loop's loop body cannot implicitly return a value. Try assigning it to a mutable variable declared outside of the loop instead.` Fixes #6395 ## Description ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. Co-authored-by: IGI-111 --- .../src/language/parsed/expression/mod.rs | 1 + .../ast_node/expression/typed_expression.rs | 30 ++++++++++++++----- .../to_parsed_lang/convert_parse_tree.rs | 2 ++ .../should_fail/for_loop_error/Forc.lock | 13 ++++++++ .../should_fail/for_loop_error/Forc.toml | 8 +++++ .../for_loop_error/json_abi_oracle.json | 1 + .../should_fail/for_loop_error/src/main.sw | 12 ++++++++ .../should_fail/for_loop_error/test.toml | 13 ++++++++ 8 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/test.toml diff --git a/sway-core/src/language/parsed/expression/mod.rs b/sway-core/src/language/parsed/expression/mod.rs index 90d41fbf19b..7e03c3bf43e 100644 --- a/sway-core/src/language/parsed/expression/mod.rs +++ b/sway-core/src/language/parsed/expression/mod.rs @@ -370,6 +370,7 @@ impl PartialEqWithEngines for IntrinsicFunctionExpression { pub struct WhileLoopExpression { pub condition: Box, pub body: CodeBlock, + pub is_desugared_for_loop: bool, } impl EqWithEngines for WhileLoopExpression {} diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 3d6204c46ce..3d4d5259ec1 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -506,9 +506,18 @@ impl ty::TyExpression { arguments, span, ), - ExpressionKind::WhileLoop(WhileLoopExpression { condition, body }) => { - Self::type_check_while_loop(handler, ctx.by_ref(), condition, body, span) - } + ExpressionKind::WhileLoop(WhileLoopExpression { + condition, + body, + is_desugared_for_loop, + }) => Self::type_check_while_loop( + handler, + ctx.by_ref(), + condition, + body, + *is_desugared_for_loop, + span, + ), ExpressionKind::ForLoop(ForLoopExpression { desugared }) => { Self::type_check_for_loop(handler, ctx.by_ref(), desugared) } @@ -2131,6 +2140,7 @@ impl ty::TyExpression { mut ctx: TypeCheckContext, condition: &Expression, body: &CodeBlock, + is_desugared_for_loop: bool, span: Span, ) -> Result { let type_engine = ctx.engines.te(); @@ -2144,11 +2154,17 @@ impl ty::TyExpression { }; let unit_ty = type_engine.id_of_unit(); - let mut ctx = ctx.with_type_annotation(unit_ty).with_help_text( - "A while loop's loop body cannot implicitly return a value. Try \ + let mut ctx = ctx + .with_type_annotation(unit_ty) + .with_help_text(if is_desugared_for_loop { + "A for loop's loop body cannot implicitly return a value. Try \ assigning it to a mutable variable declared outside of the loop \ - instead.", - ); + instead." + } else { + "A while loop's loop body cannot implicitly return a value. Try \ + assigning it to a mutable variable declared outside of the loop \ + instead." + }); let typed_body = ty::TyCodeBlock::type_check(handler, ctx.by_ref(), body, false)?; let exp = ty::TyExpression { 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 fd3fb725089..cf3f8daab71 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 @@ -2131,6 +2131,7 @@ fn expr_to_expression( kind: ExpressionKind::WhileLoop(WhileLoopExpression { condition: Box::new(expr_to_expression(context, handler, engines, *condition)?), body: braced_code_block_contents_to_code_block(context, handler, engines, block)?, + is_desugared_for_loop: false, }), span, }, @@ -3278,6 +3279,7 @@ fn for_expr_to_expression( span: Span::dummy(), }), body: while_body, + is_desugared_for_loop: true, }), span: Span::dummy(), }), diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.lock new file mode 100644 index 00000000000..cc167580e1e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-FF35018BB7DF2595" + +[[package]] +name = "for_loop_error" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-FF35018BB7DF2595" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.toml new file mode 100644 index 00000000000..700b97ff4e3 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +license = "Apache-2.0" +name = "for_loop_error" +entry = "main.sw" + +[dependencies] +std = { path = "../../../reduced_std_libs/sway-lib-std-vec" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/json_abi_oracle.json new file mode 100644 index 00000000000..0637a088a01 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/json_abi_oracle.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/src/main.sw new file mode 100644 index 00000000000..5c3f883c10d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/src/main.sw @@ -0,0 +1,12 @@ +script; + +fn main() { + let mut v : Vec = Vec::new(); + v.push(1); + v.push(2); + v.push(3); + for elem in v.iter() { + log(elem); + 3 + }; +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/test.toml new file mode 100644 index 00000000000..e738a23e98e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/test.toml @@ -0,0 +1,13 @@ +category = "fail" + +# check: $()3 +# nextln: $()Mismatched types. +# nextln: $()expected: () +# nextln: $()found: numeric. +# nextln: $()Implicit return must match up with block's type. + +# check: $()3 +# nextln: $()Mismatched types. +# nextln: $()expected: () +# nextln: $()found: numeric. +# nextln: $()A for loop's loop body cannot implicitly return a value. Try assigning it to a mutable variable declared outside of the loop instead. \ No newline at end of file From 2bc469ad8ca323aea29fede836805d51db1c0a18 Mon Sep 17 00:00:00 2001 From: Joshua Batty Date: Sat, 30 Nov 2024 08:11:17 +1100 Subject: [PATCH 30/52] Improve document symbol hierarchy to match rust-analyzer layout (#6678) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Changes document symbols to provide a richer code outline view with nested hierarchies and type information, similar to rust-analyzer's implementation. This improves code navigation by showing relationships between elements (e.g., structs with their fields, functions with their variables) and includes type annotations for better understanding. Key improvements: - Nested symbol hierarchy instead of flat list - Type information in symbol details - Function signatures with parameter/return types - Proper parent-child relationships for all code elements - Better outline view organization Screenshot 2024-11-26 at 2 25 17 PM Note: the performance impact is due to the `get_range_from_span` function which can't avoid calling. 19ms is still reasonable. closes #6100 ## 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). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --- sway-lsp/benches/lsp_benchmarks/requests.rs | 4 +- sway-lsp/src/capabilities/document_symbol.rs | 558 +++++++++++++++++-- sway-lsp/src/core/session.rs | 25 +- sway-lsp/src/handlers/request.rs | 4 +- sway-lsp/tests/integration/lsp.rs | 60 +- sway-lsp/tests/lib.rs | 2 +- 6 files changed, 586 insertions(+), 67 deletions(-) diff --git a/sway-lsp/benches/lsp_benchmarks/requests.rs b/sway-lsp/benches/lsp_benchmarks/requests.rs index c2c79eaf25c..ce9081cd7a9 100644 --- a/sway-lsp/benches/lsp_benchmarks/requests.rs +++ b/sway-lsp/benches/lsp_benchmarks/requests.rs @@ -24,8 +24,8 @@ fn benchmarks(c: &mut Criterion) { c.bench_function("document_symbol", |b| { b.iter(|| { session - .symbol_information(&uri) - .map(DocumentSymbolResponse::Flat) + .document_symbols(&uri) + .map(DocumentSymbolResponse::Nested) }) }); diff --git a/sway-lsp/src/capabilities/document_symbol.rs b/sway-lsp/src/capabilities/document_symbol.rs index 79f90b1eeba..5e31b65ff4a 100644 --- a/sway-lsp/src/capabilities/document_symbol.rs +++ b/sway-lsp/src/capabilities/document_symbol.rs @@ -1,60 +1,514 @@ -use crate::core::token::{SymbolKind, Token, TokenIdent}; -use dashmap::mapref::multiple::RefMulti; -use lsp_types::{self, Location, SymbolInformation, Url}; - -pub fn to_symbol_information<'a, I>(tokens: I, url: &Url) -> Vec -where - I: Iterator>, -{ - tokens - .map(|entry| { - let (ident, token) = entry.pair(); - symbol_info(ident, token, url.clone()) +use crate::core::{token::get_range_from_span, token_map::TokenMap}; +use lsp_types::{self, DocumentSymbol, Url}; +use std::path::PathBuf; +use sway_core::{ + language::ty::{ + TyAbiDecl, TyAstNodeContent, TyConstantDecl, TyDecl, TyEnumDecl, TyFunctionDecl, + TyFunctionParameter, TyProgram, TyStorageDecl, TyStructDecl, TyTraitInterfaceItem, + TyTraitItem, TyTraitType, + }, + Engines, TypeArgument, +}; +use sway_types::{Span, Spanned}; + +/// Generates a hierarchical document symbol tree for LSP code outline/navigation. +/// Processes declarations (functions, structs, enums, etc.) into nested symbols, +/// preserving parent-child relationships like functions with their variables, +/// structs with their fields, and traits with their methods. +pub fn to_document_symbols( + uri: &Url, + path: &PathBuf, + ty_program: &TyProgram, + engines: &Engines, + token_map: &TokenMap, +) -> Vec { + let source_id = engines.se().get_source_id(path); + + // Find if there is a configurable symbol in the token map that belongs to the current file + // We will add children symbols to this when we encounter configurable declarations below. + let mut configurable_symbol = token_map + .tokens_for_file(uri) + .find(|item| item.key().name == "configurable") + .map(|item| { + DocumentSymbolBuilder::new() + .name(item.key().name.clone()) + .kind(lsp_types::SymbolKind::STRUCT) + .range(item.key().range) + .selection_range(item.key().range) + .children(vec![]) + .build() + }); + + // Only include nodes that originate from the file. + let mut nodes: Vec<_> = (if ty_program.root.span.source_id() == Some(&source_id) { + Some(ty_program.root.all_nodes.iter()) + } else { + ty_program + .root + .submodules_recursive() + .find(|(_, submodule)| submodule.module.span.source_id() == Some(&source_id)) + .map(|(_, submodule)| submodule.module.all_nodes.iter()) + }) + .into_iter() + .flatten() + .filter_map(|node| { + match &node.content { + TyAstNodeContent::Declaration(decl) => match decl { + TyDecl::FunctionDecl(decl) => { + let fn_decl = engines.de().get_function(&decl.decl_id); + let range = get_range_from_span(&fn_decl.name.span()); + let detail = Some(fn_decl_detail(&fn_decl.parameters, &fn_decl.return_type)); + let children = collect_variables_from_func_decl(engines, &fn_decl); + let func_symbol = DocumentSymbolBuilder::new() + .name(fn_decl.name.span().str().to_string()) + .kind(lsp_types::SymbolKind::FUNCTION) + .range(range) + .selection_range(range) + .detail(detail) + .children(children) + .build(); + Some(func_symbol) + } + TyDecl::EnumDecl(decl) => { + let enum_decl = engines.de().get_enum(&decl.decl_id); + let span = enum_decl.call_path.suffix.span(); + let range = get_range_from_span(&span); + let children = collect_enum_variants(&enum_decl); + let enum_symbol = DocumentSymbolBuilder::new() + .name(span.str().to_string()) + .kind(lsp_types::SymbolKind::ENUM) + .range(range) + .selection_range(range) + .children(children) + .build(); + Some(enum_symbol) + } + TyDecl::StructDecl(decl) => { + let struct_decl = engines.de().get_struct(&decl.decl_id); + let span = struct_decl.call_path.suffix.span(); + let range = get_range_from_span(&span); + let children = collect_struct_fields(&struct_decl); + let struct_symbol = DocumentSymbolBuilder::new() + .name(span.str().to_string()) + .kind(lsp_types::SymbolKind::STRUCT) + .range(range) + .selection_range(range) + .children(children) + .build(); + Some(struct_symbol) + } + TyDecl::AbiDecl(decl) => { + let abi_decl = engines.de().get_abi(&decl.decl_id); + let decl_str = abi_decl.span().str(); + let name = extract_header(&decl_str); + let range = get_range_from_span(&abi_decl.name.span()); + let children = collect_fns_from_abi_decl(engines, &abi_decl); + let abi_symbol = DocumentSymbolBuilder::new() + .name(name) + .kind(lsp_types::SymbolKind::NAMESPACE) + .range(range) + .selection_range(range) + .children(children) + .build(); + Some(abi_symbol) + } + TyDecl::TraitDecl(decl) => { + let trait_decl = engines.de().get_trait(&decl.decl_id); + let decl_str = trait_decl.span().str().to_string(); + let name = extract_header(&decl_str); + let range = get_range_from_span(&trait_decl.name.span()); + let children = + collect_interface_surface(engines, &trait_decl.interface_surface); + let trait_symbol = DocumentSymbolBuilder::new() + .name(name) + .kind(lsp_types::SymbolKind::INTERFACE) + .range(range) + .selection_range(range) + .children(children) + .build(); + Some(trait_symbol) + } + TyDecl::TraitTypeDecl(decl) => { + let trait_type_decl = engines.de().get_type(&decl.decl_id); + Some(build_trait_symbol(&trait_type_decl)) + } + TyDecl::ImplSelfOrTrait(decl) => { + let impl_trait_decl = engines.de().get_impl_self_or_trait(&decl.decl_id); + let decl_str = impl_trait_decl.span().str().to_string(); + let name = extract_header(&decl_str); + let range = get_range_from_span(&impl_trait_decl.trait_name.suffix.span()); + let children = collect_ty_trait_items(engines, &impl_trait_decl.items); + let symbol = DocumentSymbolBuilder::new() + .name(name) + .kind(lsp_types::SymbolKind::NAMESPACE) + .range(range) + .selection_range(range) + .children(children) + .build(); + Some(symbol) + } + TyDecl::ConstantDecl(decl) => { + let const_decl = engines.de().get_constant(&decl.decl_id); + Some(build_constant_symbol(&const_decl)) + } + TyDecl::StorageDecl(decl) => { + let storage_decl = engines.de().get_storage(&decl.decl_id); + let span = storage_decl.storage_keyword.span(); + let range = get_range_from_span(&span); + let children = collect_fields_from_storage(&storage_decl); + let storage_symbol = DocumentSymbolBuilder::new() + .name(span.str().to_string()) + .kind(lsp_types::SymbolKind::STRUCT) + .range(range) + .selection_range(range) + .children(children) + .build(); + Some(storage_symbol) + } + TyDecl::ConfigurableDecl(decl) => { + let configurable_decl = engines.de().get_configurable(&decl.decl_id); + let span = configurable_decl.call_path.suffix.span(); + let range = get_range_from_span(&span); + let symbol = DocumentSymbolBuilder::new() + .name(span.str().to_string()) + .kind(lsp_types::SymbolKind::FIELD) + .detail(Some( + configurable_decl.type_ascription.span.as_str().to_string(), + )) + .range(range) + .selection_range(range) + .build(); + // Add symbol to the end of configurable_symbol's children field + configurable_symbol + .as_mut()? + .children + .as_mut()? + .push(symbol); + None + } + _ => None, + }, + _ => None, + } + }) + .collect(); + + // Add configurable symbol to the end after all children symbols have been added + if let Some(symbol) = configurable_symbol { + nodes.push(symbol); + } + + // Sort by range start position + nodes.sort_by_key(|node| node.range.start); + nodes +} + +fn build_constant_symbol(const_decl: &TyConstantDecl) -> DocumentSymbol { + let span = const_decl.call_path.suffix.span(); + let range = get_range_from_span(&span); + DocumentSymbolBuilder::new() + .name(span.str().to_string()) + .kind(lsp_types::SymbolKind::CONSTANT) + .detail(Some(const_decl.type_ascription.span.as_str().to_string())) + .range(range) + .selection_range(range) + .build() +} + +fn build_trait_symbol(trait_type_decl: &TyTraitType) -> DocumentSymbol { + let span = trait_type_decl.name.span(); + let range = get_range_from_span(&span); + DocumentSymbolBuilder::new() + .name(span.str().to_string()) + .kind(lsp_types::SymbolKind::TYPE_PARAMETER) + .range(range) + .selection_range(range) + .build() +} + +fn collect_interface_surface( + engines: &Engines, + items: &[TyTraitInterfaceItem], +) -> Vec { + items + .iter() + .map(|item| match item { + TyTraitInterfaceItem::TraitFn(decl_ref) => { + let fn_decl = engines.de().get_trait_fn(decl_ref); + build_function_symbol( + &fn_decl.name.span(), + &fn_decl.parameters, + &fn_decl.return_type, + ) + } + TyTraitInterfaceItem::Constant(decl_ref) => { + let const_decl = engines.de().get_constant(decl_ref); + build_constant_symbol(&const_decl) + } + TyTraitInterfaceItem::Type(decl_ref) => { + let trait_type_decl = engines.de().get_type(decl_ref); + build_trait_symbol(&trait_type_decl) + } + }) + .collect() +} + +fn collect_ty_trait_items(engines: &Engines, items: &[TyTraitItem]) -> Vec { + items + .iter() + .filter_map(|item| match item { + TyTraitItem::Fn(decl_ref) => Some(engines.de().get_function(decl_ref)), + _ => None, + }) + .map(|fn_decl| { + let children = collect_variables_from_func_decl(engines, &fn_decl); + let mut symbol = build_function_symbol( + &fn_decl.name.span(), + &fn_decl.parameters, + &fn_decl.return_type, + ); + symbol.children = Some(children); + symbol }) .collect() } -/// Given a `token::SymbolKind`, return the `lsp_types::SymbolKind` that corresponds to it. -pub(crate) fn symbol_kind(symbol_kind: &SymbolKind) -> lsp_types::SymbolKind { - match symbol_kind { - SymbolKind::Field => lsp_types::SymbolKind::FIELD, - SymbolKind::BuiltinType | SymbolKind::TypeParameter => { - lsp_types::SymbolKind::TYPE_PARAMETER +fn collect_fields_from_storage(decl: &TyStorageDecl) -> Vec { + decl.fields + .iter() + .map(|field| build_field_symbol(&field.name.span(), &field.type_argument)) + .collect() +} + +fn build_field_symbol(span: &Span, type_argument: &TypeArgument) -> DocumentSymbol { + let range = get_range_from_span(span); + DocumentSymbolBuilder::new() + .name(span.clone().str().to_string()) + .detail(Some(type_argument.span.as_str().to_string())) + .kind(lsp_types::SymbolKind::FIELD) + .range(range) + .selection_range(range) + .build() +} + +fn build_function_symbol( + span: &Span, + parameters: &[TyFunctionParameter], + return_type: &TypeArgument, +) -> DocumentSymbol { + let range = get_range_from_span(span); + DocumentSymbolBuilder::new() + .name(span.clone().str().to_string()) + .detail(Some(fn_decl_detail(parameters, return_type))) + .kind(lsp_types::SymbolKind::FUNCTION) + .range(range) + .selection_range(range) + .build() +} + +fn collect_fns_from_abi_decl(engines: &Engines, decl: &TyAbiDecl) -> Vec { + decl.interface_surface + .iter() + .filter_map(|item| match item { + TyTraitInterfaceItem::TraitFn(decl_ref) => Some(engines.de().get_trait_fn(decl_ref)), + _ => None, + }) + .map(|trait_fn| { + build_function_symbol( + &trait_fn.name.span(), + &trait_fn.parameters, + &trait_fn.return_type, + ) + }) + .collect() +} + +fn collect_struct_fields(decl: &TyStructDecl) -> Vec { + decl.fields + .iter() + .map(|field| build_field_symbol(&field.name.span(), &field.type_argument)) + .collect() +} + +// Collect all enum variants +fn collect_enum_variants(decl: &TyEnumDecl) -> Vec { + decl.variants + .iter() + .map(|variant| { + let range = get_range_from_span(&variant.name.span()); + // Check for the presence of a CallPathTree, and if it exists, use the type information as the detail. + let detail = variant + .type_argument + .call_path_tree + .as_ref() + .map(|_| Some(variant.type_argument.span.as_str().to_string())) + .unwrap_or(None); + + DocumentSymbolBuilder::new() + .name(variant.name.span().str().to_string()) + .kind(lsp_types::SymbolKind::ENUM_MEMBER) + .range(range) + .selection_range(range) + .detail(detail) + .build() + }) + .collect() +} + +// Collect all variables declared within the function body +fn collect_variables_from_func_decl( + engines: &Engines, + decl: &TyFunctionDecl, +) -> Vec { + decl.body + .contents + .iter() + .filter_map(|node| { + if let TyAstNodeContent::Declaration(TyDecl::VariableDecl(var_decl)) = &node.content { + let range = get_range_from_span(&var_decl.name.span()); + let type_name = format!("{}", engines.help_out(var_decl.type_ascription.type_id)); + let symbol = DocumentSymbolBuilder::new() + .name(var_decl.name.span().str().to_string()) + .kind(lsp_types::SymbolKind::VARIABLE) + .range(range) + .selection_range(range) + .detail((!type_name.is_empty()).then_some(type_name)) + .build(); + Some(symbol) + } else { + None + } + }) + .collect() +} + +// Generate the signature for functions +fn fn_decl_detail(parameters: &[TyFunctionParameter], return_type: &TypeArgument) -> String { + let params = parameters + .iter() + .map(|p| format!("{}: {}", p.name, p.type_argument.span.as_str())) + .collect::>() + .join(", "); + + // Check for the presence of a CallPathTree, and if it exists, add it to the return type. + let return_type = return_type + .call_path_tree + .as_ref() + .map(|_| format!(" -> {}", return_type.span.as_str())) + .unwrap_or_default(); + format!("fn({}){}", params, return_type) +} + +/// Extracts the header of a sway construct such as an `impl` block or `abi` declaration, +/// including any generic parameters, traits, or super traits, up to (but not including) +/// the opening `{` character. Trims any trailing whitespace. +/// +/// If the `{` character is not found, the entire string is returned without trailing whitespace. +/// +/// # Examples +/// +/// ``` +/// let impl_example = "impl Setter for FooBarData {\n fn set(self, new_value: T) -> Self {\n FooBarData {\n value: new_value,\n }\n }\n}"; +/// let result = extract_header(impl_example); +/// assert_eq!(result, "impl Setter for FooBarData"); +/// +/// let abi_example = "abi MyAbi : MySuperAbi {\n fn bar();\n}"; +/// let result = extract_header(abi_example); +/// assert_eq!(result, "abi MyAbi : MySuperAbi"); +/// ``` +fn extract_header(s: &str) -> &str { + if let Some(pos) = s.find('{') { + s[..pos].trim_end() + } else { + s.trim_end() + } +} + +/// Builder for creating [`DocumentSymbol`] instances with method chaining. +/// Initializes with empty name, NULL kind, and zero position ranges. +pub struct DocumentSymbolBuilder { + name: String, + detail: Option, + kind: lsp_types::SymbolKind, + tags: Option>, + range: lsp_types::Range, + selection_range: lsp_types::Range, + children: Option>, + deprecated: Option, +} + +impl Default for DocumentSymbolBuilder { + fn default() -> Self { + Self::new() + } +} + +impl DocumentSymbolBuilder { + pub fn new() -> Self { + Self { + name: String::new(), + kind: lsp_types::SymbolKind::NULL, + range: lsp_types::Range::new( + lsp_types::Position::new(0, 0), + lsp_types::Position::new(0, 0), + ), + selection_range: lsp_types::Range::new( + lsp_types::Position::new(0, 0), + lsp_types::Position::new(0, 0), + ), + detail: None, + tags: None, + children: None, + deprecated: None, } - SymbolKind::Function | SymbolKind::DeriveHelper | SymbolKind::Intrinsic => { - lsp_types::SymbolKind::FUNCTION + } + + pub fn name(mut self, name: impl Into) -> Self { + self.name = name.into(); + self + } + + pub fn kind(mut self, kind: lsp_types::SymbolKind) -> Self { + self.kind = kind; + self + } + + pub fn range(mut self, range: lsp_types::Range) -> Self { + self.range = range; + self + } + + pub fn selection_range(mut self, range: lsp_types::Range) -> Self { + self.selection_range = range; + self + } + + pub fn detail(mut self, detail: Option) -> Self { + self.detail = detail; + self + } + + pub fn tags(mut self, tags: Vec) -> Self { + self.tags = Some(tags); + self + } + + pub fn children(mut self, children: Vec) -> Self { + self.children = Some(children); + self + } + + pub fn build(self) -> DocumentSymbol { + #[allow(warnings)] + DocumentSymbol { + name: self.name, + detail: self.detail, + kind: self.kind, + tags: self.tags, + range: self.range, + selection_range: self.selection_range, + children: self.children, + deprecated: self.deprecated, } - SymbolKind::Const => lsp_types::SymbolKind::CONSTANT, - SymbolKind::Struct => lsp_types::SymbolKind::STRUCT, - SymbolKind::Trait => lsp_types::SymbolKind::INTERFACE, - SymbolKind::Module => lsp_types::SymbolKind::MODULE, - SymbolKind::Enum => lsp_types::SymbolKind::ENUM, - SymbolKind::Variant => lsp_types::SymbolKind::ENUM_MEMBER, - SymbolKind::BoolLiteral => lsp_types::SymbolKind::BOOLEAN, - SymbolKind::StringLiteral => lsp_types::SymbolKind::STRING, - SymbolKind::NumericLiteral => lsp_types::SymbolKind::NUMBER, - SymbolKind::ValueParam - | SymbolKind::ByteLiteral - | SymbolKind::Variable - | SymbolKind::TypeAlias - | SymbolKind::TraitType - | SymbolKind::Keyword - | SymbolKind::SelfKeyword - | SymbolKind::SelfTypeKeyword - | SymbolKind::ProgramTypeKeyword - | SymbolKind::Unknown => lsp_types::SymbolKind::VARIABLE, - } -} - -#[allow(warnings)] -// TODO: the "deprecated: None" field is deprecated according to this library -fn symbol_info(ident: &TokenIdent, token: &Token, url: Url) -> SymbolInformation { - SymbolInformation { - name: ident.name.to_string(), - kind: symbol_kind(&token.kind), - location: Location::new(url, ident.range), - tags: None, - container_name: None, - deprecated: None, } } diff --git a/sway-lsp/src/core/session.rs b/sway-lsp/src/core/session.rs index 0129c8fa583..26f0bccb4b6 100644 --- a/sway-lsp/src/core/session.rs +++ b/sway-lsp/src/core/session.rs @@ -19,7 +19,7 @@ use crate::{ use dashmap::DashMap; use forc_pkg as pkg; use lsp_types::{ - CompletionItem, GotoDefinitionResponse, Location, Position, Range, SymbolInformation, Url, + CompletionItem, DocumentSymbol, GotoDefinitionResponse, Location, Position, Range, Url, }; use parking_lot::RwLock; use pkg::{ @@ -248,12 +248,23 @@ impl Session { Some(program.root.namespace) } - pub fn symbol_information(&self, url: &Url) -> Option> { - let _p = tracing::trace_span!("symbol_information").entered(); - let tokens = self.token_map.tokens_for_file(url); - self.sync - .to_workspace_url(url.clone()) - .map(|url| capabilities::document_symbol::to_symbol_information(tokens, &url)) + /// Generate hierarchical document symbols for the given file. + pub fn document_symbols(&self, url: &Url) -> Option> { + let _p = tracing::trace_span!("document_symbols").entered(); + let path = url.to_file_path().ok()?; + self.compiled_program + .read() + .typed + .as_ref() + .map(|ty_program| { + capabilities::document_symbol::to_document_symbols( + url, + &path, + ty_program, + &self.engines.read(), + &self.token_map, + ) + }) } /// Populate [Documents] with sway files found in the workspace. diff --git a/sway-lsp/src/handlers/request.rs b/sway-lsp/src/handlers/request.rs index fb4b72d86a8..68d9de0b27c 100644 --- a/sway-lsp/src/handlers/request.rs +++ b/sway-lsp/src/handlers/request.rs @@ -67,8 +67,8 @@ pub async fn handle_document_symbol( .await { Ok((uri, session)) => Ok(session - .symbol_information(&uri) - .map(DocumentSymbolResponse::Flat)), + .document_symbols(&uri) + .map(DocumentSymbolResponse::Nested)), Err(err) => { tracing::error!("{}", err.to_string()); Ok(None) diff --git a/sway-lsp/tests/integration/lsp.rs b/sway-lsp/tests/integration/lsp.rs index b187510b5fb..0b5303994cb 100644 --- a/sway-lsp/tests/integration/lsp.rs +++ b/sway-lsp/tests/integration/lsp.rs @@ -247,7 +247,7 @@ pub(crate) async fn semantic_tokens_request(server: &ServerState, uri: &Url) { } } -pub(crate) async fn document_symbol_request(server: &ServerState, uri: &Url) { +pub(crate) async fn document_symbols_request(server: &ServerState, uri: &Url) { let params = DocumentSymbolParams { text_document: TextDocumentIdentifier { uri: uri.clone() }, work_done_progress_params: Default::default(), @@ -256,8 +256,62 @@ pub(crate) async fn document_symbol_request(server: &ServerState, uri: &Url) { let response = request::handle_document_symbol(server, params) .await .unwrap(); - if let Some(DocumentSymbolResponse::Flat(res)) = response { - assert!(!res.is_empty()); + + if let Some(DocumentSymbolResponse::Nested(symbols)) = response { + // Check for enum with its variants + let enum_symbol = symbols + .iter() + .find(|s| s.name == "NumberOrString") + .expect("Should find NumberOrString enum"); + assert_eq!(enum_symbol.kind, SymbolKind::ENUM); + let variants = enum_symbol + .children + .as_ref() + .expect("Enum should have variants"); + assert_eq!(variants.len(), 2); + assert!(variants.iter().any(|v| v.name == "Number")); + assert!(variants.iter().any(|v| v.name == "String")); + + // Check for struct with its fields + let struct_symbol = symbols + .iter() + .find(|s| s.name == "Data") + .expect("Should find Data struct"); + assert_eq!(struct_symbol.kind, SymbolKind::STRUCT); + let fields = struct_symbol + .children + .as_ref() + .expect("Struct should have fields"); + assert_eq!(fields.len(), 2); + assert!(fields + .iter() + .any(|f| f.name == "value" && f.detail.as_deref() == Some("NumberOrString"))); + assert!(fields + .iter() + .any(|f| f.name == "address" && f.detail.as_deref() == Some("u64"))); + + // Check for impl with nested function and variable + let impl_symbol = symbols + .iter() + .find(|s| s.name == "impl FooABI for Contract") + .expect("Should find impl block"); + let impl_fns = impl_symbol + .children + .as_ref() + .expect("Impl should have functions"); + let main_fn = impl_fns + .iter() + .find(|f| f.name == "main") + .expect("Should find main function"); + let vars = main_fn + .children + .as_ref() + .expect("Function should have variables"); + assert!(vars + .iter() + .any(|v| v.name == "_data" && v.detail.as_deref() == Some("Data"))); + } else { + panic!("Expected nested document symbols response"); } } diff --git a/sway-lsp/tests/lib.rs b/sway-lsp/tests/lib.rs index 39e9174a96f..f37a8cc1da9 100644 --- a/sway-lsp/tests/lib.rs +++ b/sway-lsp/tests/lib.rs @@ -1952,7 +1952,7 @@ lsp_capability_test!( ); lsp_capability_test!( document_symbol, - lsp::document_symbol_request, + lsp::document_symbols_request, doc_comments_dir().join("src/main.sw") ); lsp_capability_test!( From 6d9065b8d762a39eb475562426a2d4ed17d92d00 Mon Sep 17 00:00:00 2001 From: Marcos Henrich Date: Fri, 29 Nov 2024 22:00:33 +0000 Subject: [PATCH 31/52] Fixes qualified call path without as trait. (#6764) ## Description The parser no longer parses qualified call paths without the `as` token and trait. This invalidates code that was previously accepted such as: `let x: ::S:: = S::{x: 8};` Fixes #6389 ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. Co-authored-by: Joshua Batty --- sway-ast/src/path.rs | 2 +- .../to_parsed_lang/convert_parse_tree.rs | 28 ++++++++----------- sway-parse/src/path.rs | 5 +--- swayfmt/src/utils/language/path.rs | 7 ++--- .../Forc.lock | 13 +++++++++ .../Forc.toml | 8 ++++++ .../src/main.sw | 9 ++++++ .../test.toml | 4 +++ 8 files changed, 51 insertions(+), 25 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/test.toml diff --git a/sway-ast/src/path.rs b/sway-ast/src/path.rs index b472426c8d9..c7be1225e87 100644 --- a/sway-ast/src/path.rs +++ b/sway-ast/src/path.rs @@ -110,5 +110,5 @@ impl Spanned for PathTypeSegment { #[derive(Clone, Debug, Serialize)] pub struct QualifiedPathRoot { pub ty: Box, - pub as_trait: Option<(AsToken, Box)>, + pub as_trait: (AsToken, Box), } 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 cf3f8daab71..98b554311a6 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 @@ -3335,22 +3335,18 @@ fn path_root_opt_to_bool_and_qualified_path_root( close_angle_bracket_token: _, }), _, - )) => ( - false, - if let Some((_, path_type)) = as_trait { - Some(QualifiedPathType { - ty: ty_to_type_argument(context, handler, engines, *ty)?, - as_trait: engines.te().insert( - engines, - path_type_to_type_info(context, handler, engines, *path_type.clone())?, - path_type.span().source_id(), - ), - as_trait_span: path_type.span(), - }) - } else { - None - }, - ), + )) => (false, { + let (_, path_type) = as_trait; + Some(QualifiedPathType { + ty: ty_to_type_argument(context, handler, engines, *ty)?, + as_trait: engines.te().insert( + engines, + path_type_to_type_info(context, handler, engines, *path_type.clone())?, + path_type.span().source_id(), + ), + as_trait_span: path_type.span(), + }) + }), }) } diff --git a/sway-parse/src/path.rs b/sway-parse/src/path.rs index a9bb8c3826a..657e339747c 100644 --- a/sway-parse/src/path.rs +++ b/sway-parse/src/path.rs @@ -121,10 +121,7 @@ impl Parse for PathTypeSegment { impl Parse for QualifiedPathRoot { fn parse(parser: &mut Parser) -> ParseResult { let ty = parser.parse()?; - let as_trait = match parser.take() { - Some(as_token) => Some((as_token, parser.parse()?)), - None => None, - }; + let as_trait = (parser.parse()?, parser.parse()?); Ok(QualifiedPathRoot { ty, as_trait }) } } diff --git a/swayfmt/src/utils/language/path.rs b/swayfmt/src/utils/language/path.rs index 78711542b7f..f8575f185b0 100644 --- a/swayfmt/src/utils/language/path.rs +++ b/swayfmt/src/utils/language/path.rs @@ -62,10 +62,9 @@ impl Format for QualifiedPathRoot { formatter: &mut Formatter, ) -> Result<(), FormatterError> { self.ty.format(formatted_code, formatter)?; - if let Some((as_token, path_type)) = &self.as_trait { - write!(formatted_code, " {} ", as_token.span().as_str())?; - path_type.format(formatted_code, formatter)?; - } + let (as_token, path_type) = &self.as_trait; + write!(formatted_code, " {} ", as_token.span().as_str())?; + path_type.format(formatted_code, formatter)?; Ok(()) } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.lock new file mode 100644 index 00000000000..e319a387961 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-3A3AB9F18BDA9100" + +[[package]] +name = "parser_generic_turbo_fish_prefix" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-3A3AB9F18BDA9100" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.toml new file mode 100644 index 00000000000..22143b9b5eb --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "parser_generic_turbo_fish_prefix" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/src/main.sw new file mode 100644 index 00000000000..af437cc603e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/src/main.sw @@ -0,0 +1,9 @@ +script; + +struct S { + x: T, +} + +fn main() { + let x: ::S:: = S::{x: 8}; +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/test.toml new file mode 100644 index 00000000000..cfb2e0f1a93 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/test.toml @@ -0,0 +1,4 @@ +category = "fail" + +# check: $()let x: ::S:: = S::{x: 8}; +# nextln: $()Expected `as`. From 37205445ab5c54f4a37fa6d43b9f2fdad1b5ad7a Mon Sep 17 00:00:00 2001 From: Joshua Batty Date: Mon, 2 Dec 2024 09:48:45 +1100 Subject: [PATCH 32/52] Implement Serde for AstNode types (#6605) ## Description This PR extends Serde support across all AstNode-related types, building upon the partial implementation from #4193. Key points: * Adds both `Serialize` and `Deserialize` trait implementations to all relevant types. * Prepares for upcoming language server features that will serialize/deserialize types between keystrokes. * Important: The type interface in the compiler is not yet stable. This implementation is intended for temporary serialization/deserialization work, not for persistent storage. ## Checklist - [x] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] 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. --- sway-ast/src/intrinsics.rs | 3 +- sway-ast/src/literal.rs | 14 +- sway-ast/src/priv_prelude.rs | 2 +- sway-core/Cargo.toml | 2 +- sway-core/src/decl_engine/id.rs | 41 +++- .../src/decl_engine/interface_decl_id.rs | 6 +- sway-core/src/decl_engine/parsed_id.rs | 47 +++- sway-core/src/decl_engine/ref.rs | 11 +- sway-core/src/language/asm.rs | 6 +- sway-core/src/language/call_path.rs | 24 +- sway-core/src/language/lazy_op.rs | 4 +- sway-core/src/language/literal.rs | 9 +- .../src/language/parsed/declaration/trait.rs | 11 +- .../src/language/parsed/expression/mod.rs | 6 +- .../src/language/parsed/use_statement.rs | 3 +- sway-core/src/language/purity.rs | 4 +- sway-core/src/language/ty/ast_node.rs | 21 +- sway-core/src/language/ty/code_block.rs | 11 +- sway-core/src/language/ty/declaration/abi.rs | 7 +- .../language/ty/declaration/configurable.rs | 17 +- .../src/language/ty/declaration/constant.rs | 17 +- .../language/ty/declaration/declaration.rs | 46 ++-- sway-core/src/language/ty/declaration/enum.rs | 25 +- .../src/language/ty/declaration/function.rs | 36 ++- .../src/language/ty/declaration/impl_trait.rs | 12 +- .../src/language/ty/declaration/storage.rs | 19 +- .../src/language/ty/declaration/struct.rs | 23 +- .../src/language/ty/declaration/trait.rs | 26 +-- .../src/language/ty/declaration/trait_type.rs | 15 +- .../src/language/ty/declaration/type_alias.rs | 13 +- .../src/language/ty/declaration/variable.rs | 9 +- sway-core/src/language/ty/expression/asm.rs | 7 +- .../src/language/ty/expression/contract.rs | 3 +- .../src/language/ty/expression/expression.rs | 21 +- .../ty/expression/expression_variant.rs | 21 +- .../ty/expression/intrinsic_function.rs | 12 +- .../language/ty/expression/reassignment.rs | 21 +- .../src/language/ty/expression/scrutinee.rs | 10 +- .../src/language/ty/expression/storage.rs | 12 +- .../ty/expression/struct_exp_field.rs | 11 +- .../ty/side_effect/include_statement.rs | 4 +- .../language/ty/side_effect/side_effect.rs | 5 +- .../language/ty/side_effect/use_statement.rs | 3 +- .../src/language/ty/variable_mutability.rs | 3 +- sway-core/src/language/visibility.rs | 4 +- sway-core/src/transform/attribute.rs | 12 +- .../src/type_system/ast_elements/binding.rs | 12 +- .../ast_elements/trait_constraint.rs | 25 +- .../type_system/ast_elements/type_argument.rs | 3 +- .../ast_elements/type_parameter.rs | 15 +- sway-core/src/type_system/id.rs | 3 +- sway-core/src/type_system/info.rs | 14 +- sway-error/src/handler.rs | 3 +- sway-parse/src/attribute.rs | 221 ++++++++++++++---- sway-parse/src/module.rs | 65 +++++- sway-parse/src/path.rs | 54 +++-- sway-parse/tests/noop_script.rs | 65 +++++- sway-types/Cargo.toml | 2 +- sway-types/src/ident.rs | 18 +- sway-types/src/span.rs | 29 +-- sway-types/src/u256.rs | 6 +- 61 files changed, 699 insertions(+), 475 deletions(-) diff --git a/sway-ast/src/intrinsics.rs b/sway-ast/src/intrinsics.rs index 30dea17436d..d14c4e1b85a 100644 --- a/sway-ast/src/intrinsics.rs +++ b/sway-ast/src/intrinsics.rs @@ -1,6 +1,7 @@ +use serde::{Deserialize, Serialize}; use std::fmt; -#[derive(Eq, PartialEq, Debug, Clone, Hash)] +#[derive(Eq, PartialEq, Debug, Clone, Hash, Serialize, Deserialize)] pub enum Intrinsic { IsReferenceType, SizeOfType, diff --git a/sway-ast/src/literal.rs b/sway-ast/src/literal.rs index 1cede566e18..0b175235506 100644 --- a/sway-ast/src/literal.rs +++ b/sway-ast/src/literal.rs @@ -1,25 +1,25 @@ use crate::priv_prelude::*; -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub struct LitString { pub span: Span, pub parsed: String, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub struct LitChar { pub span: Span, pub parsed: char, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub struct LitInt { pub span: Span, pub parsed: BigUint, pub ty_opt: Option<(LitIntType, Span)>, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub enum LitIntType { U8, U16, @@ -32,13 +32,13 @@ pub enum LitIntType { I64, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub struct LitBool { pub span: Span, pub kind: LitBoolType, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub enum LitBoolType { True, False, @@ -53,7 +53,7 @@ impl From for bool { } } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub enum Literal { String(LitString), Char(LitChar), diff --git a/sway-ast/src/priv_prelude.rs b/sway-ast/src/priv_prelude.rs index b799d69f37d..9da93d80994 100644 --- a/sway-ast/src/priv_prelude.rs +++ b/sway-ast/src/priv_prelude.rs @@ -35,7 +35,7 @@ pub use { }, extension_trait::extension_trait, num_bigint::BigUint, - serde::Serialize, + serde::{Deserialize, Serialize}, sway_types::{ ast::{Delimiter, PunctKind}, Ident, Span, Spanned, diff --git a/sway-core/Cargo.toml b/sway-core/Cargo.toml index 5e2e5d54536..71ca263d962 100644 --- a/sway-core/Cargo.toml +++ b/sway-core/Cargo.toml @@ -23,7 +23,7 @@ graph-cycles.workspace = true hashbrown.workspace = true hex = { workspace = true, optional = true } im.workspace = true -indexmap.workspace = true +indexmap = { workspace = true, features = ["serde"] } itertools.workspace = true lazy_static.workspace = true object = { workspace = true, features = ["write"] } diff --git a/sway-core/src/decl_engine/id.rs b/sway-core/src/decl_engine/id.rs index 8878b9aaa79..597b716f1c1 100644 --- a/sway-core/src/decl_engine/id.rs +++ b/sway-core/src/decl_engine/id.rs @@ -1,20 +1,20 @@ -use std::collections::hash_map::DefaultHasher; -use std::hash::Hasher; -use std::marker::PhantomData; -use std::{fmt, hash::Hash}; - -use sway_types::{Named, Spanned}; - -use crate::language::ty::{TyDeclParsedType, TyTraitType}; use crate::{ decl_engine::*, engine_threading::*, language::ty::{ - TyEnumDecl, TyFunctionDecl, TyImplSelfOrTrait, TyStructDecl, TyTraitDecl, TyTraitFn, - TyTypeAliasDecl, + TyDeclParsedType, TyEnumDecl, TyFunctionDecl, TyImplSelfOrTrait, TyStructDecl, TyTraitDecl, + TyTraitFn, TyTraitType, TyTypeAliasDecl, }, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::{ + collections::hash_map::DefaultHasher, + fmt, + hash::{Hash, Hasher}, + marker::PhantomData, +}; +use sway_types::{Named, Spanned}; pub type DeclIdIndexType = usize; @@ -27,7 +27,7 @@ impl fmt::Debug for DeclId { } } -#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize)] pub struct DeclUniqueId(pub(crate) u64); impl DeclId { @@ -258,3 +258,22 @@ where } } } + +impl Serialize for DeclId { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.0.serialize(serializer) + } +} + +impl<'de, T> Deserialize<'de> for DeclId { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let id = DeclIdIndexType::deserialize(deserializer)?; + Ok(DeclId::new(id)) + } +} diff --git a/sway-core/src/decl_engine/interface_decl_id.rs b/sway-core/src/decl_engine/interface_decl_id.rs index 2306622a94a..cba36cfd429 100644 --- a/sway-core/src/decl_engine/interface_decl_id.rs +++ b/sway-core/src/decl_engine/interface_decl_id.rs @@ -1,3 +1,4 @@ +use super::{parsed_engine::ParsedDeclEngineGet, parsed_id::ParsedDeclId}; use crate::{ decl_engine::*, engine_threading::{EqWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext}, @@ -6,8 +7,7 @@ use crate::{ ty, }, }; - -use super::{parsed_engine::ParsedDeclEngineGet, parsed_id::ParsedDeclId}; +use serde::{Deserialize, Serialize}; #[derive(Debug, Eq, PartialEq, Hash, Clone)] pub enum ParsedInterfaceDeclId { @@ -43,7 +43,7 @@ impl From> for ParsedInterfaceDeclId { } } -#[derive(Debug, Eq, PartialEq, Hash, Clone)] +#[derive(Debug, Eq, PartialEq, Hash, Clone, Serialize, Deserialize)] pub enum InterfaceDeclId { Abi(DeclId), Trait(DeclId), diff --git a/sway-core/src/decl_engine/parsed_id.rs b/sway-core/src/decl_engine/parsed_id.rs index 3a97459aa75..1a513a6d5be 100644 --- a/sway-core/src/decl_engine/parsed_id.rs +++ b/sway-core/src/decl_engine/parsed_id.rs @@ -1,16 +1,20 @@ -use std::hash::{DefaultHasher, Hasher}; -use std::marker::PhantomData; -use std::{fmt, hash::Hash}; - -use sway_types::{Named, Spanned}; - -use crate::engine_threading::{ - EqWithEngines, HashWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext, +use super::{ + parsed_engine::{ParsedDeclEngine, ParsedDeclEngineGet, ParsedDeclEngineIndex}, + DeclUniqueId, }; -use crate::Engines; - -use super::parsed_engine::{ParsedDeclEngine, ParsedDeclEngineGet, ParsedDeclEngineIndex}; -use super::DeclUniqueId; +use crate::{ + engine_threading::{ + EqWithEngines, HashWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext, + }, + Engines, +}; +use serde::{Deserialize, Serialize}; +use std::{ + hash::{DefaultHasher, Hasher}, + marker::PhantomData, + {fmt, hash::Hash}, +}; +use sway_types::{Named, Spanned}; pub type ParsedDeclIdIndexType = usize; @@ -91,6 +95,25 @@ impl Ord for ParsedDeclId { } } +impl Serialize for ParsedDeclId { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.0.serialize(serializer) + } +} + +impl<'de, T> Deserialize<'de> for ParsedDeclId { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let id = usize::deserialize(deserializer)?; + Ok(ParsedDeclId::new(id)) + } +} + impl ParsedDeclId { pub(crate) fn new(id: usize) -> Self { ParsedDeclId(id, PhantomData) diff --git a/sway-core/src/decl_engine/ref.rs b/sway-core/src/decl_engine/ref.rs index 663fd563a60..4fb8f1bb87f 100644 --- a/sway-core/src/decl_engine/ref.rs +++ b/sway-core/src/decl_engine/ref.rs @@ -20,11 +20,6 @@ //! `fn my_function() { .. }`, and to use [DeclRef] for cases like function //! application `my_function()`. -use std::hash::{Hash, Hasher}; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ decl_engine::*, engine_threading::*, @@ -35,6 +30,10 @@ use crate::{ semantic_analysis::TypeCheckContext, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Named, Span, Spanned}; pub type DeclRefFunction = DeclRef>; pub type DeclRefTrait = DeclRef>; @@ -53,7 +52,7 @@ pub type DeclRefMixedInterface = DeclRef; /// Represents the use of / syntactic reference to a declaration. A /// smart-wrapper around a [DeclId], containing additional information about a /// declaration. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct DeclRef { /// The name of the declaration. // NOTE: In the case of storage, the name is "storage". diff --git a/sway-core/src/language/asm.rs b/sway-core/src/language/asm.rs index c8fcbb429a5..409e343eef6 100644 --- a/sway-core/src/language/asm.rs +++ b/sway-core/src/language/asm.rs @@ -1,8 +1,8 @@ +use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; - use sway_types::{BaseIdent, Ident, Span}; -#[derive(Debug, Clone, Eq)] +#[derive(Debug, Clone, Eq, Serialize, Deserialize)] pub struct AsmOp { pub(crate) op_name: Ident, pub(crate) op_args: Vec, @@ -43,7 +43,7 @@ impl PartialEq for AsmOp { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct AsmRegister { pub(crate) name: String, } diff --git a/sway-core/src/language/call_path.rs b/sway-core/src/language/call_path.rs index 8036d3ecab8..4ef90706af1 100644 --- a/sway-core/src/language/call_path.rs +++ b/sway-core/src/language/call_path.rs @@ -1,27 +1,25 @@ -use std::{ - cmp::Ordering, - fmt, - hash::{Hash, Hasher}, - sync::Arc, -}; - use crate::{ engine_threading::{ DebugWithEngines, DisplayWithEngines, EqWithEngines, HashWithEngines, OrdWithEngines, OrdWithEnginesContext, PartialEqWithEngines, PartialEqWithEnginesContext, }, + parsed::QualifiedPathType, Engines, Ident, Namespace, }; - +use serde::{Deserialize, Serialize}; +use std::{ + cmp::Ordering, + fmt, + hash::{Hash, Hasher}, + sync::Arc, +}; use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, }; use sway_types::{span::Span, Spanned}; -use super::parsed::QualifiedPathType; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct CallPathTree { pub qualified_call_path: QualifiedCallPath, pub children: Vec, @@ -75,7 +73,7 @@ impl OrdWithEngines for CallPathTree { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct QualifiedCallPath { pub call_path: CallPath, @@ -179,7 +177,7 @@ impl DebugWithEngines for QualifiedCallPath { /// In the expression `a::b::c()`, `a` and `b` are the prefixes and `c` is the suffix. /// `c` can be any type `T`, but in practice `c` is either an `Ident` or a `TypeInfo`. -#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize)] pub struct CallPath { pub prefixes: Vec, pub suffix: T, diff --git a/sway-core/src/language/lazy_op.rs b/sway-core/src/language/lazy_op.rs index 73e3daae256..abcb6149d26 100644 --- a/sway-core/src/language/lazy_op.rs +++ b/sway-core/src/language/lazy_op.rs @@ -1,4 +1,6 @@ -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum LazyOp { And, Or, diff --git a/sway-core/src/language/literal.rs b/sway-core/src/language/literal.rs index afedaad12d0..df0bc8735fb 100644 --- a/sway-core/src/language/literal.rs +++ b/sway-core/src/language/literal.rs @@ -1,15 +1,14 @@ use crate::{type_system::*, Engines}; - -use sway_error::error::CompileError; -use sway_types::{integer_bits::IntegerBits, span, u256::U256}; - +use serde::{Deserialize, Serialize}; use std::{ fmt, hash::{Hash, Hasher}, num::{IntErrorKind, ParseIntError}, }; +use sway_error::error::CompileError; +use sway_types::{integer_bits::IntegerBits, span, u256::U256}; -#[derive(Debug, Clone, Eq)] +#[derive(Debug, Clone, Eq, Serialize, Deserialize)] pub enum Literal { U8(u8), U16(u16), diff --git a/sway-core/src/language/parsed/declaration/trait.rs b/sway-core/src/language/parsed/declaration/trait.rs index 12e76e554c6..89bff7b4e94 100644 --- a/sway-core/src/language/parsed/declaration/trait.rs +++ b/sway-core/src/language/parsed/declaration/trait.rs @@ -1,7 +1,4 @@ -use std::hash::{Hash, Hasher}; - use super::{ConstantDeclaration, FunctionDeclaration, FunctionParameter}; - use crate::{ decl_engine::{parsed_id::ParsedDeclId, DeclRefTrait}, engine_threading::*, @@ -9,16 +6,18 @@ use crate::{ transform, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; use sway_error::handler::ErrorEmitted; use sway_types::{ident::Ident, span::Span, Named, Spanned}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum TraitItem { TraitFn(ParsedDeclId), Constant(ParsedDeclId), Type(ParsedDeclId), // to handle parser recovery: Error represents an incomplete trait item - Error(Box<[Span]>, ErrorEmitted), + Error(Box<[Span]>, #[serde(skip)] ErrorEmitted), } impl EqWithEngines for TraitItem {} @@ -75,7 +74,7 @@ impl Spanned for TraitDeclaration { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Supertrait { pub name: CallPath, pub decl_ref: Option, diff --git a/sway-core/src/language/parsed/expression/mod.rs b/sway-core/src/language/parsed/expression/mod.rs index 7e03c3bf43e..d6f6f2df54b 100644 --- a/sway-core/src/language/parsed/expression/mod.rs +++ b/sway-core/src/language/parsed/expression/mod.rs @@ -1,5 +1,3 @@ -use std::{cmp::Ordering, fmt, hash::Hasher}; - use crate::{ decl_engine::parsed_id::ParsedDeclId, engine_threading::{ @@ -10,6 +8,8 @@ use crate::{ type_system::TypeBinding, Engines, TypeArgument, TypeId, }; +use serde::{Deserialize, Serialize}; +use std::{cmp::Ordering, fmt, hash::Hasher}; use sway_error::handler::ErrorEmitted; use sway_types::{ident::Ident, Span, Spanned}; @@ -198,7 +198,7 @@ impl Spanned for AmbiguousSuffix { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct QualifiedPathType { pub ty: TypeArgument, pub as_trait: TypeId, diff --git a/sway-core/src/language/parsed/use_statement.rs b/sway-core/src/language/parsed/use_statement.rs index ceda688d75f..106fa21e04a 100644 --- a/sway-core/src/language/parsed/use_statement.rs +++ b/sway-core/src/language/parsed/use_statement.rs @@ -1,7 +1,8 @@ use crate::{language::Visibility, parsed::Span}; +use serde::{Deserialize, Serialize}; use sway_types::ident::Ident; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum ImportType { Star, SelfImport(Span), diff --git a/sway-core/src/language/purity.rs b/sway-core/src/language/purity.rs index 4b498b2fcdd..46961a8d0df 100644 --- a/sway-core/src/language/purity.rs +++ b/sway-core/src/language/purity.rs @@ -1,7 +1,9 @@ +use serde::{Deserialize, Serialize}; + /// The purity of a function is related to its access of contract storage. If a function accesses /// or could potentially access contract storage, it is [Purity::Impure]. If a function does not utilize any /// any accesses (reads _or_ writes) of storage, then it is [Purity::Pure]. -#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, Default)] +#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] pub enum Purity { #[default] Pure, diff --git a/sway-core/src/language/ty/ast_node.rs b/sway-core/src/language/ty/ast_node.rs index 59d9e942004..34dcdf95572 100644 --- a/sway-core/src/language/ty/ast_node.rs +++ b/sway-core/src/language/ty/ast_node.rs @@ -1,11 +1,3 @@ -use std::{ - fmt::{self, Debug}, - hash::{Hash, Hasher}, -}; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Span}; - use crate::{ decl_engine::*, engine_threading::*, @@ -18,12 +10,19 @@ use crate::{ type_system::*, types::*, }; +use serde::{Deserialize, Serialize}; +use std::{ + fmt::{self, Debug}, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Span}; pub trait GetDeclIdent { fn get_decl_ident(&self, engines: &Engines) -> Option; } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyAstNode { pub content: TyAstNodeContent, pub span: Span, @@ -353,13 +352,13 @@ impl TyAstNode { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyAstNodeContent { Declaration(TyDecl), Expression(TyExpression), // a no-op node used for something that just issues a side effect, like an import statement. SideEffect(TySideEffect), - Error(Box<[Span]>, ErrorEmitted), + Error(Box<[Span]>, #[serde(skip)] ErrorEmitted), } impl EqWithEngines for TyAstNodeContent {} diff --git a/sway-core/src/language/ty/code_block.rs b/sway-core/src/language/ty/code_block.rs index 6ae9b0d0dea..77a841ff4bc 100644 --- a/sway-core/src/language/ty/code_block.rs +++ b/sway-core/src/language/ty/code_block.rs @@ -1,14 +1,13 @@ -use std::hash::Hasher; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::Span; - use crate::{ decl_engine::*, engine_threading::*, language::ty::*, semantic_analysis::TypeCheckContext, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::hash::Hasher; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::Span; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyCodeBlock { pub contents: Vec, pub(crate) whole_block_span: Span, diff --git a/sway-core/src/language/ty/declaration/abi.rs b/sway-core/src/language/ty/declaration/abi.rs index 7dae1ef3271..4d3371394ed 100644 --- a/sway-core/src/language/ty/declaration/abi.rs +++ b/sway-core/src/language/ty/declaration/abi.rs @@ -1,18 +1,17 @@ +use super::{TyDeclParsedType, TyTraitInterfaceItem, TyTraitItem}; use crate::{ engine_threading::*, language::parsed::{self, AbiDeclaration}, transform, type_system::*, }; +use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; - use sway_types::{Ident, Named, Span, Spanned}; -use super::{TyDeclParsedType, TyTraitInterfaceItem, TyTraitItem}; - /// A [TyAbiDecl] contains the type-checked version of the parse tree's /// `AbiDeclaration`. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyAbiDecl { /// The name of the abi trait (also known as a "contract trait") pub name: Ident, diff --git a/sway-core/src/language/ty/declaration/configurable.rs b/sway-core/src/language/ty/declaration/configurable.rs index da7349fc91b..3de69ed1425 100644 --- a/sway-core/src/language/ty/declaration/configurable.rs +++ b/sway-core/src/language/ty/declaration/configurable.rs @@ -1,11 +1,3 @@ -use std::{ - fmt, - hash::{Hash, Hasher}, -}; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ decl_engine::{DeclId, DeclMapping, DeclRef, ReplaceDecls}, engine_threading::*, @@ -15,8 +7,15 @@ use crate::{ transform, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::{ + fmt, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Named, Span, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyConfigurableDecl { pub call_path: CallPath, pub value: Option, diff --git a/sway-core/src/language/ty/declaration/constant.rs b/sway-core/src/language/ty/declaration/constant.rs index c8acda6b5cf..35b675e6ace 100644 --- a/sway-core/src/language/ty/declaration/constant.rs +++ b/sway-core/src/language/ty/declaration/constant.rs @@ -1,11 +1,3 @@ -use std::{ - fmt, - hash::{Hash, Hasher}, -}; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ decl_engine::{DeclMapping, ReplaceDecls}, engine_threading::*, @@ -15,8 +7,15 @@ use crate::{ transform, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::{ + fmt, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Named, Span, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyConstantDecl { pub call_path: CallPath, pub value: Option, diff --git a/sway-core/src/language/ty/declaration/declaration.rs b/sway-core/src/language/ty/declaration/declaration.rs index 3c5b6481d09..5a9ba831149 100644 --- a/sway-core/src/language/ty/declaration/declaration.rs +++ b/sway-core/src/language/ty/declaration/declaration.rs @@ -1,3 +1,11 @@ +use crate::{ + decl_engine::*, + engine_threading::*, + language::{parsed::Declaration, ty::*, Visibility}, + type_system::*, + types::*, +}; +use serde::{Deserialize, Serialize}; use std::{ fmt, hash::{Hash, Hasher}, @@ -9,15 +17,7 @@ use sway_error::{ }; use sway_types::{Ident, Named, Span, Spanned}; -use crate::{ - decl_engine::*, - engine_threading::*, - language::{parsed::Declaration, ty::*, Visibility}, - type_system::*, - types::*, -}; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyDecl { VariableDecl(Box), ConstantDecl(ConstantDecl), @@ -33,7 +33,7 @@ pub enum TyDecl { // If type parameters are defined for a function, they are put in the namespace just for // the body of that function. GenericTypeForFunctionScope(GenericTypeForFunctionScope), - ErrorRecovery(Span, ErrorEmitted), + ErrorRecovery(Span, #[serde(skip)] ErrorEmitted), StorageDecl(StorageDecl), TypeAliasDecl(TypeAliasDecl), } @@ -46,70 +46,70 @@ pub trait TyDeclParsedType { type ParsedType; } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConstantDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigurableDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TraitTypeDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct FunctionDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TraitDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct StructDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct EnumDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct EnumVariantDecl { pub enum_ref: DeclRefEnum, pub variant_name: Ident, pub variant_decl_span: Span, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct ImplSelfOrTrait { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct AbiDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct GenericTypeForFunctionScope { pub name: Ident, pub type_id: TypeId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct StorageDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TypeAliasDecl { pub decl_id: DeclId, } diff --git a/sway-core/src/language/ty/declaration/enum.rs b/sway-core/src/language/ty/declaration/enum.rs index 2ce5e3eae46..126fb4549a5 100644 --- a/sway-core/src/language/ty/declaration/enum.rs +++ b/sway-core/src/language/ty/declaration/enum.rs @@ -1,26 +1,23 @@ +use crate::{ + engine_threading::*, + has_changes, + language::{parsed::EnumDeclaration, ty::TyDeclParsedType, CallPath, Visibility}, + transform, + type_system::*, +}; +use monomorphization::MonomorphizeHelper; +use serde::{Deserialize, Serialize}; use std::{ cmp::Ordering, hash::{Hash, Hasher}, }; - -use monomorphization::MonomorphizeHelper; use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, }; use sway_types::{Ident, Named, Span, Spanned}; -use crate::{ - engine_threading::*, - has_changes, - language::{parsed::EnumDeclaration, CallPath, Visibility}, - transform, - type_system::*, -}; - -use super::TyDeclParsedType; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyEnumDecl { pub call_path: CallPath, pub type_parameters: Vec, @@ -133,7 +130,7 @@ impl Spanned for TyEnumVariant { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TyEnumVariant { pub name: Ident, pub type_argument: TypeArgument, diff --git a/sway-core/src/language/ty/declaration/function.rs b/sway-core/src/language/ty/declaration/function.rs index 8bb26f1f598..6849ccaa7db 100644 --- a/sway-core/src/language/ty/declaration/function.rs +++ b/sway-core/src/language/ty/declaration/function.rs @@ -1,37 +1,31 @@ -use std::{ - fmt, - hash::{Hash, Hasher}, -}; - -use monomorphization::MonomorphizeHelper; -use sha2::{Digest, Sha256}; -use sway_error::handler::{ErrorEmitted, Handler}; - use crate::{ + decl_engine::*, + engine_threading::*, has_changes, + language::{parsed, ty::*, Inline, Purity, Visibility}, language::{ parsed::{FunctionDeclaration, FunctionDeclarationKind}, CallPath, }, - transform::AttributeKind, -}; - -use crate::{ - decl_engine::*, - engine_threading::*, - language::{parsed, ty::*, Inline, Purity, Visibility}, semantic_analysis::TypeCheckContext, - transform, + transform::{self, AttributeKind}, type_system::*, types::*, }; - +use monomorphization::MonomorphizeHelper; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use std::{ + fmt, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{ constants::{INLINE_ALWAYS_NAME, INLINE_NEVER_NAME}, Ident, Named, Span, Spanned, }; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyFunctionDeclKind { Default, Entry, @@ -39,7 +33,7 @@ pub enum TyFunctionDeclKind { Test, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyFunctionDecl { pub name: Ident, pub body: TyCodeBlock, @@ -489,7 +483,7 @@ impl TyFunctionDecl { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TyFunctionParameter { pub name: Ident, pub is_reference: bool, diff --git a/sway-core/src/language/ty/declaration/impl_trait.rs b/sway-core/src/language/ty/declaration/impl_trait.rs index 0c2d25aa5fd..6125eeb9569 100644 --- a/sway-core/src/language/ty/declaration/impl_trait.rs +++ b/sway-core/src/language/ty/declaration/impl_trait.rs @@ -1,7 +1,4 @@ -use std::hash::{Hash, Hasher}; - -use sway_types::{Ident, Named, Span, Spanned}; - +use super::{TyDeclParsedType, TyTraitItem}; use crate::{ decl_engine::DeclRefMixedInterface, engine_threading::*, @@ -9,13 +6,14 @@ use crate::{ language::{parsed::ImplSelfOrTrait, CallPath}, type_system::*, }; - -use super::{TyDeclParsedType, TyTraitItem}; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; +use sway_types::{Ident, Named, Span, Spanned}; pub type TyImplItem = TyTraitItem; // impl Trait for Type -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyImplSelfOrTrait { pub impl_type_parameters: Vec, pub trait_name: CallPath, diff --git a/sway-core/src/language/ty/declaration/storage.rs b/sway-core/src/language/ty/declaration/storage.rs index abc5a67b20c..1036159a826 100644 --- a/sway-core/src/language/ty/declaration/storage.rs +++ b/sway-core/src/language/ty/declaration/storage.rs @@ -1,11 +1,3 @@ -use std::hash::{Hash, Hasher}; - -use sway_error::{ - error::{CompileError, StructFieldUsageContext}, - handler::{ErrorEmitted, Handler}, -}; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ engine_threading::*, ir_generation::storage::get_storage_key_string, @@ -15,8 +7,15 @@ use crate::{ type_system::*, Namespace, }; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; +use sway_error::{ + error::{CompileError, StructFieldUsageContext}, + handler::{ErrorEmitted, Handler}, +}; +use sway_types::{Ident, Named, Span, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyStorageDecl { pub fields: Vec, pub span: Span, @@ -243,7 +242,7 @@ impl Spanned for TyStorageField { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyStorageField { pub name: Ident, pub namespace_names: Vec, diff --git a/sway-core/src/language/ty/declaration/struct.rs b/sway-core/src/language/ty/declaration/struct.rs index c4dc7e3e219..e64281b1ea9 100644 --- a/sway-core/src/language/ty/declaration/struct.rs +++ b/sway-core/src/language/ty/declaration/struct.rs @@ -1,24 +1,21 @@ -use std::{ - cmp::Ordering, - hash::{Hash, Hasher}, -}; - -use monomorphization::MonomorphizeHelper; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ engine_threading::*, error::module_can_be_changed, has_changes, - language::{parsed::StructDeclaration, CallPath, Visibility}, + language::{parsed::StructDeclaration, ty::TyDeclParsedType, CallPath, Visibility}, transform, type_system::*, Namespace, }; +use monomorphization::MonomorphizeHelper; +use serde::{Deserialize, Serialize}; +use std::{ + cmp::Ordering, + hash::{Hash, Hasher}, +}; +use sway_types::{Ident, Named, Span, Spanned}; -use super::TyDeclParsedType; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyStructDecl { pub call_path: CallPath, pub fields: Vec, @@ -182,7 +179,7 @@ impl From for (bool, bool) { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TyStructField { pub visibility: Visibility, pub name: Ident, diff --git a/sway-core/src/language/ty/declaration/trait.rs b/sway-core/src/language/ty/declaration/trait.rs index f0c7ee24ff3..14970814fe3 100644 --- a/sway-core/src/language/ty/declaration/trait.rs +++ b/sway-core/src/language/ty/declaration/trait.rs @@ -1,12 +1,3 @@ -use std::{ - fmt, - hash::{Hash, Hasher}, -}; - -use monomorphization::MonomorphizeHelper; -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ decl_engine::{ DeclEngineReplace, DeclRefConstant, DeclRefFunction, DeclRefTraitFn, DeclRefTraitType, @@ -16,6 +7,7 @@ use crate::{ has_changes, language::{ parsed::{self, TraitDeclaration}, + ty::{TyDecl, TyDeclParsedType}, CallPath, Visibility, }, semantic_analysis::{ @@ -25,10 +17,16 @@ use crate::{ transform, type_system::*, }; +use monomorphization::MonomorphizeHelper; +use serde::{Deserialize, Serialize}; +use std::{ + fmt, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Named, Span, Spanned}; -use super::{TyDecl, TyDeclParsedType}; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyTraitDecl { pub name: Ident, pub type_parameters: Vec, @@ -46,7 +44,7 @@ impl TyDeclParsedType for TyTraitDecl { type ParsedType = TraitDeclaration; } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyTraitInterfaceItem { TraitFn(DeclRefTraitFn), Constant(DeclRefConstant), @@ -82,7 +80,7 @@ impl DebugWithEngines for TyTraitInterfaceItem { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyTraitItem { Fn(DeclRefFunction), Constant(DeclRefConstant), diff --git a/sway-core/src/language/ty/declaration/trait_type.rs b/sway-core/src/language/ty/declaration/trait_type.rs index 24925afa457..9c9cee3e5eb 100644 --- a/sway-core/src/language/ty/declaration/trait_type.rs +++ b/sway-core/src/language/ty/declaration/trait_type.rs @@ -1,18 +1,15 @@ +use crate::{ + engine_threading::*, has_changes, language::parsed::TraitTypeDeclaration, + language::ty::TyDeclParsedType, transform, type_system::*, +}; +use serde::{Deserialize, Serialize}; use std::{ fmt, hash::{Hash, Hasher}, }; - use sway_types::{Ident, Named, Span, Spanned}; -use crate::{ - engine_threading::*, has_changes, language::parsed::TraitTypeDeclaration, transform, - type_system::*, -}; - -use super::TyDeclParsedType; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyTraitType { pub name: Ident, pub attributes: transform::AttributesMap, diff --git a/sway-core/src/language/ty/declaration/type_alias.rs b/sway-core/src/language/ty/declaration/type_alias.rs index cb33c0d27bd..9c41fae8f50 100644 --- a/sway-core/src/language/ty/declaration/type_alias.rs +++ b/sway-core/src/language/ty/declaration/type_alias.rs @@ -1,17 +1,14 @@ -use std::hash::{Hash, Hasher}; - -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ engine_threading::*, - language::{parsed::TypeAliasDeclaration, CallPath, Visibility}, + language::{parsed::TypeAliasDeclaration, ty::TyDeclParsedType, CallPath, Visibility}, transform, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; +use sway_types::{Ident, Named, Span, Spanned}; -use super::TyDeclParsedType; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyTypeAliasDecl { pub name: Ident, pub call_path: CallPath, diff --git a/sway-core/src/language/ty/declaration/variable.rs b/sway-core/src/language/ty/declaration/variable.rs index d7eb80ad7c6..5337651b8e5 100644 --- a/sway-core/src/language/ty/declaration/variable.rs +++ b/sway-core/src/language/ty/declaration/variable.rs @@ -1,14 +1,13 @@ -use std::hash::{Hash, Hasher}; - -use sway_types::{Ident, Named, Spanned}; - use crate::{ engine_threading::*, language::{parsed::VariableDeclaration, ty::*}, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; +use sway_types::{Ident, Named, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyVariableDecl { pub name: Ident, pub body: TyExpression, diff --git a/sway-core/src/language/ty/expression/asm.rs b/sway-core/src/language/ty/expression/asm.rs index 04944125258..6e4ad95af3c 100644 --- a/sway-core/src/language/ty/expression/asm.rs +++ b/sway-core/src/language/ty/expression/asm.rs @@ -1,10 +1,9 @@ +use crate::{engine_threading::*, language::ty::*, type_system::*}; +use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; - use sway_types::Ident; -use crate::{engine_threading::*, language::ty::*, type_system::*}; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyAsmRegisterDeclaration { pub initializer: Option, pub(crate) name: Ident, diff --git a/sway-core/src/language/ty/expression/contract.rs b/sway-core/src/language/ty/expression/contract.rs index 2bdec40421e..926aba9923c 100644 --- a/sway-core/src/language/ty/expression/contract.rs +++ b/sway-core/src/language/ty/expression/contract.rs @@ -1,6 +1,7 @@ use crate::language::ty::*; +use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct ContractCallParams { // This is none in encoding V1 pub(crate) func_selector: Option<[u8; 4]>, diff --git a/sway-core/src/language/ty/expression/expression.rs b/sway-core/src/language/ty/expression/expression.rs index a0c70559b1d..4f369d3c269 100644 --- a/sway-core/src/language/ty/expression/expression.rs +++ b/sway-core/src/language/ty/expression/expression.rs @@ -1,13 +1,3 @@ -use std::{fmt, hash::Hasher}; - -use sway_error::{ - error::CompileError, - handler::{ErrorEmitted, Handler}, - type_error::TypeError, - warning::{CompileWarning, Warning}, -}; -use sway_types::{Span, Spanned}; - use crate::{ decl_engine::*, engine_threading::*, @@ -21,8 +11,17 @@ use crate::{ type_system::*, types::*, }; +use serde::{Deserialize, Serialize}; +use std::{fmt, hash::Hasher}; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, + type_error::TypeError, + warning::{CompileWarning, Warning}, +}; +use sway_types::{Span, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyExpression { pub expression: TyExpressionVariant, pub return_type: TypeId, diff --git a/sway-core/src/language/ty/expression/expression_variant.rs b/sway-core/src/language/ty/expression/expression_variant.rs index 9908bb09f5b..ea221466273 100644 --- a/sway-core/src/language/ty/expression/expression_variant.rs +++ b/sway-core/src/language/ty/expression/expression_variant.rs @@ -1,13 +1,3 @@ -use std::{ - collections::VecDeque, - fmt::{self, Write}, - hash::{Hash, Hasher}, -}; - -use indexmap::IndexMap; -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ decl_engine::*, engine_threading::*, @@ -20,8 +10,17 @@ use crate::{ }, type_system::*, }; +use indexmap::IndexMap; +use serde::{Deserialize, Serialize}; +use std::{ + collections::VecDeque, + fmt::{self, Write}, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Named, Span, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyExpressionVariant { Literal(Literal), FunctionApplication { diff --git a/sway-core/src/language/ty/expression/intrinsic_function.rs b/sway-core/src/language/ty/expression/intrinsic_function.rs index 4fb4e72c3bc..d7646ecf64c 100644 --- a/sway-core/src/language/ty/expression/intrinsic_function.rs +++ b/sway-core/src/language/ty/expression/intrinsic_function.rs @@ -1,18 +1,18 @@ -use std::{ - fmt, - hash::{Hash, Hasher}, -}; - use crate::{ abi_generation::abi_str::AbiStrContext, engine_threading::*, has_changes, language::ty::*, type_system::*, types::*, }; use itertools::Itertools; +use serde::{Deserialize, Serialize}; +use std::{ + fmt, + hash::{Hash, Hasher}, +}; use sway_ast::Intrinsic; use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::Span; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TyIntrinsicFunctionKind { pub kind: Intrinsic, pub arguments: Vec, diff --git a/sway-core/src/language/ty/expression/reassignment.rs b/sway-core/src/language/ty/expression/reassignment.rs index 54a8e740c5c..698af692dda 100644 --- a/sway-core/src/language/ty/expression/reassignment.rs +++ b/sway-core/src/language/ty/expression/reassignment.rs @@ -1,11 +1,3 @@ -use std::{ - borrow::Cow, - hash::{Hash, Hasher}, -}; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Span, Spanned}; - use crate::{ decl_engine::*, engine_threading::*, @@ -17,14 +9,21 @@ use crate::{ }, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::{ + borrow::Cow, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Span, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyReassignment { pub lhs: TyReassignmentTarget, pub rhs: TyExpression, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyReassignmentTarget { /// An [TyExpression] representing a single variable or a path /// to a part of an aggregate. @@ -258,7 +257,7 @@ impl UpdateConstantExpression for TyReassignment { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum ProjectionKind { StructField { name: Ident, diff --git a/sway-core/src/language/ty/expression/scrutinee.rs b/sway-core/src/language/ty/expression/scrutinee.rs index 68c51af26eb..78fde994732 100644 --- a/sway-core/src/language/ty/expression/scrutinee.rs +++ b/sway-core/src/language/ty/expression/scrutinee.rs @@ -1,19 +1,19 @@ -use sway_types::{Ident, Span}; - use crate::{ decl_engine::{DeclRefEnum, DeclRefStruct}, language::{ty::*, *}, type_system::*, }; +use serde::{Deserialize, Serialize}; +use sway_types::{Ident, Span}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TyScrutinee { pub variant: TyScrutineeVariant, pub type_id: TypeId, pub span: Span, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum TyScrutineeVariant { Or(Vec), CatchAll, @@ -36,7 +36,7 @@ pub enum TyScrutineeVariant { Tuple(Vec), } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TyStructScrutineeField { pub field: Ident, pub scrutinee: Option, diff --git a/sway-core/src/language/ty/expression/storage.rs b/sway-core/src/language/ty/expression/storage.rs index 127d64fd20b..adaa6f28730 100644 --- a/sway-core/src/language/ty/expression/storage.rs +++ b/sway-core/src/language/ty/expression/storage.rs @@ -1,13 +1,11 @@ +use super::TyExpression; +use crate::{engine_threading::*, type_system::TypeId}; +use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; - use sway_types::{Ident, Span, Spanned}; -use crate::{engine_threading::*, type_system::TypeId}; - -use super::TyExpression; - /// Describes the full storage access including all the subfields -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyStorageAccess { pub fields: Vec, pub storage_field_names: Vec, @@ -64,7 +62,7 @@ impl TyStorageAccess { } /// Describes a single subfield access in the sequence when accessing a subfield within storage. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyStorageAccessDescriptor { pub name: Ident, pub type_id: TypeId, diff --git a/sway-core/src/language/ty/expression/struct_exp_field.rs b/sway-core/src/language/ty/expression/struct_exp_field.rs index 5f879640fb3..7262f38a901 100644 --- a/sway-core/src/language/ty/expression/struct_exp_field.rs +++ b/sway-core/src/language/ty/expression/struct_exp_field.rs @@ -1,8 +1,3 @@ -use std::hash::{Hash, Hasher}; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::Ident; - use crate::{ decl_engine::*, engine_threading::*, @@ -10,8 +5,12 @@ use crate::{ semantic_analysis::{TypeCheckContext, TypeCheckFinalization, TypeCheckFinalizationContext}, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::Ident; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyStructExpressionField { pub name: Ident, pub value: TyExpression, diff --git a/sway-core/src/language/ty/side_effect/include_statement.rs b/sway-core/src/language/ty/side_effect/include_statement.rs index 5d35f02b722..666e5b63a58 100644 --- a/sway-core/src/language/ty/side_effect/include_statement.rs +++ b/sway-core/src/language/ty/side_effect/include_statement.rs @@ -1,8 +1,8 @@ use crate::language::Visibility; - +use serde::{Deserialize, Serialize}; use sway_types::{ident::Ident, Span, Spanned}; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct TyIncludeStatement { pub span: Span, pub visibility: Visibility, diff --git a/sway-core/src/language/ty/side_effect/side_effect.rs b/sway-core/src/language/ty/side_effect/side_effect.rs index 41f2a5b945b..9e8e672c5fa 100644 --- a/sway-core/src/language/ty/side_effect/side_effect.rs +++ b/sway-core/src/language/ty/side_effect/side_effect.rs @@ -1,11 +1,12 @@ use super::{TyIncludeStatement, TyUseStatement}; +use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct TySideEffect { pub side_effect: TySideEffectVariant, } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum TySideEffectVariant { IncludeStatement(TyIncludeStatement), UseStatement(TyUseStatement), diff --git a/sway-core/src/language/ty/side_effect/use_statement.rs b/sway-core/src/language/ty/side_effect/use_statement.rs index 5d9c0cf1ca1..476a58907ef 100644 --- a/sway-core/src/language/ty/side_effect/use_statement.rs +++ b/sway-core/src/language/ty/side_effect/use_statement.rs @@ -1,7 +1,8 @@ use crate::language::parsed; +use serde::{Deserialize, Serialize}; use sway_types::{ident::Ident, Span, Spanned}; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct TyUseStatement { pub call_path: Vec, pub span: Span, diff --git a/sway-core/src/language/ty/variable_mutability.rs b/sway-core/src/language/ty/variable_mutability.rs index ba2532028b6..b1831af1279 100644 --- a/sway-core/src/language/ty/variable_mutability.rs +++ b/sway-core/src/language/ty/variable_mutability.rs @@ -1,6 +1,7 @@ use crate::language::Visibility; +use serde::{Deserialize, Serialize}; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] pub enum VariableMutability { // mutable Mutable, diff --git a/sway-core/src/language/visibility.rs b/sway-core/src/language/visibility.rs index a3838e06aff..e6b19912e7e 100644 --- a/sway-core/src/language/visibility.rs +++ b/sway-core/src/language/visibility.rs @@ -1,4 +1,6 @@ -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Visibility { Private, Public, diff --git a/sway-core/src/transform/attribute.rs b/sway-core/src/transform/attribute.rs index d29978205c8..d44538befa2 100644 --- a/sway-core/src/transform/attribute.rs +++ b/sway-core/src/transform/attribute.rs @@ -21,6 +21,8 @@ //! #[foo(bar, bar)] use indexmap::IndexMap; +use serde::{Deserialize, Serialize}; +use std::{hash::Hash, sync::Arc}; use sway_ast::Literal; use sway_types::{ constants::{ @@ -29,9 +31,7 @@ use sway_types::{ Ident, Span, Spanned, }; -use std::{hash::Hash, sync::Arc}; - -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct AttributeArg { pub name: Ident, pub value: Option, @@ -47,7 +47,7 @@ impl Spanned for AttributeArg { /// An attribute has a name (i.e "doc", "storage"), /// a vector of possible arguments and /// a span from its declaration. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct Attribute { pub name: Ident, pub args: Vec, @@ -55,7 +55,7 @@ pub struct Attribute { } /// Valid kinds of attributes supported by the compiler -#[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub enum AttributeKind { Doc, DocComment, @@ -104,7 +104,7 @@ impl AttributeKind { } /// Stores the attributes associated with the type. -#[derive(Default, Clone, Debug, Eq, PartialEq)] +#[derive(Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct AttributesMap(Arc>>); impl AttributesMap { diff --git a/sway-core/src/type_system/ast_elements/binding.rs b/sway-core/src/type_system/ast_elements/binding.rs index 3ea45397a51..96d91b24f74 100644 --- a/sway-core/src/type_system/ast_elements/binding.rs +++ b/sway-core/src/type_system/ast_elements/binding.rs @@ -1,7 +1,3 @@ -use sway_ast::Intrinsic; -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Span, Spanned}; - use crate::{ decl_engine::{ parsed_id::ParsedDeclId, DeclEngineGetParsedDeclId, DeclEngineInsert, DeclId, DeclRef, @@ -18,6 +14,10 @@ use crate::{ type_system::priv_prelude::*, EnforceTypeArguments, Ident, }; +use serde::{Deserialize, Serialize}; +use sway_ast::Intrinsic; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Span, Spanned}; /// A `TypeBinding` is the result of using turbofish to bind types to /// generic parameters. @@ -78,7 +78,7 @@ use crate::{ /// - `data4` has a type ascription and has type arguments in the `TypeBinding`, /// so, with the type from the value passed to `value`, all three are unified /// together -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TypeBinding { pub inner: T, pub type_arguments: TypeArgs, @@ -103,7 +103,7 @@ pub struct TypeBinding { /// ``` /// So we can have type parameters in the `Prefix` or `Regular` variant but not /// in both. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum TypeArgs { /// `Regular` variant indicates the type arguments are located after the suffix. Regular(Vec), diff --git a/sway-core/src/type_system/ast_elements/trait_constraint.rs b/sway-core/src/type_system/ast_elements/trait_constraint.rs index cfe0b41bcb1..f51fe79d691 100644 --- a/sway-core/src/type_system/ast_elements/trait_constraint.rs +++ b/sway-core/src/type_system/ast_elements/trait_constraint.rs @@ -1,15 +1,3 @@ -use std::{ - cmp::Ordering, - fmt, - hash::{Hash, Hasher}, -}; - -use sway_error::{ - error::CompileError, - handler::{ErrorEmitted, Handler}, -}; -use sway_types::Spanned; - use crate::{ engine_threading::*, language::{parsed::Supertrait, ty, CallPath}, @@ -21,8 +9,19 @@ use crate::{ types::{CollectTypesMetadata, CollectTypesMetadataContext, TypeMetadata}, EnforceTypeArguments, }; +use serde::{Deserialize, Serialize}; +use std::{ + cmp::Ordering, + fmt, + hash::{Hash, Hasher}, +}; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; +use sway_types::Spanned; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TraitConstraint { pub trait_name: CallPath, pub type_arguments: Vec, diff --git a/sway-core/src/type_system/ast_elements/type_argument.rs b/sway-core/src/type_system/ast_elements/type_argument.rs index bdddde93ad4..3ab7e5a0322 100644 --- a/sway-core/src/type_system/ast_elements/type_argument.rs +++ b/sway-core/src/type_system/ast_elements/type_argument.rs @@ -1,4 +1,5 @@ use crate::{engine_threading::*, language::CallPathTree, type_system::priv_prelude::*}; +use serde::{Deserialize, Serialize}; use std::{cmp::Ordering, fmt, hash::Hasher}; use sway_types::{Span, Spanned}; @@ -13,7 +14,7 @@ use sway_types::{Span, Spanned}; /// /// The annotations are ignored when calculating the [TypeArgument]'s hash /// (with engines) and equality (with engines). -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TypeArgument { /// The [TypeId] of the "referenced" [TypeInfo]. pub type_id: TypeId, diff --git a/sway-core/src/type_system/ast_elements/type_parameter.rs b/sway-core/src/type_system/ast_elements/type_parameter.rs index cdd656aaef0..7b6c8b48e5a 100644 --- a/sway-core/src/type_system/ast_elements/type_parameter.rs +++ b/sway-core/src/type_system/ast_elements/type_parameter.rs @@ -7,19 +7,18 @@ use crate::{ semantic_analysis::{GenericShadowingMode, TypeCheckContext}, type_system::priv_prelude::*, }; - -use sway_error::{ - error::CompileError, - handler::{ErrorEmitted, Handler}, -}; -use sway_types::{ident::Ident, span::Span, BaseIdent, Spanned}; - +use serde::{Deserialize, Serialize}; use std::{ cmp::Ordering, collections::BTreeMap, fmt, hash::{Hash, Hasher}, }; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; +use sway_types::{ident::Ident, span::Span, BaseIdent, Spanned}; /// [TypeParameter] describes a generic type parameter, including its /// monomorphized version. It holds the `name` of the parameter, its @@ -33,7 +32,7 @@ use std::{ /// /// The annotations are ignored when calculating the [TypeParameter]'s hash /// (with engines) and equality (with engines). -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TypeParameter { pub type_id: TypeId, /// Denotes the initial type represented by the [TypeParameter], before diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index 090ed6b370a..5e8f5bba90e 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -1,5 +1,6 @@ #![allow(clippy::mutable_key_type)] use indexmap::IndexMap; +use serde::{Deserialize, Serialize}; use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, @@ -34,7 +35,7 @@ pub enum TreatNumericAs { } /// A identifier to uniquely refer to our type terms -#[derive(PartialEq, Eq, Hash, Clone, Copy, Ord, PartialOrd, Debug)] +#[derive(PartialEq, Eq, Hash, Clone, Copy, Ord, PartialOrd, Debug, Deserialize, Serialize)] pub struct TypeId(usize); impl DisplayWithEngines for TypeId { diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index dc089c9c25f..e0304d62ed2 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -12,19 +12,19 @@ use crate::{ type_system::priv_prelude::*, Ident, }; -use sway_error::{ - error::{CompileError, InvalidImplementingForType}, - handler::{ErrorEmitted, Handler}, -}; -use sway_types::{integer_bits::IntegerBits, span::Span}; - +use serde::{Deserialize, Serialize}; use std::{ cmp::Ordering, fmt, hash::{Hash, Hasher}, }; +use sway_error::{ + error::{CompileError, InvalidImplementingForType}, + handler::{ErrorEmitted, Handler}, +}; +use sway_types::{integer_bits::IntegerBits, span::Span}; -#[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)] +#[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum AbiName { Deferred, Known(CallPath), diff --git a/sway-error/src/handler.rs b/sway-error/src/handler.rs index 24d2222da1b..ddb4d3b24f5 100644 --- a/sway-error/src/handler.rs +++ b/sway-error/src/handler.rs @@ -1,5 +1,4 @@ use crate::{error::CompileError, warning::CompileWarning}; - use core::cell::RefCell; /// A handler with which you can emit diagnostics. @@ -127,7 +126,7 @@ impl Handler { } /// Proof that an error was emitted through a `Handler`. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)] pub struct ErrorEmitted { _priv: (), } diff --git a/sway-parse/src/attribute.rs b/sway-parse/src/attribute.rs index 84a174f3bf2..4b3d545eb8c 100644 --- a/sway-parse/src/attribute.rs +++ b/sway-parse/src/attribute.rs @@ -188,67 +188,121 @@ mod tests { fn main() { () } - "#,), @r###" + "#,), @r#" Annotated( attribute_list: [ AttributeDecl( hash_kind: Outer(HashToken( - span: (82, 108), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 82, + end: 108, + source_id: None, + ), )), attribute: SquareBrackets( inner: Punctuated( value_separator_pairs: [], final_value_opt: Some(Attribute( - name: Ident( - to_string: "doc-comment", - span: (82, 108), + name: BaseIdent( + name_override_opt: Some("doc-comment"), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 82, + end: 108, + source_id: None, + ), + is_raw_ident: false, ), args: Some(Parens( inner: Punctuated( value_separator_pairs: [], final_value_opt: Some(AttributeArg( - name: Ident( - to_string: " This is a doc comment.", - span: (85, 108), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 85, + end: 108, + source_id: None, + ), + is_raw_ident: false, ), value: None, )), ), - span: (85, 108), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 85, + end: 108, + source_id: None, + ), )), )), ), - span: (82, 108), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 82, + end: 108, + source_id: None, + ), ), ), AttributeDecl( hash_kind: Outer(HashToken( - span: (121, 122), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 121, + end: 122, + source_id: None, + ), )), attribute: SquareBrackets( inner: Punctuated( value_separator_pairs: [], final_value_opt: Some(Attribute( - name: Ident( - to_string: "storage", - span: (123, 130), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 123, + end: 130, + source_id: None, + ), + is_raw_ident: false, ), args: Some(Parens( inner: Punctuated( value_separator_pairs: [], final_value_opt: Some(AttributeArg( - name: Ident( - to_string: "read", - span: (131, 135), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 131, + end: 135, + source_id: None, + ), + is_raw_ident: false, ), value: None, )), ), - span: (130, 136), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 130, + end: 136, + source_id: None, + ), )), )), ), - span: (122, 137), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 122, + end: 137, + source_id: None, + ), ), ), ], @@ -256,11 +310,22 @@ mod tests { fn_signature: FnSignature( visibility: None, fn_token: FnToken( - span: (150, 152), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 150, + end: 152, + source_id: None, + ), ), - name: Ident( - to_string: "main", - span: (153, 157), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 153, + end: 157, + source_id: None, + ), + is_raw_ident: false, ), generics: None, arguments: Parens( @@ -268,7 +333,12 @@ mod tests { value_separator_pairs: [], final_value_opt: None, )), - span: (157, 159), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 157, + end: 159, + source_id: None, + ), ), return_type_opt: None, where_clause_opt: None, @@ -278,63 +348,122 @@ mod tests { statements: [], final_expr_opt: Some(Tuple(Parens( inner: Nil, - span: (178, 180), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 178, + end: 180, + source_id: None, + ), ))), - span: (161, 193), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 161, + end: 193, + source_id: None, + ), + ), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 160, + end: 194, + source_id: None, ), - span: (160, 194), ), ), ) - "###); + "#); } #[test] fn parse_attribute() { assert_ron_snapshot!(parse::(r#" name(arg1, arg2 = "value", arg3) - "#,), @r###" + "#,), @r#" Attribute( - name: Ident( - to_string: "name", - span: (13, 17), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 13, + end: 17, + source_id: None, + ), + is_raw_ident: false, ), args: Some(Parens( inner: Punctuated( value_separator_pairs: [ (AttributeArg( - name: Ident( - to_string: "arg1", - span: (18, 22), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 18, + end: 22, + source_id: None, + ), + is_raw_ident: false, ), value: None, ), CommaToken( - span: (22, 23), + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 22, + end: 23, + source_id: None, + ), )), (AttributeArg( - name: Ident( - to_string: "arg2", - span: (24, 28), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 24, + end: 28, + source_id: None, + ), + is_raw_ident: false, ), value: Some(String(LitString( - span: (31, 38), + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 31, + end: 38, + source_id: None, + ), parsed: "value", ))), ), CommaToken( - span: (38, 39), + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 38, + end: 39, + source_id: None, + ), )), ], final_value_opt: Some(AttributeArg( - name: Ident( - to_string: "arg3", - span: (40, 44), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 40, + end: 44, + source_id: None, + ), + is_raw_ident: false, ), value: None, )), ), - span: (17, 45), + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 17, + end: 45, + source_id: None, + ), )), ) - "###); + "#); } } diff --git a/sway-parse/src/module.rs b/sway-parse/src/module.rs index 7936012e96a..05d97d82b42 100644 --- a/sway-parse/src/module.rs +++ b/sway-parse/src/module.rs @@ -87,17 +87,27 @@ mod tests { fn main() { () } - "#,), @r###" + "#,), @r#" Annotated( attribute_list: [], value: Module( kind: Script( script_token: ScriptToken( - span: (13, 19), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 13, + end: 19, + source_id: None, + ), ), ), semicolon_token: SemicolonToken( - span: (19, 20), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 19, + end: 20, + source_id: None, + ), ), items: [ Annotated( @@ -106,11 +116,22 @@ mod tests { fn_signature: FnSignature( visibility: None, fn_token: FnToken( - span: (42, 44), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 42, + end: 44, + source_id: None, + ), ), - name: Ident( - to_string: "main", - span: (45, 49), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 45, + end: 49, + source_id: None, + ), + is_raw_ident: false, ), generics: None, arguments: Parens( @@ -118,7 +139,12 @@ mod tests { value_separator_pairs: [], final_value_opt: None, )), - span: (49, 51), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 49, + end: 51, + source_id: None, + ), ), return_type_opt: None, where_clause_opt: None, @@ -128,17 +154,32 @@ mod tests { statements: [], final_expr_opt: Some(Tuple(Parens( inner: Nil, - span: (70, 72), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 70, + end: 72, + source_id: None, + ), ))), - span: (53, 85), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 53, + end: 85, + source_id: None, + ), + ), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 52, + end: 86, + source_id: None, ), - span: (52, 86), ), )), ), ], ), ) - "###); + "#); } } diff --git a/sway-parse/src/path.rs b/sway-parse/src/path.rs index 657e339747c..4a2a57ac706 100644 --- a/sway-parse/src/path.rs +++ b/sway-parse/src/path.rs @@ -136,37 +136,65 @@ mod tests { fn parse_nested_path() { assert_ron_snapshot!(parse::(r#" std::vec::Vec - "#,), @r###" + "#,), @r#" PathExpr( root_opt: None, prefix: PathExprSegment( - name: Ident( - to_string: "std", - span: (13, 16), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n std::vec::Vec\n ", + start: 13, + end: 16, + source_id: None, + ), + is_raw_ident: false, ), generics_opt: None, ), suffix: [ (DoubleColonToken( - span: (16, 18), + span: Span( + src: "\n std::vec::Vec\n ", + start: 16, + end: 18, + source_id: None, + ), ), PathExprSegment( - name: Ident( - to_string: "vec", - span: (18, 21), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n std::vec::Vec\n ", + start: 18, + end: 21, + source_id: None, + ), + is_raw_ident: false, ), generics_opt: None, )), (DoubleColonToken( - span: (21, 23), + span: Span( + src: "\n std::vec::Vec\n ", + start: 21, + end: 23, + source_id: None, + ), ), PathExprSegment( - name: Ident( - to_string: "Vec", - span: (23, 26), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n std::vec::Vec\n ", + start: 23, + end: 26, + source_id: None, + ), + is_raw_ident: false, ), generics_opt: None, )), ], ) - "###); + "#); } } diff --git a/sway-parse/tests/noop_script.rs b/sway-parse/tests/noop_script.rs index fd3fe83cf0e..709da28de33 100644 --- a/sway-parse/tests/noop_script.rs +++ b/sway-parse/tests/noop_script.rs @@ -12,17 +12,27 @@ fn noop_script_file() { fn main() { () } - "#,), @r###" + "#,), @r#" Some(Annotated( attribute_list: [], value: Module( kind: Script( script_token: ScriptToken( - span: (7, 13), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 7, + end: 13, + source_id: None, + ), ), ), semicolon_token: SemicolonToken( - span: (13, 14), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 13, + end: 14, + source_id: None, + ), ), items: [ Annotated( @@ -31,11 +41,22 @@ fn noop_script_file() { fn_signature: FnSignature( visibility: None, fn_token: FnToken( - span: (28, 30), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 28, + end: 30, + source_id: None, + ), ), - name: Ident( - to_string: "main", - span: (31, 35), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 31, + end: 35, + source_id: None, + ), + is_raw_ident: false, ), generics: None, arguments: Parens( @@ -43,7 +64,12 @@ fn noop_script_file() { value_separator_pairs: [], final_value_opt: None, )), - span: (35, 37), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 35, + end: 37, + source_id: None, + ), ), return_type_opt: None, where_clause_opt: None, @@ -53,16 +79,31 @@ fn noop_script_file() { statements: [], final_expr_opt: Some(Tuple(Parens( inner: Nil, - span: (48, 50), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 48, + end: 50, + source_id: None, + ), ))), - span: (39, 57), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 39, + end: 57, + source_id: None, + ), + ), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 38, + end: 58, + source_id: None, ), - span: (38, 58), ), )), ), ], ), )) - "###); + "#); } diff --git a/sway-types/Cargo.toml b/sway-types/Cargo.toml index aad3c5e52ac..89931ff9ab7 100644 --- a/sway-types/Cargo.toml +++ b/sway-types/Cargo.toml @@ -19,7 +19,7 @@ num-bigint.workspace = true num-traits.workspace = true parking_lot.workspace = true rustc-hash.workspace = true -serde = { workspace = true, features = ["derive"] } +serde = { workspace = true, features = ["derive", "std", "rc"] } sway-utils.workspace = true thiserror.workspace = true diff --git a/sway-types/src/ident.rs b/sway-types/src/ident.rs index f4aa577bc5d..ff1c168e9e6 100644 --- a/sway-types/src/ident.rs +++ b/sway-types/src/ident.rs @@ -1,7 +1,5 @@ -use serde::Serialize; - use crate::{span::Span, Spanned}; - +use serde::{Deserialize, Serialize}; use std::{ cmp::{Ord, Ordering}, fmt, @@ -13,7 +11,7 @@ pub trait Named { fn name(&self) -> &BaseIdent; } -#[derive(Clone)] +#[derive(Clone, Serialize, Deserialize)] pub struct BaseIdent { name_override_opt: Option>, span: Span, @@ -93,18 +91,6 @@ impl BaseIdent { /// often be different. pub type Ident = BaseIdent; -impl Serialize for Ident { - // Serialize an `Ident` struct with two fields: `to_string` and `span`. - fn serialize(&self, serializer: S) -> Result { - use serde::ser::SerializeStruct; - - let mut state = serializer.serialize_struct("Ident", 2)?; - state.serialize_field("to_string", &self.to_string())?; - state.serialize_field("span", &self.span)?; - state.end() - } -} - impl Hash for Ident { fn hash(&self, state: &mut H) { self.as_str().hash(state); diff --git a/sway-types/src/span.rs b/sway-types/src/span.rs index c757fb523da..99536c080ee 100644 --- a/sway-types/src/span.rs +++ b/sway-types/src/span.rs @@ -1,12 +1,11 @@ -use std::fmt::Display; - -use serde::{Deserialize, Serialize}; - use crate::SourceId; - -use { - lazy_static::lazy_static, - std::{cmp, fmt, hash::Hash, sync::Arc}, +use lazy_static::lazy_static; +use serde::{Deserialize, Serialize}; +use std::{ + cmp, + fmt::{self, Display}, + hash::Hash, + sync::Arc, }; lazy_static! { @@ -43,7 +42,7 @@ impl<'a> Position<'a> { } /// Represents a span of the source code in a specific file. -#[derive(Clone, Ord, PartialOrd)] +#[derive(Clone, Ord, PartialOrd, Serialize, Deserialize)] pub struct Span { // The original source code. src: Arc, @@ -71,18 +70,6 @@ impl PartialEq for Span { impl Eq for Span {} -impl Serialize for Span { - // Serialize a tuple two fields: `start` and `end`. - fn serialize(&self, serializer: S) -> Result { - use serde::ser::SerializeTuple; - - let mut state = serializer.serialize_tuple(2)?; - state.serialize_element(&self.start)?; - state.serialize_element(&self.end)?; - state.end() - } -} - impl From for std::ops::Range { fn from(value: Span) -> Self { Self { diff --git a/sway-types/src/u256.rs b/sway-types/src/u256.rs index e116308f169..2f42b43b0f3 100644 --- a/sway-types/src/u256.rs +++ b/sway-types/src/u256.rs @@ -1,10 +1,10 @@ -use std::ops::{Not, Shl, Shr}; - use num_bigint::{BigUint, ParseBigIntError, TryFromBigIntError}; use num_traits::Zero; +use serde::{Deserialize, Serialize}; +use std::ops::{Not, Shl, Shr}; use thiserror::Error; -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Serialize, Deserialize)] pub struct U256(BigUint); impl U256 { From 07dfa55182354f95202f1cbf1ca737fbc7040e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Matos?= Date: Mon, 2 Dec 2024 11:53:17 +0000 Subject: [PATCH 33/52] More namespace cleanups (#6675) ## Description Another round of namespace-related cleanups. ## 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). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --------- Co-authored-by: Joshua Batty --- .../ast_node/declaration/declaration.rs | 75 ++++----- .../ast_node/declaration/impl_trait.rs | 14 +- .../ast_node/declaration/supertrait.rs | 8 +- .../typed/typed_match_branch.rs | 5 +- .../match_expression/typed/typed_scrutinee.rs | 24 +-- .../ast_node/expression/typed_expression.rs | 69 ++------- .../typed_expression/method_application.rs | 26 +--- .../typed_expression/struct_instantiation.rs | 3 +- .../src/semantic_analysis/coins_analysis.rs | 27 ++-- .../semantic_analysis/namespace/namespace.rs | 68 +------- .../src/semantic_analysis/namespace/root.rs | 113 +------------- .../symbol_resolve_context.rs | 82 ++-------- .../semantic_analysis/type_check_context.rs | 70 +++++++-- .../src/semantic_analysis/type_resolve.rs | 145 ++++++++++++++---- .../src/type_system/ast_elements/binding.rs | 24 +-- .../ast_elements/trait_constraint.rs | 3 +- .../ast_elements/type_parameter.rs | 9 +- sway-core/src/type_system/monomorphization.rs | 3 +- 18 files changed, 269 insertions(+), 499 deletions(-) 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 b063fd53028..6047c8776aa 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -187,26 +187,20 @@ impl TyDecl { // save decl_refs for the LSP for supertrait in trait_decl.supertraits.iter_mut() { - let _ = ctx - .namespace() - .resolve_call_path_typed( - handler, - engines, - &supertrait.name, - ctx.self_type(), - ) - .map(|supertrait_decl| { - if let ty::TyDecl::TraitDecl(ty::TraitDecl { - decl_id: supertrait_decl_id, - }) = supertrait_decl - { - supertrait.decl_ref = Some(DeclRef::new( - engines.de().get(&supertrait_decl_id).name.clone(), - supertrait_decl_id, - engines.de().get(&supertrait_decl_id).span.clone(), - )); - } - }); + let _ = + ctx.resolve_call_path(handler, &supertrait.name) + .map(|supertrait_decl| { + if let ty::TyDecl::TraitDecl(ty::TraitDecl { + decl_id: supertrait_decl_id, + }) = supertrait_decl + { + supertrait.decl_ref = Some(DeclRef::new( + engines.de().get(&supertrait_decl_id).name.clone(), + supertrait_decl_id, + engines.de().get(&supertrait_decl_id).span.clone(), + )); + } + }); } let decl: ty::TyDecl = decl_engine @@ -301,12 +295,7 @@ impl TyDecl { // Choose which items are going to be visible depending if this is an abi impl // or trait impl - let t = ctx.namespace().resolve_call_path_typed( - &Handler::default(), - engines, - &impl_trait.trait_name, - ctx.self_type(), - ); + let t = ctx.resolve_call_path(&Handler::default(), &impl_trait.trait_name); let empty_vec = vec![]; let impl_trait_items = if let Ok(ty::TyDecl::TraitDecl { .. }) = t { @@ -369,26 +358,20 @@ impl TyDecl { // save decl_refs for the LSP for supertrait in abi_decl.supertraits.iter_mut() { - let _ = ctx - .namespace() - .resolve_call_path_typed( - handler, - engines, - &supertrait.name, - ctx.self_type(), - ) - .map(|supertrait_decl| { - if let ty::TyDecl::TraitDecl(ty::TraitDecl { - decl_id: supertrait_decl_id, - }) = supertrait_decl - { - supertrait.decl_ref = Some(DeclRef::new( - engines.de().get(&supertrait_decl_id).name.clone(), - supertrait_decl_id, - engines.de().get(&supertrait_decl_id).span.clone(), - )); - } - }); + let _ = + ctx.resolve_call_path(handler, &supertrait.name) + .map(|supertrait_decl| { + if let ty::TyDecl::TraitDecl(ty::TraitDecl { + decl_id: supertrait_decl_id, + }) = supertrait_decl + { + supertrait.decl_ref = Some(DeclRef::new( + engines.de().get(&supertrait_decl_id).name.clone(), + supertrait_decl_id, + engines.de().get(&supertrait_decl_id).span.clone(), + )); + } + }); } let decl: ty::TyDecl = decl_engine.insert(abi_decl.clone(), Some(&decl_id)).into(); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index 72320202ba2..758bfd1f09e 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -165,11 +165,7 @@ impl TyImplSelfOrTrait { .with_type_annotation(type_engine.new_unknown()) .with_self_type(Some(implementing_for.type_id)); - let impl_trait = match ctx - .namespace() - .resolve_call_path_typed(handler, engines, &trait_name, ctx.self_type()) - .ok() - { + let impl_trait = match ctx.resolve_call_path(handler, &trait_name).ok() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { let mut trait_decl = (*decl_engine.get_trait(&decl_id)).clone(); @@ -1567,14 +1563,8 @@ fn handle_supertraits( } match ctx - .namespace() // Use the default Handler to avoid emitting the redundant SymbolNotFound error. - .resolve_call_path_typed( - &Handler::default(), - engines, - &supertrait.name, - ctx.self_type(), - ) + .resolve_call_path(&Handler::default(), &supertrait.name) .ok() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs index d74932eea9e..0a791301737 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs @@ -53,14 +53,8 @@ pub(crate) fn insert_supertraits_into_namespace( } let decl = ctx - .namespace() // Use the default Handler to avoid emitting the redundant SymbolNotFound error. - .resolve_call_path_typed( - &Handler::default(), - engines, - &supertrait.name, - ctx.self_type(), - ) + .resolve_call_path(&Handler::default(), &supertrait.name) .ok(); match (decl.clone(), supertraits_of) { diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs index e00b968c4ce..09ac73392db 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs @@ -92,9 +92,8 @@ impl ty::TyMatchBranch { for (ident, is_struct_field) in variables { let default_handler = &Handler::default(); // If there exist a configurable with the same name as the pattern variable. - if let Ok(ty::TyDecl::ConfigurableDecl(configurable_decl)) = ctx - .namespace() - .resolve_symbol_typed(default_handler, engines, &ident, ctx.self_type()) + if let Ok(ty::TyDecl::ConfigurableDecl(configurable_decl)) = + ctx.resolve_symbol(default_handler, &ident) { let name = (&ident).into(); let configurable_span = engines diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs index f81916fa337..acfec750058 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs @@ -155,11 +155,7 @@ fn type_check_variable( let type_engine = engines.te(); let decl_engine = engines.de(); - let typed_scrutinee = match ctx - .namespace() - .resolve_symbol_typed(&Handler::default(), engines, &name, ctx.self_type()) - .ok() - { + let typed_scrutinee = match ctx.resolve_symbol(&Handler::default(), &name).ok() { // If the name represents a constant, then we turn it into a [ty::TyScrutineeVariant::Constant]. Some(ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id, .. })) => { let constant_decl = (*decl_engine.get_constant(&decl_id)).clone(); @@ -219,9 +215,7 @@ fn type_check_struct( let decl_engine = engines.de(); // find the struct definition from the name - let unknown_decl = - ctx.namespace() - .resolve_symbol_typed(handler, engines, &struct_name, ctx.self_type())?; + let unknown_decl = ctx.resolve_symbol(handler, &struct_name)?; let struct_id = unknown_decl.to_struct_decl(handler, ctx.engines())?; let mut struct_decl = (*decl_engine.get_struct(&struct_id)).clone(); @@ -484,23 +478,13 @@ fn type_check_enum( is_absolute: call_path.is_absolute, }; // find the enum definition from the name - let unknown_decl = ctx.namespace().resolve_call_path_typed( - handler, - engines, - &enum_callpath, - ctx.self_type(), - )?; + let unknown_decl = ctx.resolve_call_path(handler, &enum_callpath)?; let enum_id = unknown_decl.to_enum_id(handler, ctx.engines())?; (enum_callpath.span(), enum_id, unknown_decl) } None => { // we may have an imported variant - let decl = ctx.namespace().resolve_call_path_typed( - handler, - engines, - &call_path, - ctx.self_type(), - )?; + let decl = ctx.resolve_call_path(handler, &call_path)?; if let TyDecl::EnumVariantDecl(ty::EnumVariantDecl { enum_ref, .. }) = decl.clone() { (call_path.suffix.span(), *enum_ref.id(), decl) } else { diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 3d4d5259ec1..c8b72ec3837 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -49,6 +49,7 @@ use sway_error::{ }; use sway_types::{integer_bits::IntegerBits, u256::U256, Ident, Named, Span, Spanned}; use symbol_collection_context::SymbolCollectionContext; +use type_resolve::{resolve_call_path, VisibilityCheck}; #[allow(clippy::too_many_arguments)] impl ty::TyExpression { @@ -309,14 +310,7 @@ impl ty::TyExpression { is_absolute: false, }; if matches!( - ctx.namespace() - .resolve_call_path_typed( - &Handler::default(), - engines, - &call_path, - ctx.self_type() - ) - .ok(), + ctx.resolve_call_path(&Handler::default(), &call_path,).ok(), Some(ty::TyDecl::EnumVariantDecl { .. }) ) { Self::type_check_delineated_path( @@ -651,11 +645,7 @@ impl ty::TyExpression { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); - let exp = match ctx - .namespace() - .resolve_symbol_typed(&Handler::default(), engines, &name, ctx.self_type()) - .ok() - { + let exp = match ctx.resolve_symbol(&Handler::default(), &name).ok() { Some(ty::TyDecl::VariableDecl(decl)) => { let ty::TyVariableDecl { name: decl_name, @@ -1260,12 +1250,14 @@ impl ty::TyExpression { let storage_key_ident = Ident::new_with_override("StorageKey".into(), span.clone()); // Search for the struct declaration with the call path above. - let storage_key_decl = ctx.namespace().root().resolve_symbol( + let storage_key_decl = resolve_call_path( handler, engines, + ctx.namespace().root(), &storage_key_mod_path, - &storage_key_ident, + &storage_key_ident.into(), None, + VisibilityCheck::No, )?; let storage_key_struct_decl_id = storage_key_decl @@ -1420,12 +1412,7 @@ impl ty::TyExpression { is_absolute, }; if matches!( - ctx.namespace().resolve_call_path_typed( - &Handler::default(), - engines, - &call_path, - ctx.self_type() - ), + ctx.resolve_call_path(&Handler::default(), &call_path,), Ok(ty::TyDecl::EnumVariantDecl { .. }) ) { // if it's a singleton it's either an enum variant or a function @@ -1480,13 +1467,7 @@ impl ty::TyExpression { suffix: before.inner.clone(), is_absolute, }; - ctx.namespace() - .resolve_call_path_typed( - &Handler::default(), - engines, - &probe_call_path, - ctx.self_type(), - ) + ctx.resolve_call_path(&Handler::default(), &probe_call_path) .and_then(|decl| decl.to_enum_id(&Handler::default(), ctx.engines())) .map(|decl_ref| decl_engine.get_enum(&decl_ref)) .and_then(|decl| { @@ -1799,12 +1780,7 @@ impl ty::TyExpression { }; // look up the call path and get the declaration it references - let abi = ctx.namespace().resolve_call_path_typed( - handler, - engines, - &abi_name, - ctx.self_type(), - )?; + let abi = ctx.resolve_call_path(handler, &abi_name)?; let abi_ref = match abi { ty::TyDecl::AbiDecl(ty::AbiDecl { decl_id }) => { let abi_decl = engines.de().get(&decl_id); @@ -1825,12 +1801,7 @@ impl ty::TyExpression { match abi_name { // look up the call path and get the declaration it references AbiName::Known(abi_name) => { - let unknown_decl = ctx.namespace().resolve_call_path_typed( - handler, - engines, - abi_name, - ctx.self_type(), - )?; + let unknown_decl = ctx.resolve_call_path(handler, abi_name)?; unknown_decl.to_abi_ref(handler, engines)? } AbiName::Deferred => { @@ -2244,12 +2215,7 @@ impl ty::TyExpression { let (decl_reference_name, decl_reference_rhs, decl_reference_type) = match &reference_exp.expression { TyExpressionVariant::VariableExpression { name, .. } => { - let var_decl = ctx.namespace().resolve_symbol_typed( - handler, - engines, - name, - ctx.self_type(), - )?; + let var_decl = ctx.resolve_symbol(handler, name)?; let TyDecl::VariableDecl(var_decl) = var_decl else { return Err(handler.emit_err(CompileError::Internal( @@ -2309,12 +2275,7 @@ impl ty::TyExpression { match expr.kind { ExpressionKind::Variable(name) => { // check that the reassigned name exists - let unknown_decl = ctx.namespace().resolve_symbol_typed( - handler, - engines, - &name, - ctx.self_type(), - )?; + let unknown_decl = ctx.resolve_symbol(handler, &name)?; match unknown_decl { TyDecl::VariableDecl(variable_decl) => { @@ -2803,15 +2764,13 @@ fn check_asm_block_validity( // Emit warning if this register shadows a constant, or a configurable, or a variable. let temp_handler = Handler::default(); - let decl = ctx.namespace().resolve_call_path_typed( + let decl = ctx.resolve_call_path( &temp_handler, - ctx.engines, &CallPath { prefixes: vec![], suffix: sway_types::BaseIdent::new(span.clone()), is_absolute: true, }, - None, ); let shadowing_item = match decl { diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs index 6a836f56f3c..c5cb709b70c 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs @@ -225,13 +225,10 @@ pub(crate) fn type_check_method_application( // if the coins contract call parameter is not specified // it's considered to be zero and hence no error needs to be reported if let Some(coins_expr) = contract_call_params_map.get(CONTRACT_CALL_COINS_PARAMETER_NAME) { - if coins_analysis::possibly_nonzero_u64_expression( - ctx.namespace(), - ctx.engines, - coins_expr, - ) && !method - .attributes - .contains_key(&crate::transform::AttributeKind::Payable) + if coins_analysis::possibly_nonzero_u64_expression(&ctx, coins_expr) + && !method + .attributes + .contains_key(&crate::transform::AttributeKind::Payable) { return Err( handler.emit_err(CompileError::CoinsPassedToNonPayableMethod { @@ -288,12 +285,7 @@ pub(crate) fn type_check_method_application( ) -> Result<(), ErrorEmitted> { match exp { ty::TyExpressionVariant::VariableExpression { name, .. } => { - let unknown_decl = ctx.namespace().resolve_symbol_typed( - &Handler::default(), - ctx.engines, - name, - ctx.self_type(), - )?; + let unknown_decl = ctx.resolve_symbol(&Handler::default(), name)?; let is_decl_mutable = match unknown_decl { ty::TyDecl::ConstantDecl { .. } => false, @@ -816,11 +808,9 @@ pub(crate) fn resolve_method_name( let type_info_prefix = ctx .namespace() .prepend_module_path(&call_path_binding.inner.prefixes); - ctx.namespace().lookup_submodule_from_absolute_path( - handler, - engines, - &type_info_prefix, - )?; + ctx.namespace() + .root_module() + .lookup_submodule(handler, engines, &type_info_prefix)?; // find the method let decl_ref = ctx.find_method_for_type( diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs index bf52842ea81..85ba0be7b13 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs @@ -74,7 +74,8 @@ pub(crate) fn struct_instantiation( // find the module that the struct decl is in let type_info_prefix = ctx.namespace().prepend_module_path(prefixes); ctx.namespace() - .lookup_submodule_from_absolute_path(handler, engines, &type_info_prefix)?; + .root_module() + .lookup_submodule(handler, engines, &type_info_prefix)?; // resolve the type of the struct decl let type_id = ctx diff --git a/sway-core/src/semantic_analysis/coins_analysis.rs b/sway-core/src/semantic_analysis/coins_analysis.rs index 3b2b352f714..c88be235b84 100644 --- a/sway-core/src/semantic_analysis/coins_analysis.rs +++ b/sway-core/src/semantic_analysis/coins_analysis.rs @@ -1,16 +1,14 @@ use sway_error::handler::Handler; -use crate::{language::ty, Engines, Namespace}; +use crate::language::ty; + +use super::TypeCheckContext; // This analysis checks if an expression is known statically to evaluate // to a non-zero value at runtime. // It's intended to be used in the payability analysis to check if a non-payable // method gets called with a non-zero amount of `coins` -pub fn possibly_nonzero_u64_expression( - namespace: &Namespace, - engines: &Engines, - expr: &ty::TyExpression, -) -> bool { +pub fn possibly_nonzero_u64_expression(ctx: &TypeCheckContext, expr: &ty::TyExpression) -> bool { use ty::TyExpressionVariant::*; match &expr.expression { Literal(crate::language::Literal::U64(value)) => *value != 0, @@ -18,29 +16,24 @@ pub fn possibly_nonzero_u64_expression( // not a u64 literal, hence we return true to be on the safe side Literal(_) => true, ConstantExpression { decl, .. } => match &decl.value { - Some(expr) => possibly_nonzero_u64_expression(namespace, engines, expr), + Some(expr) => possibly_nonzero_u64_expression(ctx, expr), None => false, }, ConfigurableExpression { decl, .. } => match &decl.value { - Some(expr) => possibly_nonzero_u64_expression(namespace, engines, expr), + Some(expr) => possibly_nonzero_u64_expression(ctx, expr), None => false, }, VariableExpression { name, .. } => { - match namespace - .resolve_symbol_typed(&Handler::default(), engines, name, None) - .ok() - { + match ctx.resolve_symbol(&Handler::default(), name).ok() { Some(ty_decl) => { match ty_decl { ty::TyDecl::VariableDecl(var_decl) => { - possibly_nonzero_u64_expression(namespace, engines, &var_decl.body) + possibly_nonzero_u64_expression(ctx, &var_decl.body) } ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id, .. }) => { - let const_decl = engines.de().get_constant(&decl_id); + let const_decl = ctx.engines.de().get_constant(&decl_id); match &const_decl.value { - Some(value) => { - possibly_nonzero_u64_expression(namespace, engines, value) - } + Some(value) => possibly_nonzero_u64_expression(ctx, value), None => true, } } diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index 6ed7fe8007b..17f5a50a996 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -1,16 +1,10 @@ -use crate::{ - language::{ty, CallPath, Visibility}, - Engines, Ident, TypeId, -}; +use crate::{language::Visibility, Engines, Ident}; use super::{ - module::Module, - root::{ResolvedDeclaration, Root}, - submodule_namespace::SubmoduleNamespace, - ModulePath, ModulePathBuf, + module::Module, root::Root, submodule_namespace::SubmoduleNamespace, ModulePath, ModulePathBuf, }; -use sway_error::handler::{ErrorEmitted, Handler}; +use sway_error::handler::Handler; use sway_types::span::Span; /// The set of items that represent the namespace context passed throughout type checking. @@ -124,15 +118,6 @@ impl Namespace { .unwrap() } - pub fn lookup_submodule_from_absolute_path( - &self, - handler: &Handler, - engines: &Engines, - path: &ModulePath, - ) -> Result<&Module, ErrorEmitted> { - self.root.module.lookup_submodule(handler, engines, path) - } - /// Returns true if the current module being checked is a direct or indirect submodule of /// the module given by the `absolute_module_path`. /// @@ -189,53 +174,6 @@ impl Namespace { root_name != &absolute_module_path[0] } - /// Short-hand for calling [Root::resolve_symbol] on `root` with the `mod_path`. - pub(crate) fn resolve_symbol( - &self, - handler: &Handler, - engines: &Engines, - symbol: &Ident, - self_type: Option, - ) -> Result { - self.root - .resolve_symbol(handler, engines, &self.mod_path, symbol, self_type) - } - - /// Short-hand for calling [Root::resolve_symbol] on `root` with the `mod_path`. - pub(crate) fn resolve_symbol_typed( - &self, - handler: &Handler, - engines: &Engines, - symbol: &Ident, - self_type: Option, - ) -> Result { - self.resolve_symbol(handler, engines, symbol, self_type) - .map(|resolved_decl| resolved_decl.expect_typed()) - } - - /// Short-hand for calling [Root::resolve_call_path] on `root` with the `mod_path`. - pub(crate) fn resolve_call_path_typed( - &self, - handler: &Handler, - engines: &Engines, - call_path: &CallPath, - self_type: Option, - ) -> Result { - self.resolve_call_path(handler, engines, call_path, self_type) - .map(|resolved_decl| resolved_decl.expect_typed()) - } - - /// Short-hand for calling [Root::resolve_call_path] on `root` with the `mod_path`. - pub(crate) fn resolve_call_path( - &self, - handler: &Handler, - engines: &Engines, - call_path: &CallPath, - self_type: Option, - ) -> Result { - self.root - .resolve_call_path(handler, engines, &self.mod_path, call_path, self_type) - } /// "Enter" the submodule at the given path by returning a new [SubmoduleNamespace]. /// diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 086d91b31aa..99fd5eafc2b 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -7,10 +7,9 @@ use crate::{ language::{ parsed::*, ty::{self, StructDecl, TyDecl}, - CallPath, Visibility, + Visibility, }, namespace::{ModulePath, ModulePathBuf}, - semantic_analysis::type_resolve::{resolve_associated_item, resolve_associated_type}, TypeId, }; use sway_error::{ @@ -723,116 +722,6 @@ impl Root { Ok(()) } - - ////// NAME RESOLUTION ////// - - /// Resolve a symbol that is potentially prefixed with some path, e.g. `foo::bar::symbol`. - /// - /// This is short-hand for concatenating the `mod_path` with the `call_path`'s prefixes and - /// then calling `resolve_symbol` with the resulting path and call_path's suffix. - pub(crate) fn resolve_call_path( - &self, - handler: &Handler, - engines: &Engines, - mod_path: &ModulePath, - call_path: &CallPath, - self_type: Option, - ) -> Result { - let (decl, _) = - self.resolve_call_path_and_mod_path(handler, engines, mod_path, call_path, self_type)?; - Ok(decl) - } - - pub(crate) fn resolve_call_path_and_mod_path( - &self, - handler: &Handler, - engines: &Engines, - mod_path: &ModulePath, - call_path: &CallPath, - self_type: Option, - ) -> Result<(ResolvedDeclaration, ModulePathBuf), ErrorEmitted> { - let symbol_path: Vec<_> = mod_path - .iter() - .chain(&call_path.prefixes) - .cloned() - .collect(); - self.resolve_symbol_and_mod_path( - handler, - engines, - &symbol_path, - &call_path.suffix, - self_type, - ) - } - - /// Given a path to a module and the identifier of a symbol within that module, resolve its - /// declaration. - /// - /// If the symbol is within the given module's namespace via import, we recursively traverse - /// imports until we find the original declaration. - pub(crate) fn resolve_symbol( - &self, - handler: &Handler, - engines: &Engines, - mod_path: &ModulePath, - symbol: &Ident, - self_type: Option, - ) -> Result { - let (decl, _) = - self.resolve_symbol_and_mod_path(handler, engines, mod_path, symbol, self_type)?; - Ok(decl) - } - - fn resolve_symbol_and_mod_path( - &self, - handler: &Handler, - engines: &Engines, - mod_path: &ModulePath, - symbol: &Ident, - self_type: Option, - ) -> Result<(ResolvedDeclaration, Vec), ErrorEmitted> { - // This block tries to resolve associated types - let mut module = &self.module; - let mut current_mod_path = vec![]; - let mut decl_opt = None; - for ident in mod_path.iter() { - if let Some(decl) = decl_opt { - decl_opt = Some(resolve_associated_type( - handler, engines, module, ident, decl, None, self_type, - )?); - } else { - match module.submodules.get(ident.as_str()) { - Some(ns) => { - module = ns; - current_mod_path.push(ident.clone()); - } - None => { - decl_opt = Some( - module - .current_lexical_scope() - .items - .resolve_symbol(handler, engines, ident)?, - ); - } - } - } - } - if let Some(decl) = decl_opt { - let decl = - resolve_associated_item(handler, engines, module, symbol, decl, None, self_type)?; - return Ok((decl, current_mod_path)); - } - - self.module - .lookup_submodule(handler, engines, mod_path) - .and_then(|module| { - let decl = module - .current_lexical_scope() - .items - .resolve_symbol(handler, engines, symbol)?; - Ok((decl, mod_path.to_vec())) - }) - } } impl From for Root { diff --git a/sway-core/src/semantic_analysis/symbol_resolve_context.rs b/sway-core/src/semantic_analysis/symbol_resolve_context.rs index 01bc631ec0e..7a9155a193a 100644 --- a/sway-core/src/semantic_analysis/symbol_resolve_context.rs +++ b/sway-core/src/semantic_analysis/symbol_resolve_context.rs @@ -1,18 +1,18 @@ use crate::{ engine_threading::*, language::{CallPath, Visibility}, - namespace::{ModulePath, ResolvedDeclaration}, + namespace::ResolvedDeclaration, semantic_analysis::{ast_node::ConstShadowingMode, Namespace}, type_system::TypeId, }; -use sway_error::{ - error::CompileError, - handler::{ErrorEmitted, Handler}, -}; -use sway_types::{span::Span, Ident, Spanned}; -use sway_utils::iter_prefixes; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{span::Span, Ident}; -use super::{symbol_collection_context::SymbolCollectionContext, GenericShadowingMode}; +use super::{ + symbol_collection_context::SymbolCollectionContext, + type_resolve::{resolve_call_path, VisibilityCheck}, + GenericShadowingMode, +}; /// Contextual state tracked and accumulated throughout symbol resolving. pub struct SymbolResolveContext<'a> { @@ -184,70 +184,14 @@ impl<'a> SymbolResolveContext<'a> { handler: &Handler, call_path: &CallPath, ) -> Result { - self.resolve_call_path_with_visibility_check_and_modpath( + resolve_call_path( handler, + self.engines(), + self.namespace().root(), &self.namespace().mod_path, call_path, + self.self_type(), + VisibilityCheck::Yes, ) } - - /// Resolve a symbol that is potentially prefixed with some path, e.g. `foo::bar::symbol`. - /// - /// This will concatenate the `mod_path` with the `call_path`'s prefixes and - /// then calling `resolve_symbol` with the resulting path and call_path's suffix. - /// - /// The `mod_path` is significant here as we assume the resolution is done within the - /// context of the module pointed to by `mod_path` and will only check the call path prefixes - /// and the symbol's own visibility. - pub(crate) fn resolve_call_path_with_visibility_check_and_modpath( - &self, - handler: &Handler, - mod_path: &ModulePath, - call_path: &CallPath, - ) -> Result { - let (decl, mod_path) = self.namespace().root.resolve_call_path_and_mod_path( - handler, - self.engines, - mod_path, - call_path, - self.self_type, - )?; - - // In case there is no mod path we don't need to check visibility - if mod_path.is_empty() { - return Ok(decl); - } - - // In case there are no prefixes we don't need to check visibility - if call_path.prefixes.is_empty() { - return Ok(decl); - } - - // check the visibility of the call path elements - // we don't check the first prefix because direct children are always accessible - for prefix in iter_prefixes(&call_path.prefixes).skip(1) { - let module = self.namespace().lookup_submodule_from_absolute_path( - handler, - self.engines(), - prefix, - )?; - if module.visibility().is_private() { - let prefix_last = prefix[prefix.len() - 1].clone(); - handler.emit_err(CompileError::ImportPrivateModule { - span: prefix_last.span(), - name: prefix_last, - }); - } - } - - // check the visibility of the symbol itself - if !decl.visibility(self.engines).is_public() { - handler.emit_err(CompileError::ImportPrivateSymbol { - name: call_path.suffix.clone(), - span: call_path.suffix.span(), - }); - } - - Ok(decl) - } } diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index 2a6b71b5687..0c9827a2f1d 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -30,7 +30,7 @@ use sway_types::{span::Span, Ident, Spanned}; use super::{ symbol_collection_context::SymbolCollectionContext, - type_resolve::{resolve_call_path, resolve_qualified_call_path, resolve_type}, + type_resolve::{resolve_call_path, resolve_qualified_call_path, resolve_type, VisibilityCheck}, GenericShadowingMode, }; @@ -671,39 +671,80 @@ impl<'a> TypeCheckContext<'a> { type_info_prefix, self.self_type(), &self.subst_ctx(), + VisibilityCheck::Yes, ) } + pub(crate) fn resolve_qualified_call_path( + &mut self, + handler: &Handler, + qualified_call_path: &QualifiedCallPath, + ) -> Result { + resolve_qualified_call_path( + handler, + self.engines(), + self.namespace(), + &self.namespace().mod_path.clone(), + qualified_call_path, + self.self_type(), + &self.subst_ctx(), + VisibilityCheck::Yes, + ) + .map(|d| d.expect_typed()) + } + + /// Short-hand for calling [Root::resolve_symbol] on `root` with the `mod_path`. + pub(crate) fn resolve_symbol( + &self, + handler: &Handler, + symbol: &Ident, + ) -> Result { + resolve_call_path( + handler, + self.engines(), + self.namespace().root(), + self.namespace().mod_path(), + &symbol.clone().into(), + self.self_type(), + VisibilityCheck::No, + ) + .map(|d| d.expect_typed()) + } + /// Short-hand for calling [Root::resolve_call_path_with_visibility_check] on `root` with the `mod_path`. pub(crate) fn resolve_call_path_with_visibility_check( &self, handler: &Handler, call_path: &CallPath, - ) -> Result { + ) -> Result { resolve_call_path( handler, self.engines(), - self.namespace(), + self.namespace().root(), &self.namespace().mod_path, call_path, self.self_type(), + VisibilityCheck::Yes, ) + .map(|d| d.expect_typed()) } - pub(crate) fn resolve_qualified_call_path_with_visibility_check( - &mut self, + /// Short-hand for calling [Root::resolve_call_path] on `root` with the `mod_path`. + pub(crate) fn resolve_call_path( + &self, handler: &Handler, - qualified_call_path: &QualifiedCallPath, - ) -> Result { - resolve_qualified_call_path( + call_path: &CallPath, + ) -> Result { + resolve_call_path( handler, self.engines(), - self.namespace(), - &self.namespace().mod_path.clone(), - qualified_call_path, + self.namespace().root(), + self.namespace().mod_path(), + call_path, self.self_type(), - &self.subst_ctx(), + VisibilityCheck::No, ) + .map(|d| d.expect_typed()) } /// Given a name and a type (plus a `self_type` to potentially @@ -726,7 +767,7 @@ impl<'a> TypeCheckContext<'a> { } // grab the local module - let local_module = self.namespace().lookup_submodule_from_absolute_path( + let local_module = self.namespace().root_module().lookup_submodule( handler, self.engines(), &self.namespace().mod_path, @@ -749,11 +790,12 @@ impl<'a> TypeCheckContext<'a> { None, self.self_type(), &self.subst_ctx(), + VisibilityCheck::Yes, ) .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // grab the module where the type itself is declared - let type_module = self.namespace().lookup_submodule_from_absolute_path( + let type_module = self.namespace().root_module().lookup_submodule( handler, self.engines(), item_prefix, diff --git a/sway-core/src/semantic_analysis/type_resolve.rs b/sway-core/src/semantic_analysis/type_resolve.rs index 387d3f48b2d..06279dfceb5 100644 --- a/sway-core/src/semantic_analysis/type_resolve.rs +++ b/sway-core/src/semantic_analysis/type_resolve.rs @@ -11,11 +11,18 @@ use crate::{ CallPath, QualifiedCallPath, }, monomorphization::type_decl_opt_to_type_id, - namespace::{Module, ModulePath, ResolvedDeclaration, ResolvedTraitImplItem}, + namespace::{Module, ModulePath, ResolvedDeclaration, ResolvedTraitImplItem, Root}, type_system::SubstTypes, EnforceTypeArguments, Engines, Namespace, SubstTypesContext, TypeId, TypeInfo, }; +/// Specifies if visibility checks should be performed as part of name resolution. +#[derive(Clone, Copy, PartialEq)] +pub enum VisibilityCheck { + Yes, + No, +} + /// Resolve the type of the given [TypeId], replacing any instances of /// [TypeInfo::Custom] with either a monomorphized struct, monomorphized /// enum, or a reference to a type parameter. @@ -31,6 +38,7 @@ pub fn resolve_type( type_info_prefix: Option<&ModulePath>, self_type: Option, subst_ctx: &SubstTypesContext, + check_visibility: VisibilityCheck, ) -> Result { let type_engine = engines.te(); let module_path = type_info_prefix.unwrap_or(mod_path); @@ -47,6 +55,7 @@ pub fn resolve_type( &qualified_call_path, self_type, subst_ctx, + check_visibility, ) .ok(); type_decl_opt_to_type_id( @@ -75,6 +84,7 @@ pub fn resolve_type( None, self_type, subst_ctx, + check_visibility, ) .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); @@ -92,6 +102,7 @@ pub fn resolve_type( None, self_type, subst_ctx, + check_visibility, ) .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); @@ -110,6 +121,7 @@ pub fn resolve_type( None, self_type, subst_ctx, + check_visibility, ) .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); } @@ -156,6 +168,7 @@ pub fn resolve_type( None, self_type, subst_ctx, + check_visibility, ) .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); @@ -170,6 +183,7 @@ pub fn resolve_type( Ok(type_id) } +#[allow(clippy::too_many_arguments)] pub fn resolve_qualified_call_path( handler: &Handler, engines: &Engines, @@ -178,6 +192,7 @@ pub fn resolve_qualified_call_path( qualified_call_path: &QualifiedCallPath, self_type: Option, subst_ctx: &SubstTypesContext, + check_visibility: VisibilityCheck, ) -> Result { let type_engine = engines.te(); if let Some(qualified_path_root) = qualified_call_path.clone().qualified_path_root { @@ -190,10 +205,11 @@ pub fn resolve_qualified_call_path( let type_decl = resolve_call_path( handler, engines, - namespace, + namespace.root(), mod_path, &qualified_call_path.clone().to_call_path(handler)?, self_type, + check_visibility, )?; type_decl_opt_to_type_id( handler, @@ -238,10 +254,11 @@ pub fn resolve_qualified_call_path( resolve_call_path( handler, engines, - namespace, + namespace.root(), mod_path, &qualified_call_path.call_path, self_type, + check_visibility, ) } } @@ -257,14 +274,30 @@ pub fn resolve_qualified_call_path( pub fn resolve_call_path( handler: &Handler, engines: &Engines, - namespace: &Namespace, + root: &Root, mod_path: &ModulePath, call_path: &CallPath, self_type: Option, + check_visibility: VisibilityCheck, ) -> Result { - let (decl, mod_path) = namespace - .root - .resolve_call_path_and_mod_path(handler, engines, mod_path, call_path, self_type)?; + let symbol_path: Vec<_> = mod_path + .iter() + .chain(&call_path.prefixes) + .cloned() + .collect(); + + let (decl, mod_path) = resolve_symbol_and_mod_path( + handler, + engines, + &root.module, + &symbol_path, + &call_path.suffix, + self_type, + )?; + + if check_visibility == VisibilityCheck::No { + return Ok(decl); + } // In case there is no mod path we don't need to check visibility if mod_path.is_empty() { @@ -279,7 +312,7 @@ pub fn resolve_call_path( // check the visibility of the call path elements // we don't check the first prefix because direct children are always accessible for prefix in iter_prefixes(&call_path.prefixes).skip(1) { - let module = namespace.lookup_submodule_from_absolute_path(handler, engines, prefix)?; + let module = root.module.lookup_submodule(handler, engines, prefix)?; if module.visibility().is_private() { let prefix_last = prefix[prefix.len() - 1].clone(); handler.emit_err(CompileError::ImportPrivateModule { @@ -300,7 +333,71 @@ pub fn resolve_call_path( Ok(decl) } -pub fn decl_to_type_info( +fn resolve_symbol_and_mod_path( + handler: &Handler, + engines: &Engines, + module: &Module, + mod_path: &ModulePath, + symbol: &Ident, + self_type: Option, +) -> Result<(ResolvedDeclaration, Vec), ErrorEmitted> { + let mut current_module = module; + // This block tries to resolve associated types + let mut current_mod_path = vec![]; + let mut decl_opt = None; + for ident in mod_path.iter() { + if let Some(decl) = decl_opt { + decl_opt = Some(resolve_associated_type_or_item( + handler, + engines, + current_module, + ident, + decl, + None, + self_type, + )?); + } else { + match current_module.submodules.get(ident.as_str()) { + Some(ns) => { + current_module = ns; + current_mod_path.push(ident.clone()); + } + None => { + decl_opt = Some( + current_module + .current_lexical_scope() + .items + .resolve_symbol(handler, engines, ident)?, + ); + } + } + } + } + if let Some(decl) = decl_opt { + let decl = resolve_associated_type_or_item( + handler, + engines, + current_module, + symbol, + decl, + None, + self_type, + )?; + return Ok((decl, current_mod_path)); + } + + module + .lookup_submodule(handler, engines, mod_path) + .and_then(|module| { + let decl = module + .current_lexical_scope() + .items + .resolve_symbol(handler, engines, symbol)?; + Ok((decl, mod_path.to_vec())) + }) +} + +fn decl_to_type_info( handler: &Handler, engines: &Engines, symbol: &Ident, @@ -335,7 +432,7 @@ pub fn decl_to_type_info( } #[allow(clippy::too_many_arguments)] -pub fn resolve_associated_item_from_type_id( +fn resolve_associated_item_from_type_id( handler: &Handler, engines: &Engines, module: &Module, @@ -371,27 +468,7 @@ pub fn resolve_associated_item_from_type_id( } #[allow(clippy::too_many_arguments)] -pub fn resolve_associated_type( - handler: &Handler, - engines: &Engines, - module: &Module, - symbol: &Ident, - decl: ResolvedDeclaration, - as_trait: Option, - self_type: Option, -) -> Result { - let type_info = decl_to_type_info(handler, engines, symbol, decl)?; - let type_id = engines - .te() - .insert(engines, type_info, symbol.span().source_id()); - - resolve_associated_item_from_type_id( - handler, engines, module, symbol, type_id, as_trait, self_type, - ) -} - -#[allow(clippy::too_many_arguments)] -pub fn resolve_associated_item( +fn resolve_associated_type_or_item( handler: &Handler, engines: &Engines, module: &Module, @@ -411,7 +488,7 @@ pub fn resolve_associated_item( } #[allow(clippy::too_many_arguments)] -pub(crate) fn resolve_call_path_and_root_type_id( +fn resolve_call_path_and_root_type_id( handler: &Handler, engines: &Engines, module: &Module, @@ -437,7 +514,7 @@ pub(crate) fn resolve_call_path_and_root_type_id( )?); as_trait = None; } else if let Some(decl) = decl_opt { - decl_opt = Some(resolve_associated_type( + decl_opt = Some(resolve_associated_type_or_item( handler, engines, module, @@ -462,7 +539,7 @@ pub(crate) fn resolve_call_path_and_root_type_id( return Ok(decl); } if let Some(decl) = decl_opt { - let decl = resolve_associated_item( + let decl = resolve_associated_type_or_item( handler, engines, module, diff --git a/sway-core/src/type_system/ast_elements/binding.rs b/sway-core/src/type_system/ast_elements/binding.rs index 96d91b24f74..78b4696e313 100644 --- a/sway-core/src/type_system/ast_elements/binding.rs +++ b/sway-core/src/type_system/ast_elements/binding.rs @@ -220,7 +220,8 @@ impl TypeBinding> { // find the module that the symbol is in let type_info_prefix = ctx.namespace().prepend_module_path(&self.inner.prefixes); ctx.namespace() - .lookup_submodule_from_absolute_path(handler, engines, &type_info_prefix)?; + .root_module() + .lookup_submodule(handler, engines, &type_info_prefix)?; // create the type info object let type_info = type_info.apply_type_arguments( @@ -286,6 +287,7 @@ impl SymbolResolveTypeBinding for TypeBinding { let engines = ctx.engines(); // Grab the declaration. let unknown_decl = ctx.resolve_call_path_with_visibility_check(handler, &self.inner)?; + // Check to see if this is a function declaration. let fn_decl = unknown_decl .resolve_parsed(engines.de()) @@ -311,9 +313,7 @@ impl TypeCheckTypeBinding for TypeBinding { let decl_engine = ctx.engines.de(); // Grab the declaration. - let unknown_decl = ctx - .resolve_call_path_with_visibility_check(handler, &self.inner)? - .expect_typed(); + let unknown_decl = ctx.resolve_call_path_with_visibility_check(handler, &self.inner)?; // Check to see if this is a fn declaration. let fn_ref = unknown_decl.to_fn_ref(handler, ctx.engines())?; // Get a new copy from the declaration engine. @@ -389,9 +389,7 @@ impl TypeCheckTypeBinding for TypeBinding { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); // Grab the declaration. - let unknown_decl = ctx - .resolve_call_path_with_visibility_check(handler, &self.inner)? - .expect_typed(); + let unknown_decl = ctx.resolve_call_path_with_visibility_check(handler, &self.inner)?; // Check to see if this is a struct declaration. let struct_id = unknown_decl.to_struct_decl(handler, engines)?; // Get a new copy from the declaration engine. @@ -431,9 +429,7 @@ impl TypeCheckTypeBinding for TypeBinding { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); // Grab the declaration. - let unknown_decl = ctx - .resolve_call_path_with_visibility_check(handler, &self.inner)? - .expect_typed(); + let unknown_decl = ctx.resolve_call_path_with_visibility_check(handler, &self.inner)?; // Get a new copy from the declaration engine. let enum_id = if let ty::TyDecl::EnumVariantDecl(ty::EnumVariantDecl { enum_ref, .. }) = @@ -470,9 +466,7 @@ impl TypeBinding { ctx: &mut TypeCheckContext, ) -> Result>, ErrorEmitted> { // Grab the declaration. - let unknown_decl = ctx - .resolve_qualified_call_path_with_visibility_check(handler, &self.inner)? - .expect_typed(); + let unknown_decl = ctx.resolve_qualified_call_path(handler, &self.inner)?; // Check to see if this is a const declaration. let const_ref = unknown_decl.to_const_ref(handler, ctx.engines())?; @@ -495,9 +489,7 @@ impl TypeCheckTypeBinding for TypeBinding { ErrorEmitted, > { // Grab the declaration. - let unknown_decl = ctx - .resolve_call_path_with_visibility_check(handler, &self.inner)? - .expect_typed(); + let unknown_decl = ctx.resolve_call_path_with_visibility_check(handler, &self.inner)?; // Check to see if this is a const declaration. let const_ref = unknown_decl.to_const_ref(handler, ctx.engines())?; diff --git a/sway-core/src/type_system/ast_elements/trait_constraint.rs b/sway-core/src/type_system/ast_elements/trait_constraint.rs index f51fe79d691..d0ed5e3b0dd 100644 --- a/sway-core/src/type_system/ast_elements/trait_constraint.rs +++ b/sway-core/src/type_system/ast_elements/trait_constraint.rs @@ -192,9 +192,8 @@ impl TraitConstraint { let mut type_arguments = type_arguments.clone(); match ctx - .namespace() // Use the default Handler to avoid emitting the redundant SymbolNotFound error. - .resolve_call_path_typed(&Handler::default(), engines, trait_name, ctx.self_type()) + .resolve_call_path(&Handler::default(), trait_name) .ok() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { diff --git a/sway-core/src/type_system/ast_elements/type_parameter.rs b/sway-core/src/type_system/ast_elements/type_parameter.rs index 7b6c8b48e5a..d924c7f387b 100644 --- a/sway-core/src/type_system/ast_elements/type_parameter.rs +++ b/sway-core/src/type_system/ast_elements/type_parameter.rs @@ -274,11 +274,7 @@ impl TypeParameter { ctx: &TypeCheckContext, tc: &TraitConstraint, ) -> Vec { - match ctx - .namespace() - .resolve_call_path_typed(handler, ctx.engines, &tc.trait_name, ctx.self_type()) - .ok() - { + match ctx.resolve_call_path(handler, &tc.trait_name).ok() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { let trait_decl = ctx.engines.de().get_trait(&decl_id); let mut result = trait_decl @@ -647,9 +643,8 @@ fn handle_trait( handler.scope(|handler| { match ctx - .namespace() // Use the default Handler to avoid emitting the redundant SymbolNotFound error. - .resolve_call_path_typed(&Handler::default(), engines, trait_name, ctx.self_type()) + .resolve_call_path(&Handler::default(), trait_name) .ok() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { diff --git a/sway-core/src/type_system/monomorphization.rs b/sway-core/src/type_system/monomorphization.rs index ffe432f2292..6eb6581e96a 100644 --- a/sway-core/src/type_system/monomorphization.rs +++ b/sway-core/src/type_system/monomorphization.rs @@ -11,7 +11,7 @@ use crate::{ CallPath, }, namespace::{ModulePath, ResolvedDeclaration}, - semantic_analysis::type_resolve::resolve_type, + semantic_analysis::type_resolve::{resolve_type, VisibilityCheck}, type_system::ast_elements::create_type_id::CreateTypeId, EnforceTypeArguments, Engines, Namespace, SubstTypes, SubstTypesContext, TypeArgument, TypeId, TypeParameter, TypeSubstMap, @@ -129,6 +129,7 @@ where None, self_type, subst_ctx, + VisibilityCheck::Yes, ) .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); } From 5423c56c0cbb8aec07acdd5928f0817ad3a7fd68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Matos?= Date: Mon, 2 Dec 2024 20:01:12 +0000 Subject: [PATCH 34/52] Implement hierarchical trait map and namespace lookups. (#6516) ## Description This PR implements a hierarchical-based trait map and namespace lookup system while type checking. Previously we added the concept of lexical concepts, which store all the names in a tree-based hierarchy. But currently we still rely on a single "global" namespace, which is maintained by the type check context as we go down the tree. Thus, so far, all trait and namespace lookup have relied on looking up in that single namespace. The main idea here is to be able to just rely on the names existing in the lexical scopes, and walk up those lexical scope chains as we need to lookup any name or trait. The logic is split into these two commits: [Implement hierarchical trait map lookups.](https://github.com/FuelLabs/sway/pull/6516/commits/4043fb5bcb5157971e03752de57ea86fa8fc03b6) [Implement hierarchical namespace lookups.](https://github.com/FuelLabs/sway/pull/6516/commits/486df45623eb80f186c41451159c2959277bd0a2) This PR still does not remove that cloning, which will be done in a separate future PR. ## 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). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --- .../ast_node/declaration/impl_trait.rs | 29 ++- .../ast_node/expression/typed_expression.rs | 187 ++++++++++++++++- .../typed_expression/struct_instantiation.rs | 3 +- .../namespace/lexical_scope.rs | 194 +----------------- .../src/semantic_analysis/namespace/mod.rs | 2 +- .../src/semantic_analysis/namespace/module.rs | 95 ++++++++- .../semantic_analysis/namespace/trait_map.rs | 83 ++++++-- .../semantic_analysis/type_check_context.rs | 33 ++- .../src/semantic_analysis/type_resolve.rs | 12 +- .../ast_elements/type_parameter.rs | 22 +- sway-lsp/src/capabilities/completion.rs | 15 +- sway-lsp/src/core/session.rs | 2 +- 12 files changed, 394 insertions(+), 283 deletions(-) diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index 758bfd1f09e..1e5b9fdfd24 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -22,7 +22,7 @@ use crate::{ }, *, }, - namespace::{IsExtendingExistingImpl, IsImplSelf, TryInsertingTraitImplOnFailure}, + namespace::{IsExtendingExistingImpl, IsImplSelf, TraitMap, TryInsertingTraitImplOnFailure}, semantic_analysis::{ symbol_collection_context::SymbolCollectionContext, AbiMode, ConstShadowingMode, TyNodeDepGraphNodeId, TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, @@ -691,20 +691,19 @@ fn type_check_trait_implementation( ctx.namespace_mut() .module_mut(engines) .write(engines, |m| { - m.current_items_mut() - .implemented_traits - .check_if_trait_constraints_are_satisfied_for_type( - handler, - implementing_for, - &trait_supertraits - .iter() - .map(|x| x.into()) - .collect::>(), - block_span, - engines, - TryInsertingTraitImplOnFailure::Yes, - code_block_first_pass.into(), - ) + TraitMap::check_if_trait_constraints_are_satisfied_for_type( + handler, + m, + implementing_for, + &trait_supertraits + .iter() + .map(|x| x.into()) + .collect::>(), + block_span, + engines, + TryInsertingTraitImplOnFailure::Yes, + code_block_first_pass.into(), + ) })?; for (type_arg, type_param) in trait_type_arguments.iter().zip(trait_type_parameters) { diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index c8b72ec3837..0fa64d14598 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -23,8 +23,8 @@ use crate::{ language::{ parsed::*, ty::{ - self, GetDeclIdent, TyCodeBlock, TyDecl, TyExpression, TyExpressionVariant, TyImplItem, - TyReassignmentTarget, VariableMutability, + self, GetDeclIdent, StructAccessInfo, TyCodeBlock, TyDecl, TyExpression, + TyExpressionVariant, TyImplItem, TyReassignmentTarget, VariableMutability, }, *, }, @@ -38,12 +38,13 @@ use crate::{ use ast_node::declaration::{insert_supertraits_into_namespace, SupertraitOf}; use either::Either; use indexmap::IndexMap; +use namespace::{LexicalScope, Module, ResolvedDeclaration}; use rustc_hash::FxHashSet; use std::collections::{HashMap, VecDeque}; use sway_ast::intrinsics::Intrinsic; use sway_error::{ convert_parse_tree_error::ConvertParseTreeError, - error::CompileError, + error::{CompileError, StructFieldUsageContext}, handler::{ErrorEmitted, Handler}, warning::{CompileWarning, Warning}, }; @@ -2369,7 +2370,8 @@ impl ty::TyExpression { let indices = indices.into_iter().rev().collect::>(); let (ty_of_field, _ty_of_parent) = ctx.namespace().program_id(engines).read(engines, |m| { - m.current_items().find_subfield_type( + Self::find_subfield_type( + m, handler, ctx.engines(), ctx.namespace(), @@ -2406,6 +2408,183 @@ impl ty::TyExpression { }) } + pub fn find_subfield_type( + module: &Module, + handler: &Handler, + engines: &Engines, + namespace: &Namespace, + base_name: &Ident, + projections: &[ty::ProjectionKind], + ) -> Result<(TypeId, TypeId), ErrorEmitted> { + let ret = module.walk_scope_chain(|lexical_scope| { + Self::find_subfield_type_helper( + lexical_scope, + handler, + engines, + namespace, + base_name, + projections, + ) + })?; + + if let Some(ret) = ret { + Ok(ret) + } else { + // Symbol not found + Err(handler.emit_err(CompileError::UnknownVariable { + var_name: base_name.clone(), + span: base_name.span(), + })) + } + } + + /// Returns a tuple where the first element is the [TypeId] of the actual expression, and + /// the second is the [TypeId] of its parent. + fn find_subfield_type_helper( + lexical_scope: &LexicalScope, + handler: &Handler, + engines: &Engines, + namespace: &Namespace, + base_name: &Ident, + projections: &[ty::ProjectionKind], + ) -> Result, ErrorEmitted> { + let type_engine = engines.te(); + let decl_engine = engines.de(); + + let symbol = match lexical_scope.items.symbols.get(base_name).cloned() { + Some(s) => s, + None => { + return Ok(None); + } + }; + let mut symbol = match symbol { + ResolvedDeclaration::Parsed(_) => unreachable!(), + ResolvedDeclaration::Typed(ty_decl) => ty_decl.return_type(handler, engines)?, + }; + let mut symbol_span = base_name.span(); + let mut parent_rover = symbol; + let mut full_span_for_error = base_name.span(); + for projection in projections { + let resolved_type = match type_engine.to_typeinfo(symbol, &symbol_span) { + Ok(resolved_type) => resolved_type, + Err(error) => { + return Err(handler.emit_err(CompileError::TypeError(error))); + } + }; + match (resolved_type, projection) { + ( + TypeInfo::Struct(decl_ref), + ty::ProjectionKind::StructField { name: field_name }, + ) => { + let struct_decl = decl_engine.get_struct(&decl_ref); + let (struct_can_be_changed, is_public_struct_access) = + StructAccessInfo::get_info(engines, &struct_decl, namespace).into(); + + let field_type_id = match struct_decl.find_field(field_name) { + Some(struct_field) => { + if is_public_struct_access && struct_field.is_private() { + return Err(handler.emit_err(CompileError::StructFieldIsPrivate { + field_name: field_name.into(), + struct_name: struct_decl.call_path.suffix.clone(), + field_decl_span: struct_field.name.span(), + struct_can_be_changed, + usage_context: StructFieldUsageContext::StructFieldAccess, + })); + } + + struct_field.type_argument.type_id + } + None => { + return Err(handler.emit_err(CompileError::StructFieldDoesNotExist { + field_name: field_name.into(), + available_fields: struct_decl + .accessible_fields_names(is_public_struct_access), + is_public_struct_access, + struct_name: struct_decl.call_path.suffix.clone(), + struct_decl_span: struct_decl.span(), + struct_is_empty: struct_decl.is_empty(), + usage_context: StructFieldUsageContext::StructFieldAccess, + })); + } + }; + parent_rover = symbol; + symbol = field_type_id; + symbol_span = field_name.span().clone(); + full_span_for_error = Span::join(full_span_for_error, &field_name.span()); + } + (TypeInfo::Tuple(fields), ty::ProjectionKind::TupleField { index, index_span }) => { + let field_type_opt = { + fields + .get(*index) + .map(|TypeArgument { type_id, .. }| type_id) + }; + let field_type = match field_type_opt { + Some(field_type) => field_type, + None => { + return Err(handler.emit_err(CompileError::TupleIndexOutOfBounds { + index: *index, + count: fields.len(), + tuple_type: engines.help_out(symbol).to_string(), + span: index_span.clone(), + prefix_span: full_span_for_error.clone(), + })); + } + }; + parent_rover = symbol; + symbol = *field_type; + symbol_span = index_span.clone(); + full_span_for_error = Span::join(full_span_for_error, index_span); + } + ( + TypeInfo::Array(elem_ty, _), + ty::ProjectionKind::ArrayIndex { index_span, .. }, + ) => { + parent_rover = symbol; + symbol = elem_ty.type_id; + symbol_span = index_span.clone(); + // `index_span` does not contain the enclosing square brackets. + // Which means, if this array index access is the last one before the + // erroneous expression, the `full_span_for_error` will be missing the + // closing `]`. We can live with this small glitch so far. To fix it, + // we would need to bring the full span of the index all the way from + // the parsing stage. An effort that doesn't pay off at the moment. + // TODO: Include the closing square bracket into the error span. + full_span_for_error = Span::join(full_span_for_error, index_span); + } + (actually, ty::ProjectionKind::StructField { name }) => { + return Err(handler.emit_err(CompileError::FieldAccessOnNonStruct { + actually: engines.help_out(actually).to_string(), + storage_variable: None, + field_name: name.into(), + span: full_span_for_error, + })); + } + ( + actually, + ty::ProjectionKind::TupleField { + index, index_span, .. + }, + ) => { + return Err( + handler.emit_err(CompileError::TupleElementAccessOnNonTuple { + actually: engines.help_out(actually).to_string(), + span: full_span_for_error, + index: *index, + index_span: index_span.clone(), + }), + ); + } + (actually, ty::ProjectionKind::ArrayIndex { .. }) => { + return Err(handler.emit_err(CompileError::NotIndexable { + actually: engines.help_out(actually).to_string(), + span: full_span_for_error, + })); + } + } + } + Ok(Some((symbol, parent_rover))) + } + fn type_check_ref( handler: &Handler, mut ctx: TypeCheckContext<'_>, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs index 85ba0be7b13..ef900927271 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs @@ -334,8 +334,7 @@ fn collect_struct_constructors( // but that would be a way too much of suggestions, and moreover, it is also not a design pattern/guideline // that we wish to encourage. namespace.program_id(engines).read(engines, |m| { - m.current_items() - .get_items_for_type(engines, struct_type_id) + m.get_items_for_type(engines, struct_type_id) .iter() .filter_map(|item| match item { ResolvedTraitImplItem::Parsed(_) => unreachable!(), diff --git a/sway-core/src/semantic_analysis/namespace/lexical_scope.rs b/sway-core/src/semantic_analysis/namespace/lexical_scope.rs index 62203b13dda..a3b549abae4 100644 --- a/sway-core/src/semantic_analysis/namespace/lexical_scope.rs +++ b/sway-core/src/semantic_analysis/namespace/lexical_scope.rs @@ -3,7 +3,7 @@ use crate::{ engine_threading::{Engines, PartialEqWithEngines, PartialEqWithEnginesContext}, language::{ parsed::{Declaration, FunctionDeclaration}, - ty::{self, StructAccessInfo, TyDecl, TyStorageDecl}, + ty::{self, TyDecl, TyStorageDecl}, CallPath, Visibility, }, namespace::*, @@ -15,7 +15,7 @@ use super::{root::ResolvedDeclaration, TraitMap}; use parking_lot::RwLock; use sway_error::{ - error::{CompileError, ShadowingSource, StructFieldUsageContext}, + error::{CompileError, ShadowingSource}, handler::{ErrorEmitted, Handler}, }; use sway_types::{span::Span, IdentUnique, Named, Spanned}; @@ -161,21 +161,21 @@ impl Items { handler: &Handler, engines: &Engines, symbol: &Ident, - ) -> Result { + ) -> Result, ErrorEmitted> { // Check locally declared items. Any name clash with imports will have already been reported as an error. if let Some(decl) = self.symbols.get(symbol) { - return Ok(decl.clone()); + return Ok(Some(decl.clone())); } // Check item imports if let Some((_, _, decl, _)) = self.use_item_synonyms.get(symbol) { - return Ok(decl.clone()); + return Ok(Some(decl.clone())); } // Check glob imports if let Some(decls) = self.use_glob_synonyms.get(symbol) { if decls.len() == 1 { - return Ok(decls[0].1.clone()); + return Ok(Some(decls[0].1.clone())); } else if decls.is_empty() { return Err(handler.emit_err(CompileError::Internal( "The name {symbol} was bound in a star import, but no corresponding module paths were found", @@ -193,11 +193,7 @@ impl Items { } } - // Symbol not found - Err(handler.emit_err(CompileError::SymbolNotFound { - name: symbol.clone(), - span: symbol.span(), - })) + Ok(None) } pub(crate) fn insert_parsed_symbol( @@ -768,14 +764,6 @@ impl Items { .clear(); } - pub fn get_items_for_type( - &self, - engines: &Engines, - type_id: TypeId, - ) -> Vec { - self.implemented_traits.get_items_for_type(engines, type_id) - } - pub fn get_impl_spans_for_decl(&self, engines: &Engines, ty_decl: &TyDecl) -> Vec { let handler = Handler::default(); ty_decl @@ -797,24 +785,6 @@ impl Items { .get_impl_spans_for_trait_name(trait_name) } - pub fn get_methods_for_type( - &self, - engines: &Engines, - type_id: TypeId, - ) -> Vec { - self.get_items_for_type(engines, type_id) - .into_iter() - .filter_map(|item| match item { - ResolvedTraitImplItem::Parsed(_) => todo!(), - ResolvedTraitImplItem::Typed(item) => match item { - ty::TyTraitItem::Fn(decl_ref) => Some(ResolvedFunctionDecl::Typed(decl_ref)), - ty::TyTraitItem::Constant(_decl_ref) => None, - ty::TyTraitItem::Type(_decl_ref) => None, - }, - }) - .collect::>() - } - pub(crate) fn has_storage_declared(&self) -> bool { self.declared_storage.is_some() } @@ -839,156 +809,6 @@ impl Items { } } } - - /// Returns a tuple where the first element is the [TypeId] of the actual expression, and - /// the second is the [TypeId] of its parent. - pub(crate) fn find_subfield_type( - &self, - handler: &Handler, - engines: &Engines, - namespace: &Namespace, - base_name: &Ident, - projections: &[ty::ProjectionKind], - ) -> Result<(TypeId, TypeId), ErrorEmitted> { - let type_engine = engines.te(); - let decl_engine = engines.de(); - - let symbol = match self.symbols.get(base_name).cloned() { - Some(s) => s, - None => { - return Err(handler.emit_err(CompileError::UnknownVariable { - var_name: base_name.clone(), - span: base_name.span(), - })); - } - }; - let mut symbol = match symbol { - ResolvedDeclaration::Parsed(_) => unreachable!(), - ResolvedDeclaration::Typed(ty_decl) => ty_decl.return_type(handler, engines)?, - }; - let mut symbol_span = base_name.span(); - let mut parent_rover = symbol; - let mut full_span_for_error = base_name.span(); - for projection in projections { - let resolved_type = match type_engine.to_typeinfo(symbol, &symbol_span) { - Ok(resolved_type) => resolved_type, - Err(error) => { - return Err(handler.emit_err(CompileError::TypeError(error))); - } - }; - match (resolved_type, projection) { - ( - TypeInfo::Struct(decl_ref), - ty::ProjectionKind::StructField { name: field_name }, - ) => { - let struct_decl = decl_engine.get_struct(&decl_ref); - let (struct_can_be_changed, is_public_struct_access) = - StructAccessInfo::get_info(engines, &struct_decl, namespace).into(); - - let field_type_id = match struct_decl.find_field(field_name) { - Some(struct_field) => { - if is_public_struct_access && struct_field.is_private() { - return Err(handler.emit_err(CompileError::StructFieldIsPrivate { - field_name: field_name.into(), - struct_name: struct_decl.call_path.suffix.clone(), - field_decl_span: struct_field.name.span(), - struct_can_be_changed, - usage_context: StructFieldUsageContext::StructFieldAccess, - })); - } - - struct_field.type_argument.type_id - } - None => { - return Err(handler.emit_err(CompileError::StructFieldDoesNotExist { - field_name: field_name.into(), - available_fields: struct_decl - .accessible_fields_names(is_public_struct_access), - is_public_struct_access, - struct_name: struct_decl.call_path.suffix.clone(), - struct_decl_span: struct_decl.span(), - struct_is_empty: struct_decl.is_empty(), - usage_context: StructFieldUsageContext::StructFieldAccess, - })); - } - }; - parent_rover = symbol; - symbol = field_type_id; - symbol_span = field_name.span().clone(); - full_span_for_error = Span::join(full_span_for_error, &field_name.span()); - } - (TypeInfo::Tuple(fields), ty::ProjectionKind::TupleField { index, index_span }) => { - let field_type_opt = { - fields - .get(*index) - .map(|TypeArgument { type_id, .. }| type_id) - }; - let field_type = match field_type_opt { - Some(field_type) => field_type, - None => { - return Err(handler.emit_err(CompileError::TupleIndexOutOfBounds { - index: *index, - count: fields.len(), - tuple_type: engines.help_out(symbol).to_string(), - span: index_span.clone(), - prefix_span: full_span_for_error.clone(), - })); - } - }; - parent_rover = symbol; - symbol = *field_type; - symbol_span = index_span.clone(); - full_span_for_error = Span::join(full_span_for_error, index_span); - } - ( - TypeInfo::Array(elem_ty, _), - ty::ProjectionKind::ArrayIndex { index_span, .. }, - ) => { - parent_rover = symbol; - symbol = elem_ty.type_id; - symbol_span = index_span.clone(); - // `index_span` does not contain the enclosing square brackets. - // Which means, if this array index access is the last one before the - // erroneous expression, the `full_span_for_error` will be missing the - // closing `]`. We can live with this small glitch so far. To fix it, - // we would need to bring the full span of the index all the way from - // the parsing stage. An effort that doesn't pay off at the moment. - // TODO: Include the closing square bracket into the error span. - full_span_for_error = Span::join(full_span_for_error, index_span); - } - (actually, ty::ProjectionKind::StructField { name }) => { - return Err(handler.emit_err(CompileError::FieldAccessOnNonStruct { - actually: engines.help_out(actually).to_string(), - storage_variable: None, - field_name: name.into(), - span: full_span_for_error, - })); - } - ( - actually, - ty::ProjectionKind::TupleField { - index, index_span, .. - }, - ) => { - return Err( - handler.emit_err(CompileError::TupleElementAccessOnNonTuple { - actually: engines.help_out(actually).to_string(), - span: full_span_for_error, - index: *index, - index_span: index_span.clone(), - }), - ); - } - (actually, ty::ProjectionKind::ArrayIndex { .. }) => { - return Err(handler.emit_err(CompileError::NotIndexable { - actually: engines.help_out(actually).to_string(), - span: full_span_for_error, - })); - } - } - } - Ok((symbol, parent_rover)) - } } fn get_path_for_decl( diff --git a/sway-core/src/semantic_analysis/namespace/mod.rs b/sway-core/src/semantic_analysis/namespace/mod.rs index 5fba8b2d90e..8947e8495b0 100644 --- a/sway-core/src/semantic_analysis/namespace/mod.rs +++ b/sway-core/src/semantic_analysis/namespace/mod.rs @@ -17,7 +17,7 @@ pub(super) use trait_map::CodeBlockFirstPass; pub(super) use trait_map::IsExtendingExistingImpl; pub(super) use trait_map::IsImplSelf; pub(super) use trait_map::ResolvedTraitImplItem; -pub(super) use trait_map::TraitMap; +pub use trait_map::TraitMap; pub use trait_map::TryInsertingTraitImplOnFailure; use sway_types::Ident; diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index 77aa192b3be..319f4abb247 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -1,9 +1,14 @@ -use crate::{engine_threading::Engines, language::Visibility, Ident}; +use crate::{ + engine_threading::Engines, + language::{ty, Visibility}, + Ident, TypeId, +}; use super::{ - lexical_scope::{Items, LexicalScope}, + lexical_scope::{Items, LexicalScope, ResolvedFunctionDecl}, root::Root, - LexicalScopeId, ModuleName, ModulePath, ModulePathBuf, + LexicalScopeId, ModuleName, ModulePath, ModulePathBuf, ResolvedDeclaration, + ResolvedTraitImplItem, }; use rustc_hash::FxHasher; @@ -215,6 +220,14 @@ impl Module { .unwrap() } + pub fn get_lexical_scope(&self, id: LexicalScopeId) -> Option<&LexicalScope> { + self.lexical_scopes.get(id) + } + + pub fn get_lexical_scope_mut(&mut self, id: LexicalScopeId) -> Option<&mut LexicalScope> { + self.lexical_scopes.get_mut(id) + } + /// Returns the current lexical scope associated with this module. pub fn current_lexical_scope(&self) -> &LexicalScope { self.lexical_scopes @@ -285,6 +298,82 @@ impl Module { let parent_scope_id = self.current_lexical_scope().parent; self.current_lexical_scope_id = parent_scope_id.unwrap_or(0); } + + pub fn walk_scope_chain( + &self, + mut f: impl FnMut(&LexicalScope) -> Result, ErrorEmitted>, + ) -> Result, ErrorEmitted> { + let mut lexical_scope_opt = Some(self.current_lexical_scope()); + while let Some(lexical_scope) = lexical_scope_opt { + let result = f(lexical_scope)?; + if let Some(result) = result { + return Ok(Some(result)); + } + if let Some(parent_scope_id) = lexical_scope.parent { + lexical_scope_opt = self.get_lexical_scope(parent_scope_id); + } else { + lexical_scope_opt = None; + } + } + Ok(None) + } + + pub fn get_items_for_type( + &self, + engines: &Engines, + type_id: TypeId, + ) -> Vec { + let mut vec = vec![]; + let _ = self.walk_scope_chain(|lexical_scope| { + vec.extend( + lexical_scope + .items + .implemented_traits + .get_items_for_type(engines, type_id), + ); + Ok(Some(())) + }); + vec + } + + pub fn resolve_symbol( + &self, + handler: &Handler, + engines: &Engines, + symbol: &Ident, + ) -> Result { + let ret = self.walk_scope_chain(|lexical_scope| { + lexical_scope.items.resolve_symbol(handler, engines, symbol) + })?; + + if let Some(ret) = ret { + Ok(ret) + } else { + // Symbol not found + Err(handler.emit_err(CompileError::SymbolNotFound { + name: symbol.clone(), + span: symbol.span(), + })) + } + } + + pub fn get_methods_for_type( + &self, + engines: &Engines, + type_id: TypeId, + ) -> Vec { + self.get_items_for_type(engines, type_id) + .into_iter() + .filter_map(|item| match item { + ResolvedTraitImplItem::Parsed(_) => unreachable!(), + ResolvedTraitImplItem::Typed(item) => match item { + ty::TyTraitItem::Fn(decl_ref) => Some(ResolvedFunctionDecl::Typed(decl_ref)), + ty::TyTraitItem::Constant(_decl_ref) => None, + ty::TyTraitItem::Type(_decl_ref) => None, + }, + }) + .collect::>() + } } impl From for Module { diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index e37c30dfd61..9eb5e8b3439 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -27,9 +27,11 @@ use crate::{ TypeSubstMap, UnifyCheck, }; +use super::Module; + /// Enum used to pass a value asking for insertion of type into trait map when an implementation /// of the trait cannot be found. -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum TryInsertingTraitImplOnFailure { Yes, No, @@ -189,7 +191,7 @@ enum TypeRootFilter { /// Note: "impl self" blocks are considered traits and are stored in the /// [TraitMap]. #[derive(Clone, Debug, Default)] -pub(crate) struct TraitMap { +pub struct TraitMap { trait_impls: TraitImpls, satisfied_cache: im::HashSet, } @@ -1326,8 +1328,8 @@ impl TraitMap { /// Checks to see if the trait constraints are satisfied for a given type. #[allow(clippy::too_many_arguments)] pub(crate) fn check_if_trait_constraints_are_satisfied_for_type( - &mut self, handler: &Handler, + module: &mut Module, type_id: TypeId, constraints: &[TraitConstraint], access_span: &Span, @@ -1352,42 +1354,61 @@ impl TraitMap { } let hash = hasher.finish(); - if self.satisfied_cache.contains(&hash) { - return Ok(()); + { + let trait_map = &mut module.current_lexical_scope_mut().items.implemented_traits; + if trait_map.satisfied_cache.contains(&hash) { + return Ok(()); + } } + let all_impld_traits: BTreeSet<(Ident, TypeId)> = + Self::get_all_implemented_traits(module, type_id, engines); + // Call the real implementation and cache when true - match self.check_if_trait_constraints_are_satisfied_for_type_inner( + match Self::check_if_trait_constraints_are_satisfied_for_type_inner( handler, + module, type_id, constraints, access_span, engines, + all_impld_traits, try_inserting_trait_impl_on_failure, code_block_first_pass, ) { Ok(()) => { - self.satisfied_cache.insert(hash); + let trait_map = &mut module.current_lexical_scope_mut().items.implemented_traits; + trait_map.satisfied_cache.insert(hash); Ok(()) } r => r, } } - #[allow(clippy::too_many_arguments)] - fn check_if_trait_constraints_are_satisfied_for_type_inner( - &mut self, - handler: &Handler, + fn get_all_implemented_traits( + module: &Module, type_id: TypeId, - constraints: &[TraitConstraint], - access_span: &Span, engines: &Engines, - try_inserting_trait_impl_on_failure: TryInsertingTraitImplOnFailure, - code_block_first_pass: CodeBlockFirstPass, - ) -> Result<(), ErrorEmitted> { - let type_engine = engines.te(); + ) -> BTreeSet<(Ident, TypeId)> { + let mut all_impld_traits: BTreeSet<(Ident, TypeId)> = Default::default(); + let _ = module.walk_scope_chain(|lexical_scope| { + all_impld_traits.extend( + lexical_scope + .items + .implemented_traits + .get_implemented_traits(type_id, engines), + ); + Ok(Some(())) + }); + all_impld_traits + } - let _decl_engine = engines.de(); + fn get_implemented_traits( + &self, + type_id: TypeId, + engines: &Engines, + ) -> BTreeSet<(Ident, TypeId)> { + let type_engine = engines.te(); let unify_check = UnifyCheck::non_dynamic_equality(engines); let impls = self.get_impls(engines, type_id); @@ -1413,6 +1434,24 @@ impl TraitMap { }) .collect(); + all_impld_traits + } + + #[allow(clippy::too_many_arguments)] + fn check_if_trait_constraints_are_satisfied_for_type_inner( + handler: &Handler, + module: &mut Module, + type_id: TypeId, + constraints: &[TraitConstraint], + access_span: &Span, + engines: &Engines, + all_impld_traits: BTreeSet<(Ident, TypeId)>, + try_inserting_trait_impl_on_failure: TryInsertingTraitImplOnFailure, + code_block_first_pass: CodeBlockFirstPass, + ) -> Result<(), ErrorEmitted> { + let type_engine = engines.te(); + let unify_check = UnifyCheck::non_dynamic_equality(engines); + let required_traits: BTreeSet<(Ident, TypeId)> = constraints .iter() .map(|c| { @@ -1451,9 +1490,13 @@ impl TraitMap { try_inserting_trait_impl_on_failure, TryInsertingTraitImplOnFailure::Yes ) { - self.insert_for_type(engines, type_id, code_block_first_pass.clone()); - return self.check_if_trait_constraints_are_satisfied_for_type( + let trait_map = + &mut module.current_lexical_scope_mut().items.implemented_traits; + trait_map.insert_for_type(engines, type_id, code_block_first_pass.clone()); + + return Self::check_if_trait_constraints_are_satisfied_for_type( handler, + module, type_id, constraints, access_span, diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index 0c9827a2f1d..72eec9b4822 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -774,9 +774,7 @@ impl<'a> TypeCheckContext<'a> { )?; // grab the local items from the local module - let local_items = local_module - .current_items() - .get_items_for_type(self.engines, type_id); + let local_items = local_module.get_items_for_type(self.engines, type_id); // resolve the type let type_id = resolve_type( @@ -802,9 +800,7 @@ impl<'a> TypeCheckContext<'a> { )?; // grab the items from where the type is declared - let mut type_items = type_module - .current_items() - .get_items_for_type(self.engines, type_id); + let mut type_items = type_module.get_items_for_type(self.engines, type_id); let mut items = local_items; items.append(&mut type_items); @@ -1429,19 +1425,16 @@ impl<'a> TypeCheckContext<'a> { let handler = Handler::default(); let engines = self.engines; let code_block_first_pass = self.code_block_first_pass(); - self.namespace_mut() - .module_mut(engines) - .current_items_mut() - .implemented_traits - .check_if_trait_constraints_are_satisfied_for_type( - &handler, - type_id, - constraints, - &Span::dummy(), - engines, - crate::namespace::TryInsertingTraitImplOnFailure::Yes, - code_block_first_pass.into(), - ) - .is_ok() + TraitMap::check_if_trait_constraints_are_satisfied_for_type( + &handler, + self.namespace_mut().module_mut(engines), + type_id, + constraints, + &Span::dummy(), + engines, + crate::namespace::TryInsertingTraitImplOnFailure::Yes, + code_block_first_pass.into(), + ) + .is_ok() } } diff --git a/sway-core/src/semantic_analysis/type_resolve.rs b/sway-core/src/semantic_analysis/type_resolve.rs index 06279dfceb5..174817fdb5f 100644 --- a/sway-core/src/semantic_analysis/type_resolve.rs +++ b/sway-core/src/semantic_analysis/type_resolve.rs @@ -363,12 +363,7 @@ fn resolve_symbol_and_mod_path( current_mod_path.push(ident.clone()); } None => { - decl_opt = Some( - current_module - .current_lexical_scope() - .items - .resolve_symbol(handler, engines, ident)?, - ); + decl_opt = Some(current_module.resolve_symbol(handler, engines, ident)?); } } } @@ -389,10 +384,7 @@ fn resolve_symbol_and_mod_path( module .lookup_submodule(handler, engines, mod_path) .and_then(|module| { - let decl = module - .current_lexical_scope() - .items - .resolve_symbol(handler, engines, symbol)?; + let decl = module.resolve_symbol(handler, engines, symbol)?; Ok((decl, mod_path.to_vec())) }) } diff --git a/sway-core/src/type_system/ast_elements/type_parameter.rs b/sway-core/src/type_system/ast_elements/type_parameter.rs index d924c7f387b..9f3d24cac81 100644 --- a/sway-core/src/type_system/ast_elements/type_parameter.rs +++ b/sway-core/src/type_system/ast_elements/type_parameter.rs @@ -3,7 +3,7 @@ use crate::{ engine_threading::*, has_changes, language::{ty, CallPath}, - namespace::TryInsertingTraitImplOnFailure, + namespace::{TraitMap, TryInsertingTraitImplOnFailure}, semantic_analysis::{GenericShadowingMode, TypeCheckContext}, type_system::priv_prelude::*, }; @@ -444,13 +444,11 @@ impl TypeParameter { if *is_from_parent { ctx = ctx.with_generic_shadowing_mode(GenericShadowingMode::Allow); - let sy = ctx - .namespace() - .module(ctx.engines()) - .current_items() - .symbols - .get(name) - .unwrap(); + let sy = ctx.namespace().module(ctx.engines()).resolve_symbol( + handler, + ctx.engines(), + name, + )?; match sy.expect_typed_ref() { ty::TyDecl::GenericTypeForFunctionScope(ty::GenericTypeForFunctionScope { @@ -571,13 +569,9 @@ impl TypeParameter { } } // Check to see if the trait constraints are satisfied. - match ctx - .namespace_mut() - .module_mut(engines) - .current_items_mut() - .implemented_traits - .check_if_trait_constraints_are_satisfied_for_type( + match TraitMap::check_if_trait_constraints_are_satisfied_for_type( handler, + ctx.namespace_mut().module_mut(engines), *type_id, trait_constraints, access_span, diff --git a/sway-lsp/src/capabilities/completion.rs b/sway-lsp/src/capabilities/completion.rs index a2b77814cb9..8c057a20675 100644 --- a/sway-lsp/src/capabilities/completion.rs +++ b/sway-lsp/src/capabilities/completion.rs @@ -5,12 +5,11 @@ use lsp_types::{ }; use sway_core::{ language::ty::{TyAstNodeContent, TyDecl, TyFunctionDecl, TyFunctionParameter}, - namespace::Items, - Engines, TypeId, TypeInfo, + Engines, Namespace, TypeId, TypeInfo, }; pub(crate) fn to_completion_items( - namespace: &Items, + namespace: &Namespace, engines: &Engines, ident_to_complete: &TokenIdent, fn_decl: &TyFunctionDecl, @@ -24,7 +23,7 @@ pub(crate) fn to_completion_items( /// Gathers the given [`TypeId`] struct's fields and methods and builds completion items. fn completion_items_for_type_id( engines: &Engines, - namespace: &Items, + namespace: &Namespace, type_id: TypeId, position: Position, ) -> Vec { @@ -46,7 +45,10 @@ fn completion_items_for_type_id( } } - for method in namespace.get_methods_for_type(engines, type_id) { + for method in namespace + .module(engines) + .get_methods_for_type(engines, type_id) + { let method = method.expect_typed(); let fn_decl = engines.de().get_function(&method.id().clone()); let params = &fn_decl.parameters; @@ -134,7 +136,7 @@ fn replace_self_with_type_str( /// if it can resolve `a` in the given function. fn type_id_of_raw_ident( engines: &Engines, - namespace: &Items, + namespace: &Namespace, ident_name: &str, fn_decl: &TyFunctionDecl, ) -> Option { @@ -152,6 +154,7 @@ fn type_id_of_raw_ident( if parts[i].ends_with(')') { let method_name = parts[i].split_at(parts[i].find('(').unwrap_or(0)).0; curr_type_id = namespace + .module(engines) .get_methods_for_type(engines, curr_type_id?) .into_iter() .find_map(|method| { diff --git a/sway-lsp/src/core/session.rs b/sway-lsp/src/core/session.rs index 26f0bccb4b6..864cac9811a 100644 --- a/sway-lsp/src/core/session.rs +++ b/sway-lsp/src/core/session.rs @@ -231,7 +231,7 @@ impl Session { let program = compiled_program.typed.clone()?; let engines = self.engines.read(); return Some(capabilities::completion::to_completion_items( - program.root.namespace.module(&engines).current_items(), + &program.root.namespace, &engines, ident_to_complete, fn_decl, From 48f633df63896193a1a394ff54db5cd15821a603 Mon Sep 17 00:00:00 2001 From: Joshua Batty Date: Wed, 4 Dec 2024 09:17:30 +1100 Subject: [PATCH 35/52] refactor: Improve DAP server code organisation and readability (#6770) ## Description This PR improves the organization and readability of the forc-debug codebase through several changes: - Moves CLI functionality into a dedicated CLI module - Creates a unified error handling system using `thiserror` - Improves command handler organization and readability - Extracts common functionality into reusable helper methods - Adds clear documentation for public interfaces - Introduces the `HandlerResult` type to simplify DAP server response handling - Implements consistent error propagation throughout the codebase - Ran clippy pedantic Improvements: - Better separation of concerns between CLI and server code - More descriptive error messages with proper context - Cleaner command handling ## Checklist - [ ] 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). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --- forc-plugins/forc-debug/src/cli.rs | 332 ++++++++++ forc-plugins/forc-debug/src/error.rs | 106 ++++ forc-plugins/forc-debug/src/lib.rs | 2 + forc-plugins/forc-debug/src/main.rs | 280 +-------- forc-plugins/forc-debug/src/names.rs | 27 + forc-plugins/forc-debug/src/server/error.rs | 39 -- .../handlers/handle_breakpoint_locations.rs | 37 +- .../src/server/handlers/handle_continue.rs | 9 - .../src/server/handlers/handle_launch.rs | 183 ------ .../src/server/handlers/handle_next.rs | 9 - .../server/handlers/handle_set_breakpoints.rs | 63 +- .../src/server/handlers/handle_stack_trace.rs | 25 +- .../src/server/handlers/handle_variables.rs | 41 +- .../forc-debug/src/server/handlers/mod.rs | 129 +++- forc-plugins/forc-debug/src/server/mod.rs | 565 +++++++++++------- forc-plugins/forc-debug/src/server/state.rs | 15 +- forc-plugins/forc-debug/src/server/util.rs | 3 + forc-plugins/forc-debug/src/types.rs | 5 +- .../forc-debug/tests/server_integration.rs | 97 ++- 19 files changed, 1117 insertions(+), 850 deletions(-) create mode 100644 forc-plugins/forc-debug/src/cli.rs create mode 100644 forc-plugins/forc-debug/src/error.rs delete mode 100644 forc-plugins/forc-debug/src/server/error.rs delete mode 100644 forc-plugins/forc-debug/src/server/handlers/handle_continue.rs delete mode 100644 forc-plugins/forc-debug/src/server/handlers/handle_launch.rs delete mode 100644 forc-plugins/forc-debug/src/server/handlers/handle_next.rs diff --git a/forc-plugins/forc-debug/src/cli.rs b/forc-plugins/forc-debug/src/cli.rs new file mode 100644 index 00000000000..6705c5b8b8f --- /dev/null +++ b/forc-plugins/forc-debug/src/cli.rs @@ -0,0 +1,332 @@ +use crate::{ + error::{ArgumentError, Error, Result}, + names::{register_index, register_name}, + ContractId, FuelClient, RunResult, Transaction, +}; +use fuel_vm::consts::{VM_MAX_RAM, VM_REGISTER_COUNT, WORD_SIZE}; +use shellfish::{handler::DefaultAsyncHandler, input_handler::IO, Command as ShCommand, Shell}; + +pub struct State { + client: FuelClient, + session_id: String, +} + +/// Start the CLI debug interface +pub async fn start_cli(api_url: &str) -> Result<()> { + let mut shell = Shell::new_async( + State { + client: FuelClient::new(api_url).map_err(|e| Error::FuelClientError(e.to_string()))?, + session_id: String::new(), // Placeholder + }, + ">> ", + ); + + register_commands(&mut shell); + + let session_id = shell + .state + .client + .start_session() + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + shell.state.session_id.clone_from(&session_id); + + shell + .run_async() + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + shell + .state + .client + .end_session(&session_id) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + Ok(()) +} + +fn register_commands(shell: &mut Shell<'_, State, &str, DefaultAsyncHandler, IO>) { + // Registers an async command by wrapping the handler function `$f`, + // converting its error type into `Box`, and + // associating it with the provided command names. + macro_rules! command { + ($f:ident, $help:literal, $names:expr) => { + for c in $names { + shell.commands.insert( + c, + ShCommand::new_async($help.to_string(), |state, args| { + Box::pin(async move { + $f(state, args) + .await + .map_err(|e| Box::new(e) as Box) + }) + }), + ); + } + }; + } + + command!( + cmd_start_tx, + "path/to/tx.json -- start a new transaction", + ["n", "tx", "new_tx", "start_tx"] + ); + command!( + cmd_reset, + "-- reset, removing breakpoints and other state", + ["reset"] + ); + command!( + cmd_continue, + "-- run until next breakpoint or termination", + ["c", "continue"] + ); + command!( + cmd_step, + "[on|off] -- turn single-stepping on or off", + ["s", "step"] + ); + command!( + cmd_breakpoint, + "[contract_id] offset -- set a breakpoint", + ["b", "breakpoint"] + ); + command!( + cmd_registers, + "[regname ...] -- dump registers", + ["r", "reg", "register", "registers"] + ); + command!(cmd_memory, "[offset] limit -- dump memory", ["m", "memory"]); +} + +async fn cmd_start_tx(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove the command name + ArgumentError::ensure_arg_count(&args, 1, 1)?; // Ensure exactly one argument + + let path_to_tx_json = args.pop().unwrap(); // Safe due to arg count check + + // Read and parse the transaction JSON + let tx_json = std::fs::read(&path_to_tx_json).map_err(Error::IoError)?; + let tx: Transaction = serde_json::from_slice(&tx_json).map_err(Error::JsonError)?; + + // Start the transaction + let status = state + .client + .start_tx(&state.session_id, &tx) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + pretty_print_run_result(&status); + Ok(()) +} + +async fn cmd_reset(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove the command name + ArgumentError::ensure_arg_count(&args, 0, 0)?; // Ensure no extra arguments + + // Reset the session + state + .client + .reset(&state.session_id) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + Ok(()) +} + +async fn cmd_continue(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove the command name + ArgumentError::ensure_arg_count(&args, 0, 0)?; // Ensure no extra arguments + + // Continue the transaction + let status = state + .client + .continue_tx(&state.session_id) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + pretty_print_run_result(&status); + Ok(()) +} + +async fn cmd_step(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove the command name + ArgumentError::ensure_arg_count(&args, 0, 1)?; // Ensure the argument count is at most 1 + + // Determine whether to enable or disable single stepping + let enable = args + .first() + .map_or(true, |v| !["off", "no", "disable"].contains(&v.as_str())); + + // Call the client + state + .client + .set_single_stepping(&state.session_id, enable) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + Ok(()) +} + +async fn cmd_breakpoint(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove command name + ArgumentError::ensure_arg_count(&args, 1, 2)?; + + let offset_str = args.pop().unwrap(); // Safe due to arg count check + let offset = parse_int(&offset_str).ok_or(ArgumentError::InvalidNumber(offset_str))?; + + let contract = if let Some(contract_id) = args.pop() { + contract_id + .parse::() + .map_err(|_| ArgumentError::Invalid(format!("Invalid contract ID: {}", contract_id)))? + } else { + ContractId::zeroed() + }; + + // Call client + state + .client + .set_breakpoint(&state.session_id, contract, offset as u64) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + Ok(()) +} + +async fn cmd_registers(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove the command name + + if args.is_empty() { + // Print all registers + for r in 0..VM_REGISTER_COUNT { + let value = state + .client + .register(&state.session_id, r as u32) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + println!("reg[{:#x}] = {:<8} # {}", r, value, register_name(r)); + } + } else { + // Process specific registers provided as arguments + for arg in &args { + if let Some(v) = parse_int(arg) { + if v < VM_REGISTER_COUNT { + let value = state + .client + .register(&state.session_id, v as u32) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + println!("reg[{:#02x}] = {:<8} # {}", v, value, register_name(v)); + } else { + return Err(ArgumentError::InvalidNumber(format!( + "Register index too large: {v}" + )) + .into()); + } + } else if let Some(index) = register_index(arg) { + let value = state + .client + .register(&state.session_id, index as u32) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + println!("reg[{index:#02x}] = {value:<8} # {arg}"); + } else { + return Err(ArgumentError::Invalid(format!("Unknown register name: {arg}")).into()); + } + } + } + Ok(()) +} + +async fn cmd_memory(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove the command name + + // Parse limit argument or use the default + let limit = args + .pop() + .map(|a| parse_int(&a).ok_or(ArgumentError::InvalidNumber(a))) + .transpose()? + .unwrap_or(WORD_SIZE * (VM_MAX_RAM as usize)); + + // Parse offset argument or use the default + let offset = args + .pop() + .map(|a| parse_int(&a).ok_or(ArgumentError::InvalidNumber(a))) + .transpose()? + .unwrap_or(0); + + // Ensure no extra arguments + ArgumentError::ensure_arg_count(&args, 0, 0)?; + + // Fetch memory from the client + let mem = state + .client + .memory(&state.session_id, offset as u32, limit as u32) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + // Print memory contents + for (i, chunk) in mem.chunks(WORD_SIZE).enumerate() { + print!(" {:06x}:", offset + i * WORD_SIZE); + for byte in chunk { + print!(" {byte:02x}"); + } + println!(); + } + Ok(()) +} + +/// Pretty-prints the result of a run, including receipts and breakpoint information. +/// +/// Outputs each receipt in the `RunResult` and details about the breakpoint if present. +/// If the execution terminated without hitting a breakpoint, it prints "Terminated". +fn pretty_print_run_result(rr: &RunResult) { + for receipt in rr.receipts() { + println!("Receipt: {receipt:?}"); + } + if let Some(bp) = &rr.breakpoint { + println!( + "Stopped on breakpoint at address {} of contract {}", + bp.pc.0, bp.contract + ); + } else { + println!("Terminated"); + } +} + +/// Parses a string representing a number and returns it as a `usize`. +/// +/// The input string can be in decimal or hexadecimal format: +/// - Decimal numbers are parsed normally (e.g., `"123"`). +/// - Hexadecimal numbers must be prefixed with `"0x"` (e.g., `"0x7B"`). +/// - Underscores can be used as visual separators (e.g., `"1_000"` or `"0x1_F4"`). +/// +/// If the input string is not a valid number in the specified format, `None` is returned. +/// +/// # Examples +/// +/// ``` +/// use forc_debug::cli::parse_int; +/// /// Use underscores as separators in decimal and hexadecimal numbers +/// assert_eq!(parse_int("123"), Some(123)); +/// assert_eq!(parse_int("1_000"), Some(1000)); +/// +/// /// Parse hexadecimal numbers with "0x" prefix +/// assert_eq!(parse_int("0x7B"), Some(123)); +/// assert_eq!(parse_int("0x1_F4"), Some(500)); +/// +/// /// Handle invalid inputs gracefully +/// assert_eq!(parse_int("abc"), None); +/// assert_eq!(parse_int("0xZZZ"), None); +/// assert_eq!(parse_int(""), None); +/// ``` +/// +/// # Errors +/// +/// Returns `None` if the input string contains invalid characters, +/// is not properly formatted, or cannot be parsed into a `usize`. +pub fn parse_int(s: &str) -> Option { + let (s, radix) = s.strip_prefix("0x").map_or((s, 10), |s| (s, 16)); + usize::from_str_radix(&s.replace('_', ""), radix).ok() +} diff --git a/forc-plugins/forc-debug/src/error.rs b/forc-plugins/forc-debug/src/error.rs new file mode 100644 index 00000000000..8f9f76fe114 --- /dev/null +++ b/forc-plugins/forc-debug/src/error.rs @@ -0,0 +1,106 @@ +use crate::types::Instruction; +use dap::requests::Command; + +pub type Result = std::result::Result; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error(transparent)] + ArgumentError(#[from] ArgumentError), + + #[error(transparent)] + AdapterError(#[from] AdapterError), + + #[error("VM error: {0}")] + VMError(String), + + #[error("Fuel Client error: {0}")] + FuelClientError(String), + + #[error("Session error: {0}")] + SessionError(String), + + #[error("I/O error")] + IoError(std::io::Error), + + #[error("Json error")] + JsonError(#[from] serde_json::Error), + + #[error("Server error: {0}")] + DapServerError(#[from] dap::errors::ServerError), +} + +#[derive(Debug, thiserror::Error)] +pub enum ArgumentError { + #[error("Invalid argument: {0}")] + Invalid(String), + + #[error("Not enough arguments, expected {expected} but got {got}")] + NotEnough { expected: usize, got: usize }, + + #[error("Too many arguments, expected {expected} but got {got}")] + TooMany { expected: usize, got: usize }, + + #[error("Invalid number format: {0}")] + InvalidNumber(String), +} + +#[derive(Debug, thiserror::Error)] +pub enum AdapterError { + #[error("Unhandled command")] + UnhandledCommand { command: Command }, + + #[error("Missing command")] + MissingCommand, + + #[error("Missing configuration")] + MissingConfiguration, + + #[error("Missing source path argument")] + MissingSourcePathArgument, + + #[error("Missing breakpoint location")] + MissingBreakpointLocation, + + #[error("Missing source map")] + MissingSourceMap { pc: Instruction }, + + #[error("Unknown breakpoint")] + UnknownBreakpoint { pc: Instruction }, + + #[error("Build failed")] + BuildFailed { reason: String }, + + #[error("No active test executor")] + NoActiveTestExecutor, + + #[error("Test execution failed")] + TestExecutionFailed { + #[from] + source: anyhow::Error, + }, +} + +impl ArgumentError { + /// Ensures argument count falls within [min, max] range. + pub fn ensure_arg_count( + args: &[String], + min: usize, + max: usize, + ) -> std::result::Result<(), ArgumentError> { + let count = args.len(); + if count < min { + Err(ArgumentError::NotEnough { + expected: min, + got: count, + }) + } else if count > max { + Err(ArgumentError::TooMany { + expected: max, + got: count, + }) + } else { + Ok(()) + } + } +} diff --git a/forc-plugins/forc-debug/src/lib.rs b/forc-plugins/forc-debug/src/lib.rs index e611ae3052c..a98036d815e 100644 --- a/forc-plugins/forc-debug/src/lib.rs +++ b/forc-plugins/forc-debug/src/lib.rs @@ -1,3 +1,5 @@ +pub mod cli; +pub mod error; pub mod names; pub mod server; pub mod types; diff --git a/forc-plugins/forc-debug/src/main.rs b/forc-plugins/forc-debug/src/main.rs index 7bf6a13b81a..da60d35a70b 100644 --- a/forc-plugins/forc-debug/src/main.rs +++ b/forc-plugins/forc-debug/src/main.rs @@ -1,13 +1,5 @@ use clap::Parser; -use forc_debug::{ - names::{register_index, register_name}, - server::DapServer, - ContractId, FuelClient, RunResult, Transaction, -}; -use forc_tracing::{init_tracing_subscriber, println_error}; -use fuel_vm::consts::{VM_MAX_RAM, VM_REGISTER_COUNT, WORD_SIZE}; -use shellfish::{async_fn, Command as ShCommand, Shell}; -use std::error::Error; +use forc_tracing::{init_tracing_subscriber, println_error, TracingSubscriberOptions}; #[derive(Parser, Debug)] #[clap(name = "forc-debug", version)] @@ -23,273 +15,17 @@ pub struct Opt { #[tokio::main] async fn main() { - init_tracing_subscriber(Default::default()); + init_tracing_subscriber(TracingSubscriberOptions::default()); let config = Opt::parse(); - if let Err(err) = run(&config).await { - println_error(&format!("{}", err)); - std::process::exit(1); - } -} - -async fn run(config: &Opt) -> Result<(), Box> { - if config.serve { - return DapServer::default().start(); - } - - let mut shell = Shell::new_async( - State { - client: FuelClient::new(&config.api_url)?, - session_id: String::new(), // Placeholder - }, - ">> ", - ); - - macro_rules! command { - ($f:ident, $help:literal, $names:expr) => { - for c in $names { - shell.commands.insert( - c, - ShCommand::new_async($help.to_string(), async_fn!(State, $f)), - ); - } - }; - } - - command!( - cmd_start_tx, - "path/to/tx.json -- start a new transaction", - ["n", "tx", "new_tx", "start_tx"] - ); - command!( - cmd_reset, - "-- reset, removing breakpoints and other state", - ["reset"] - ); - command!( - cmd_continue, - "-- run until next breakpoint or termination", - ["c", "continue"] - ); - command!( - cmd_step, - "[on|off] -- turn single-stepping on or off", - ["s", "step"] - ); - command!( - cmd_breakpoint, - "[contract_id] offset -- set a breakpoint", - ["b", "breakpoint"] - ); - command!( - cmd_registers, - "[regname ...] -- dump registers", - ["r", "reg", "register", "registers"] - ); - command!(cmd_memory, "[offset] limit -- dump memory", ["m", "memory"]); - - let session_id = shell.state.client.start_session().await?; - shell.state.session_id.clone_from(&session_id); - shell.run_async().await?; - shell.state.client.end_session(&session_id).await?; - Ok(()) -} - -struct State { - client: FuelClient, - session_id: String, -} - -#[derive(Debug, thiserror::Error)] -enum ArgError { - #[error("Invalid argument")] - Invalid, - #[error("Not enough arguments")] - NotEnough, - #[error("Too many arguments")] - TooMany, -} - -fn pretty_print_run_result(rr: &RunResult) { - for receipt in rr.receipts() { - println!("Receipt: {:?}", receipt); - } - if let Some(bp) = &rr.breakpoint { - println!( - "Stopped on breakpoint at address {} of contract {}", - bp.pc.0, bp.contract - ); + let result = if config.serve { + forc_debug::server::DapServer::default().start() } else { - println!("Terminated"); - } -} - -async fn cmd_start_tx(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - let path_to_tx_json = args.pop().ok_or_else(|| Box::new(ArgError::NotEnough))?; - if !args.is_empty() { - return Err(Box::new(ArgError::TooMany)); - } - - let tx_json = std::fs::read(path_to_tx_json)?; - let tx: Transaction = serde_json::from_slice(&tx_json)?; - let status = state.client.start_tx(&state.session_id, &tx).await?; - pretty_print_run_result(&status); - - Ok(()) -} - -async fn cmd_reset(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - if !args.is_empty() { - return Err(Box::new(ArgError::TooMany)); - } - - let _ = state.client.reset(&state.session_id).await?; - - Ok(()) -} - -async fn cmd_continue(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - if !args.is_empty() { - return Err(Box::new(ArgError::TooMany)); - } - - let status = state.client.continue_tx(&state.session_id).await?; - pretty_print_run_result(&status); - - Ok(()) -} - -async fn cmd_step(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - if args.len() > 1 { - return Err(Box::new(ArgError::TooMany)); - } - - state - .client - .set_single_stepping( - &state.session_id, - args.first() - .map(|v| !["off", "no", "disable"].contains(&v.as_str())) - .unwrap_or(true), - ) - .await?; - Ok(()) -} - -async fn cmd_breakpoint(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - let offset = args.pop().ok_or_else(|| Box::new(ArgError::NotEnough))?; - let contract_id = args.pop(); - - if !args.is_empty() { - return Err(Box::new(ArgError::TooMany)); - } - - let offset = if let Some(offset) = parse_int(&offset) { - offset as u64 - } else { - return Err(Box::new(ArgError::Invalid)); + forc_debug::cli::start_cli(&config.api_url).await }; - let contract = if let Some(contract_id) = contract_id { - if let Ok(contract_id) = contract_id.parse::() { - contract_id - } else { - return Err(Box::new(ArgError::Invalid)); - } - } else { - ContractId::zeroed() // Current script - }; - - state - .client - .set_breakpoint(&state.session_id, contract, offset) - .await?; - - Ok(()) -} - -async fn cmd_registers(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - - if args.is_empty() { - for r in 0..VM_REGISTER_COUNT { - let value = state.client.register(&state.session_id, r as u32).await?; - println!("reg[{:#x}] = {:<8} # {}", r, value, register_name(r)); - } - } else { - for arg in &args { - if let Some(v) = parse_int(arg) { - if v < VM_REGISTER_COUNT { - let value = state.client.register(&state.session_id, v as u32).await?; - println!("reg[{:#02x}] = {:<8} # {}", v, value, register_name(v)); - } else { - println!("Register index too large {}", v); - return Ok(()); - } - } else if let Some(index) = register_index(arg) { - let value = state - .client - .register(&state.session_id, index as u32) - .await?; - println!("reg[{:#02x}] = {:<8} # {}", index, value, arg); - } else { - println!("Unknown register name {}", arg); - return Ok(()); - } - } - } - - Ok(()) -} - -async fn cmd_memory(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - - let limit = args - .pop() - .map(|a| parse_int(&a).ok_or(ArgError::Invalid)) - .transpose()? - .unwrap_or(WORD_SIZE * (VM_MAX_RAM as usize)); - - let offset = args - .pop() - .map(|a| parse_int(&a).ok_or(ArgError::Invalid)) - .transpose()? - .unwrap_or(0); - - if !args.is_empty() { - return Err(Box::new(ArgError::TooMany)); - } - - let mem = state - .client - .memory(&state.session_id, offset as u32, limit as u32) - .await?; - - for (i, chunk) in mem.chunks(WORD_SIZE).enumerate() { - print!(" {:06x}:", offset + i * WORD_SIZE); - for byte in chunk { - print!(" {:02x}", byte); - } - println!(); + if let Err(err) = result { + println_error(&format!("{err}")); + std::process::exit(1); } - - Ok(()) -} - -fn parse_int(s: &str) -> Option { - let (s, radix) = if let Some(stripped) = s.strip_prefix("0x") { - (stripped, 16) - } else { - (s, 10) - }; - - let s = s.replace('_', ""); - - usize::from_str_radix(&s, radix).ok() } diff --git a/forc-plugins/forc-debug/src/names.rs b/forc-plugins/forc-debug/src/names.rs index 91e8833cbf4..548305e9ba9 100644 --- a/forc-plugins/forc-debug/src/names.rs +++ b/forc-plugins/forc-debug/src/names.rs @@ -1,8 +1,22 @@ +/// A list of predefined register names mapped to their corresponding indices. pub const REGISTERS: [&str; 16] = [ "zero", "one", "of", "pc", "ssp", "sp", "fp", "hp", "err", "ggas", "cgas", "bal", "is", "ret", "retl", "flag", ]; +/// Returns the name of a register given its index. +/// +/// If the index corresponds to a predefined register, the corresponding name +/// from `REGISTERS` is returned. Otherwise, it returns a formatted name +/// like `"reg{index}"`. +/// +/// # Examples +/// +/// ``` +/// use forc_debug::names::register_name; +/// assert_eq!(register_name(0), "zero".to_string()); +/// assert_eq!(register_name(15), "flag".to_string()); +/// ``` pub fn register_name(index: usize) -> String { if index < REGISTERS.len() { REGISTERS[index].to_owned() @@ -11,6 +25,19 @@ pub fn register_name(index: usize) -> String { } } +/// Returns the index of a register given its name. +/// +/// If the name matches a predefined register in `REGISTERS`, the corresponding +/// index is returned. Otherwise, returns `None`. +/// +/// # Examples +/// +/// ``` +/// use forc_debug::names::register_index; +/// assert_eq!(register_index("zero"), Some(0)); +/// assert_eq!(register_index("flag"), Some(15)); +/// assert_eq!(register_index("unknown"), None); +/// ``` pub fn register_index(name: &str) -> Option { REGISTERS.iter().position(|&n| n == name) } diff --git a/forc-plugins/forc-debug/src/server/error.rs b/forc-plugins/forc-debug/src/server/error.rs deleted file mode 100644 index 1307e57bdd1..00000000000 --- a/forc-plugins/forc-debug/src/server/error.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::types::Instruction; -use dap::requests::Command; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum AdapterError { - #[error("Unhandled command")] - UnhandledCommand { command: Command }, - - #[error("Missing command")] - MissingCommand, - - #[error("Missing configuration")] - MissingConfiguration, - - #[error("Missing source path argument")] - MissingSourcePathArgument, - - #[error("Missing breakpoint location")] - MissingBreakpointLocation, - - #[error("Missing source map")] - MissingSourceMap { pc: Instruction }, - - #[error("Unknown breakpoint")] - UnknownBreakpoint { pc: Instruction }, - - #[error("Build failed")] - BuildFailed { reason: String }, - - #[error("No active test executor")] - NoActiveTestExecutor, - - #[error("Test execution failed")] - TestExecutionFailed { - #[from] - source: anyhow::Error, - }, -} diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_breakpoint_locations.rs b/forc-plugins/forc-debug/src/server/handlers/handle_breakpoint_locations.rs index 8d7e37259ab..4d41dd32604 100644 --- a/forc-plugins/forc-debug/src/server/handlers/handle_breakpoint_locations.rs +++ b/forc-plugins/forc-debug/src/server/handlers/handle_breakpoint_locations.rs @@ -1,13 +1,28 @@ -use crate::server::AdapterError; -use crate::server::DapServer; -use dap::requests::BreakpointLocationsArguments; -use dap::types::BreakpointLocation; +use crate::server::{AdapterError, DapServer, HandlerResult}; +use dap::{ + requests::BreakpointLocationsArguments, responses::ResponseBody, types::BreakpointLocation, +}; use std::path::PathBuf; impl DapServer { /// Handles a `breakpoint_locations` request. Returns the list of [BreakpointLocation]s. - pub(crate) fn handle_breakpoint_locations( - &mut self, + pub(crate) fn handle_breakpoint_locations_command( + &self, + args: &BreakpointLocationsArguments, + ) -> HandlerResult { + let result = self.breakpoint_locations(args).map(|breakpoints| { + ResponseBody::BreakpointLocations(dap::responses::BreakpointLocationsResponse { + breakpoints, + }) + }); + match result { + Ok(result) => HandlerResult::ok(result), + Err(e) => HandlerResult::err_with_exit(e, 1), + } + } + + fn breakpoint_locations( + &self, args: &BreakpointLocationsArguments, ) -> Result, AdapterError> { let source_path = args @@ -62,7 +77,7 @@ mod tests { }, ..Default::default() }; - let result = server.handle_breakpoint_locations(&args).expect("success"); + let result = server.breakpoint_locations(&args).expect("success"); assert_eq!(result.len(), 1); assert_eq!(result[0].line, MOCK_LINE); } @@ -70,15 +85,15 @@ mod tests { #[test] #[should_panic(expected = "MissingSourcePathArgument")] fn test_handle_breakpoint_locations_missing_argument() { - let mut server = DapServer::default(); + let server = DapServer::default(); let args = BreakpointLocationsArguments::default(); - server.handle_breakpoint_locations(&args).unwrap(); + server.breakpoint_locations(&args).unwrap(); } #[test] #[should_panic(expected = "MissingBreakpointLocation")] fn test_handle_breakpoint_locations_missing_breakpoint() { - let mut server = DapServer::default(); + let server = DapServer::default(); let args = BreakpointLocationsArguments { source: dap::types::Source { path: Some(MOCK_SOURCE_PATH.into()), @@ -86,6 +101,6 @@ mod tests { }, ..Default::default() }; - server.handle_breakpoint_locations(&args).unwrap(); + server.breakpoint_locations(&args).unwrap(); } } diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_continue.rs b/forc-plugins/forc-debug/src/server/handlers/handle_continue.rs deleted file mode 100644 index 200c7091a9a..00000000000 --- a/forc-plugins/forc-debug/src/server/handlers/handle_continue.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::server::AdapterError; -use crate::server::DapServer; - -impl DapServer { - /// Handles a `continue` request. Returns true if the server should continue running. - pub(crate) fn handle_continue(&mut self) -> Result { - self.continue_debugging_tests(false) - } -} diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_launch.rs b/forc-plugins/forc-debug/src/server/handlers/handle_launch.rs deleted file mode 100644 index 3ae3c2f3539..00000000000 --- a/forc-plugins/forc-debug/src/server/handlers/handle_launch.rs +++ /dev/null @@ -1,183 +0,0 @@ -use crate::server::{AdapterError, DapServer}; -use crate::types::Instruction; -use forc_pkg::manifest::GenericManifestFile; -use forc_pkg::{self, BuildProfile, Built, BuiltPackage, PackageManifestFile}; -use forc_test::execute::TestExecutor; -use forc_test::setup::TestSetup; -use forc_test::BuiltTests; -use std::{collections::HashMap, sync::Arc}; -use sway_types::LineCol; - -impl DapServer { - /// Handles a `launch` request. Returns true if the server should continue running. - pub fn handle_launch(&mut self) -> Result { - // Build tests for the given path. - let (pkg_to_debug, test_setup) = self.build_tests()?; - let entries = pkg_to_debug.bytecode.entries.iter().filter_map(|entry| { - if let Some(test_entry) = entry.kind.test() { - return Some((entry, test_entry)); - } - None - }); - - // Construct a TestExecutor for each test and store it - let executors: Vec = entries - .filter_map(|(entry, test_entry)| { - let offset = u32::try_from(entry.finalized.imm) - .expect("test instruction offset out of range"); - let name = entry.finalized.fn_name.clone(); - if test_entry.file_path.as_path() != self.state.program_path.as_path() { - return None; - } - - TestExecutor::build( - &pkg_to_debug.bytecode.bytes, - offset, - test_setup.clone(), - test_entry, - name.clone(), - ) - .ok() - }) - .collect(); - self.state.init_executors(executors); - - // Start debugging - self.start_debugging_tests(false) - } - - /// Builds the tests at the given [PathBuf] and stores the source maps. - pub(crate) fn build_tests(&mut self) -> Result<(BuiltPackage, TestSetup), AdapterError> { - if let Some(pkg) = &self.state.built_package { - if let Some(setup) = &self.state.test_setup { - return Ok((pkg.clone(), setup.clone())); - } - } - - // 1. Build the packages - let manifest_file = forc_pkg::manifest::ManifestFile::from_dir(&self.state.program_path) - .map_err(|err| AdapterError::BuildFailed { - reason: format!("read manifest file: {:?}", err), - })?; - let pkg_manifest: PackageManifestFile = - manifest_file - .clone() - .try_into() - .map_err(|err: anyhow::Error| AdapterError::BuildFailed { - reason: format!("package manifest: {:?}", err), - })?; - let member_manifests = - manifest_file - .member_manifests() - .map_err(|err| AdapterError::BuildFailed { - reason: format!("member manifests: {:?}", err), - })?; - let lock_path = manifest_file - .lock_path() - .map_err(|err| AdapterError::BuildFailed { - reason: format!("lock path: {:?}", err), - })?; - let build_plan = forc_pkg::BuildPlan::from_lock_and_manifests( - &lock_path, - &member_manifests, - false, - false, - &Default::default(), - ) - .map_err(|err| AdapterError::BuildFailed { - reason: format!("build plan: {:?}", err), - })?; - - let project_name = pkg_manifest.project_name(); - - let outputs = std::iter::once(build_plan.find_member_index(project_name).ok_or( - AdapterError::BuildFailed { - reason: format!("find built project: {}", project_name), - }, - )?) - .collect(); - - let built_packages = forc_pkg::build( - &build_plan, - Default::default(), - &BuildProfile { - optimization_level: sway_core::OptLevel::Opt0, - include_tests: true, - ..Default::default() - }, - &outputs, - &[], - &[], - ) - .map_err(|err| AdapterError::BuildFailed { - reason: format!("build packages: {:?}", err), - })?; - - // 2. Store the source maps - let mut pkg_to_debug: Option<&BuiltPackage> = None; - built_packages.iter().for_each(|(_, built_pkg)| { - if built_pkg.descriptor.manifest_file == pkg_manifest { - pkg_to_debug = Some(built_pkg); - } - let source_map = &built_pkg.source_map; - - let paths = &source_map.paths; - source_map.map.iter().for_each(|(instruction, sm_span)| { - if let Some(path_buf) = paths.get(sm_span.path.0) { - let LineCol { line, .. } = sm_span.range.start; - let (line, instruction) = (line as i64, *instruction as Instruction); - - self.state - .source_map - .entry(path_buf.clone()) - .and_modify(|new_map| { - new_map - .entry(line) - .and_modify(|val| { - // Store the instructions in ascending order - match val.binary_search(&instruction) { - Ok(_) => {} // Ignore duplicates - Err(pos) => val.insert(pos, instruction), - } - }) - .or_insert(vec![instruction]); - }) - .or_insert(HashMap::from([(line, vec![instruction])])); - } else { - self.error(format!( - "Path missing from source map: {:?}", - sm_span.path.0 - )); - } - }); - }); - - // 3. Build the tests - let built_package = pkg_to_debug.ok_or(AdapterError::BuildFailed { - reason: format!("find package: {}", project_name), - })?; - - let built = Built::Package(Arc::from(built_package.clone())); - - let built_tests = BuiltTests::from_built(built, &build_plan).map_err(|err| { - AdapterError::BuildFailed { - reason: format!("build tests: {:?}", err), - } - })?; - - let pkg_tests = match built_tests { - BuiltTests::Package(pkg_tests) => pkg_tests, - BuiltTests::Workspace(_) => { - return Err(AdapterError::BuildFailed { - reason: "package tests: workspace tests not supported".into(), - }) - } - }; - let test_setup = pkg_tests.setup().map_err(|err| AdapterError::BuildFailed { - reason: format!("test setup: {:?}", err), - })?; - self.state.built_package = Some(built_package.clone()); - self.state.test_setup = Some(test_setup.clone()); - Ok((built_package.clone(), test_setup)) - } -} diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_next.rs b/forc-plugins/forc-debug/src/server/handlers/handle_next.rs deleted file mode 100644 index 484228494e6..00000000000 --- a/forc-plugins/forc-debug/src/server/handlers/handle_next.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::server::AdapterError; -use crate::server::DapServer; - -impl DapServer { - /// Handles a `next` request. Returns true if the server should continue running. - pub(crate) fn handle_next(&mut self) -> Result { - self.continue_debugging_tests(true) - } -} diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_set_breakpoints.rs b/forc-plugins/forc-debug/src/server/handlers/handle_set_breakpoints.rs index 63390fb458e..d1b62c269cd 100644 --- a/forc-plugins/forc-debug/src/server/handlers/handle_set_breakpoints.rs +++ b/forc-plugins/forc-debug/src/server/handlers/handle_set_breakpoints.rs @@ -1,12 +1,27 @@ -use crate::server::AdapterError; -use crate::server::DapServer; -use dap::requests::SetBreakpointsArguments; -use dap::types::{Breakpoint, StartDebuggingRequestKind}; +use crate::server::{AdapterError, DapServer, HandlerResult}; +use dap::{ + requests::SetBreakpointsArguments, + responses::ResponseBody, + types::{Breakpoint, StartDebuggingRequestKind}, +}; use std::path::PathBuf; impl DapServer { /// Handles a `set_breakpoints` request. Returns the list of [Breakpoint]s for the path provided in `args`. - pub(crate) fn handle_set_breakpoints( + pub(crate) fn handle_set_breakpoints_command( + &mut self, + args: &SetBreakpointsArguments, + ) -> HandlerResult { + let result = self.set_breakpoints(args).map(|breakpoints| { + ResponseBody::SetBreakpoints(dap::responses::SetBreakpointsResponse { breakpoints }) + }); + match result { + Ok(result) => HandlerResult::ok(result), + Err(e) => HandlerResult::err_with_exit(e, 1), + } + } + + fn set_breakpoints( &mut self, args: &SetBreakpointsArguments, ) -> Result, AdapterError> { @@ -44,24 +59,22 @@ impl DapServer { .iter() .map(|source_bp| { let verified = source_map.contains_key(&source_bp.line); - - match existing_breakpoints.iter().find(|bp| match bp.line { - Some(line) => line == source_bp.line, - None => false, - }) { - Some(existing_bp) => Breakpoint { + if let Some(existing_bp) = existing_breakpoints + .iter() + .find(|bp| bp.line.map_or(false, |line| line == source_bp.line)) + { + Breakpoint { verified, ..existing_bp.clone() - }, - None => { - let id = Some(self.breakpoint_id_gen.next()); - Breakpoint { - id, - verified, - line: Some(source_bp.line), - source: Some(args.source.clone()), - ..Default::default() - } + } + } else { + let id = Some(self.breakpoint_id_gen.next()); + Breakpoint { + id, + verified, + line: Some(source_bp.line), + source: Some(args.source.clone()), + ..Default::default() } } }) @@ -131,7 +144,7 @@ mod tests { fn test_handle_set_breakpoints_existing_verified() { let mut server = get_test_server(true, true); let args = get_test_args(); - let result = server.handle_set_breakpoints(&args).expect("success"); + let result = server.set_breakpoints(&args).expect("success"); assert_eq!(result.len(), 1); assert_eq!(result[0].line, Some(MOCK_LINE)); assert_eq!(result[0].id, Some(MOCK_BP_ID)); @@ -146,7 +159,7 @@ mod tests { fn test_handle_set_breakpoints_existing_unverified() { let mut server = get_test_server(false, true); let args = get_test_args(); - let result = server.handle_set_breakpoints(&args).expect("success"); + let result = server.set_breakpoints(&args).expect("success"); assert_eq!(result.len(), 1); assert_eq!(result[0].line, Some(MOCK_LINE)); assert_eq!(result[0].id, Some(MOCK_BP_ID)); @@ -161,7 +174,7 @@ mod tests { fn test_handle_set_breakpoints_new() { let mut server = get_test_server(true, false); let args = get_test_args(); - let result = server.handle_set_breakpoints(&args).expect("success"); + let result = server.set_breakpoints(&args).expect("success"); assert_eq!(result.len(), 1); assert_eq!(result[0].line, Some(MOCK_LINE)); assert_eq!( @@ -176,6 +189,6 @@ mod tests { fn test_handle_breakpoint_locations_missing_argument() { let mut server = get_test_server(true, true); let args = SetBreakpointsArguments::default(); - server.handle_set_breakpoints(&args).unwrap(); + server.set_breakpoints(&args).unwrap(); } } diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_stack_trace.rs b/forc-plugins/forc-debug/src/server/handlers/handle_stack_trace.rs index fd26ff067af..0ee70988626 100644 --- a/forc-plugins/forc-debug/src/server/handlers/handle_stack_trace.rs +++ b/forc-plugins/forc-debug/src/server/handlers/handle_stack_trace.rs @@ -1,12 +1,25 @@ -use crate::server::util; -use crate::server::AdapterError; -use crate::server::DapServer; -use dap::types::StackFrame; -use dap::types::StackFramePresentationhint; +use crate::server::{util, AdapterError, DapServer, HandlerResult}; +use dap::{ + responses::ResponseBody, + types::{StackFrame, StackFramePresentationhint}, +}; impl DapServer { /// Handles a `stack_trace` request. Returns the list of [StackFrame]s for the current execution state. - pub(crate) fn handle_stack_trace(&self) -> Result, AdapterError> { + pub(crate) fn handle_stack_trace_command(&self) -> HandlerResult { + let result = self.stack_trace().map(|stack_frames| { + ResponseBody::StackTrace(dap::responses::StackTraceResponse { + stack_frames, + total_frames: None, + }) + }); + match result { + Ok(result) => HandlerResult::ok(result), + Err(e) => HandlerResult::err_with_exit(e, 1), + } + } + + fn stack_trace(&self) -> Result, AdapterError> { let executor = self .state .executors diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_variables.rs b/forc-plugins/forc-debug/src/server/handlers/handle_variables.rs index 1b4db95eab6..498413a0a80 100644 --- a/forc-plugins/forc-debug/src/server/handlers/handle_variables.rs +++ b/forc-plugins/forc-debug/src/server/handlers/handle_variables.rs @@ -1,21 +1,26 @@ -use crate::names::register_name; -use crate::server::AdapterError; -use crate::server::DapServer; -use crate::server::INSTRUCTIONS_VARIABLE_REF; -use crate::server::REGISTERS_VARIABLE_REF; -use dap::requests::VariablesArguments; -use dap::types::Variable; -use fuel_vm::fuel_asm::Imm06; -use fuel_vm::fuel_asm::Imm12; -use fuel_vm::fuel_asm::Imm18; -use fuel_vm::fuel_asm::Imm24; -use fuel_vm::fuel_asm::Instruction; -use fuel_vm::fuel_asm::RawInstruction; -use fuel_vm::fuel_asm::RegId; +use crate::{ + names::register_name, + server::{ + AdapterError, DapServer, HandlerResult, INSTRUCTIONS_VARIABLE_REF, REGISTERS_VARIABLE_REF, + }, +}; +use dap::{requests::VariablesArguments, responses::ResponseBody, types::Variable}; +use fuel_vm::fuel_asm::{Imm06, Imm12, Imm18, Imm24, Instruction, RawInstruction, RegId}; impl DapServer { - /// Handles a `variables` request. Returns the list of [Variable]s for the current execution state. - pub(crate) fn handle_variables( + /// Processes a variables request, returning all variables and their current values. + pub(crate) fn handle_variables_command(&self, args: &VariablesArguments) -> HandlerResult { + let result = self.get_variables(args).map(|variables| { + ResponseBody::Variables(dap::responses::VariablesResponse { variables }) + }); + match result { + Ok(result) => HandlerResult::ok(result), + Err(e) => HandlerResult::err_with_exit(e, 1), + } + } + + /// Returns the list of [Variable]s for the current execution state. + pub(crate) fn get_variables( &self, args: &VariablesArguments, ) -> Result, AdapterError> { @@ -32,7 +37,7 @@ impl DapServer { .enumerate() .map(|(index, value)| Variable { name: register_name(index), - value: format!("0x{:X?}", value), + value: format!("0x{value:X?}"), ..Default::default() }) .collect::>(); @@ -56,7 +61,7 @@ impl DapServer { .iter() .filter_map(|(name, value)| { value.as_ref().map(|value| Variable { - name: name.to_string(), + name: (*name).to_string(), value: value.to_string(), ..Default::default() }) diff --git a/forc-plugins/forc-debug/src/server/handlers/mod.rs b/forc-plugins/forc-debug/src/server/handlers/mod.rs index 66ef3f3aebb..601844a343f 100644 --- a/forc-plugins/forc-debug/src/server/handlers/mod.rs +++ b/forc-plugins/forc-debug/src/server/handlers/mod.rs @@ -1,7 +1,130 @@ +use crate::{ + error::AdapterError, + server::{ + AdditionalData, DapServer, HandlerResult, INSTRUCTIONS_VARIABLE_REF, + REGISTERS_VARIABLE_REF, THREAD_ID, + }, +}; +use dap::{ + prelude::*, + types::{Scope, StartDebuggingRequestKind}, +}; +use requests::{EvaluateArguments, LaunchRequestArguments}; +use std::path::PathBuf; + pub(crate) mod handle_breakpoint_locations; -pub(crate) mod handle_continue; -pub(crate) mod handle_launch; -pub(crate) mod handle_next; pub(crate) mod handle_set_breakpoints; pub(crate) mod handle_stack_trace; pub(crate) mod handle_variables; + +impl DapServer { + pub(crate) fn handle_attach(&mut self) -> HandlerResult { + self.state.mode = Some(StartDebuggingRequestKind::Attach); + self.error("This feature is not currently supported.".into()); + HandlerResult::ok_with_exit(ResponseBody::Attach, 0) + } + + pub(crate) fn handle_initialize(&mut self) -> HandlerResult { + HandlerResult::ok(ResponseBody::Initialize(types::Capabilities { + supports_breakpoint_locations_request: Some(true), + supports_configuration_done_request: Some(true), + ..Default::default() + })) + } + + pub(crate) fn handle_configuration_done(&mut self) -> HandlerResult { + self.state.configuration_done = true; + HandlerResult::ok(ResponseBody::ConfigurationDone) + } + + pub(crate) fn handle_launch(&mut self, args: &LaunchRequestArguments) -> HandlerResult { + self.state.mode = Some(StartDebuggingRequestKind::Launch); + if let Some(additional_data) = &args.additional_data { + if let Ok(data) = serde_json::from_value::(additional_data.clone()) { + self.state.program_path = PathBuf::from(data.program); + return HandlerResult::ok(ResponseBody::Launch); + } + } + HandlerResult::err_with_exit(AdapterError::MissingConfiguration, 1) + } + + /// Handles a `next` request. Returns true if the server should continue running. + pub(crate) fn handle_next(&mut self) -> HandlerResult { + match self.continue_debugging_tests(true) { + Ok(true) => HandlerResult::ok(ResponseBody::Next), + Ok(false) => { + // The tests finished executing + HandlerResult::ok_with_exit(ResponseBody::Next, 0) + } + Err(e) => HandlerResult::err_with_exit(e, 1), + } + } + + /// Handles a `continue` request. Returns true if the server should continue running. + pub(crate) fn handle_continue(&mut self) -> HandlerResult { + match self.continue_debugging_tests(false) { + Ok(true) => HandlerResult::ok(ResponseBody::Continue(responses::ContinueResponse { + all_threads_continued: Some(true), + })), + Ok(false) => HandlerResult::ok_with_exit( + ResponseBody::Continue(responses::ContinueResponse { + all_threads_continued: Some(true), + }), + 0, + ), + Err(e) => HandlerResult::err_with_exit(e, 1), + } + } + + pub(crate) fn handle_evaluate(&mut self, args: &EvaluateArguments) -> HandlerResult { + let result = match args.context { + Some(types::EvaluateArgumentsContext::Variables) => args.expression.clone(), + _ => "Evaluate expressions not supported in this context".into(), + }; + HandlerResult::ok(ResponseBody::Evaluate(responses::EvaluateResponse { + result, + ..Default::default() + })) + } + + pub(crate) fn handle_pause(&mut self) -> HandlerResult { + // TODO: interpreter pause function + if let Some(executor) = self.state.executor() { + executor.interpreter.set_single_stepping(true); + } + HandlerResult::ok(ResponseBody::Pause) + } + + pub(crate) fn handle_restart(&mut self) -> HandlerResult { + self.state.reset(); + HandlerResult::ok(ResponseBody::Restart) + } + + pub(crate) fn handle_scopes(&mut self) -> HandlerResult { + HandlerResult::ok(ResponseBody::Scopes(responses::ScopesResponse { + scopes: vec![ + Scope { + name: "Current VM Instruction".into(), + presentation_hint: Some(types::ScopePresentationhint::Registers), + variables_reference: INSTRUCTIONS_VARIABLE_REF, + ..Default::default() + }, + Scope { + name: "Registers".into(), + presentation_hint: Some(types::ScopePresentationhint::Registers), + variables_reference: REGISTERS_VARIABLE_REF, + ..Default::default() + }, + ], + })) + } + + pub(crate) fn handle_threads(&mut self) -> HandlerResult { + HandlerResult::ok(ResponseBody::Threads(responses::ThreadsResponse { + threads: vec![types::Thread { + id: THREAD_ID, + name: "main".into(), + }], + })) + } +} diff --git a/forc-plugins/forc-debug/src/server/mod.rs b/forc-plugins/forc-debug/src/server/mod.rs index 968b1cf4ec1..e06959c5e7b 100644 --- a/forc-plugins/forc-debug/src/server/mod.rs +++ b/forc-plugins/forc-debug/src/server/mod.rs @@ -1,25 +1,36 @@ -mod error; mod handlers; mod state; mod util; -use self::error::AdapterError; -use self::state::ServerState; -use self::util::IdGenerator; -use crate::types::DynResult; -use crate::types::Instruction; -use dap::events::OutputEventBody; -use dap::events::{ExitedEventBody, StoppedEventBody}; -use dap::prelude::*; -use dap::types::{Scope, StartDebuggingRequestKind}; -use forc_test::execute::DebugResult; +use crate::{ + error::{self, AdapterError, Error}, + server::{state::ServerState, util::IdGenerator}, + types::{ExitCode, Instruction}, +}; +use dap::{ + events::{ExitedEventBody, OutputEventBody, StoppedEventBody}, + prelude::*, + types::StartDebuggingRequestKind, +}; +use forc_pkg::{ + manifest::GenericManifestFile, + source::IPFSNode, + {self, BuildProfile, Built, BuiltPackage, PackageManifestFile}, +}; +use forc_test::{ + execute::{DebugResult, TestExecutor}, + setup::TestSetup, + BuiltTests, +}; use serde::{Deserialize, Serialize}; -use std::io::{Read, Write}; use std::{ - io::{BufReader, BufWriter}, - path::PathBuf, + collections::HashMap, + io::{BufReader, BufWriter, Read, Write}, process, + sync::Arc, }; +use sway_core::BuildTarget; +use sway_types::LineCol; pub const THREAD_ID: i64 = 0; pub const REGISTERS_VARIABLE_REF: i64 = 1; @@ -52,230 +63,115 @@ impl Default for DapServer { } impl DapServer { + /// Creates a new DAP server with custom input and output streams. + /// + /// # Arguments + /// * `input` - Source of DAP protocol messages (usually stdin) + /// * `output` - Destination for DAP protocol messages (usually stdout) pub fn new(input: Box, output: Box) -> Self { let server = Server::new(BufReader::new(input), BufWriter::new(output)); DapServer { server, - state: Default::default(), - breakpoint_id_gen: Default::default(), + state: ServerState::default(), + breakpoint_id_gen: IdGenerator::default(), } } - pub fn start(&mut self) -> DynResult<()> { + /// Runs the debug server event loop, handling client requests until completion or error. + pub fn start(&mut self) -> error::Result<()> { loop { - match self.server.poll_request()? { - Some(req) => { - let rsp = self.handle_request(req)?; - self.server.respond(rsp)?; - - if !self.state.initialized_event_sent { - let _ = self.server.send_event(Event::Initialized); - self.state.initialized_event_sent = true; - } - if self.state.configuration_done && !self.state.started_debugging { - if let Some(StartDebuggingRequestKind::Launch) = self.state.mode { - self.state.started_debugging = true; - match self.handle_launch() { - Ok(true) => {} - Ok(false) => { - // The tests finished executing - self.exit(0); - } - Err(e) => { - self.error(format!("Launch error: {:?}", e)); - self.exit(1); - } - } - } + let req = match self.server.poll_request()? { + Some(req) => req, + None => return Err(Error::AdapterError(AdapterError::MissingCommand)), + }; + + // Handle the request and send response + let response = self.handle_request(req)?; + self.server.respond(response)?; + + // Handle one-time initialization + if !self.state.initialized_event_sent { + let _ = self.server.send_event(Event::Initialized); + self.state.initialized_event_sent = true; + } + + // Handle launch after configuration is complete + if self.should_launch() { + self.state.started_debugging = true; + match self.launch() { + Ok(true) => continue, + Ok(false) => self.exit(0), // The tests finished executing + Err(e) => { + self.error(format!("Launch error: {e:?}")); + self.exit(1); } } - None => return Err(Box::new(AdapterError::MissingCommand)), - }; + } } } - fn handle_request(&mut self, req: Request) -> DynResult { - let command = req.command.clone(); - let (result, exit_code) = self.handle_command(command); + /// Processes a debug adapter request and generates appropriate response. + fn handle_request(&mut self, req: Request) -> error::Result { + let (result, exit_code) = self.handle_command(&req.command).into_tuple(); let response = match result { Ok(rsp) => Ok(req.success(rsp)), Err(e) => { - self.error(format!("{:?}", e)); - Ok(req.error(&format!("{:?}", e))) + self.error(format!("{e:?}")); + Ok(req.error(&format!("{e:?}"))) } }; if let Some(exit_code) = exit_code { - self.exit(exit_code) + self.exit(exit_code); } response } /// Handles a command and returns the result and exit code, if any. - pub fn handle_command( - &mut self, - command: Command, - ) -> (Result, Option) { + pub fn handle_command(&mut self, command: &Command) -> HandlerResult { match command { - Command::Attach(_) => { - self.state.mode = Some(StartDebuggingRequestKind::Attach); - self.error("This feature is not currently supported.".into()); - (Ok(ResponseBody::Attach), Some(0)) - } + Command::Attach(_) => self.handle_attach(), Command::BreakpointLocations(ref args) => { - match self.handle_breakpoint_locations(args) { - Ok(breakpoints) => ( - Ok(ResponseBody::BreakpointLocations( - responses::BreakpointLocationsResponse { breakpoints }, - )), - None, - ), - Err(e) => (Err(e), None), - } - } - Command::ConfigurationDone => { - self.state.configuration_done = true; - (Ok(ResponseBody::ConfigurationDone), None) - } - Command::Continue(_) => match self.handle_continue() { - Ok(true) => ( - Ok(ResponseBody::Continue(responses::ContinueResponse { - all_threads_continued: Some(true), - })), - None, - ), - Ok(false) => ( - Ok(ResponseBody::Continue(responses::ContinueResponse { - all_threads_continued: Some(true), - })), - Some(0), - ), - Err(e) => (Err(e), Some(1)), - }, - Command::Disconnect(_) => (Ok(ResponseBody::Disconnect), Some(0)), - Command::Evaluate(args) => { - let result = match args.context { - Some(types::EvaluateArgumentsContext::Variables) => args.expression.clone(), - _ => "Evaluate expressions not supported in this context".into(), - }; - ( - Ok(ResponseBody::Evaluate(responses::EvaluateResponse { - result, - ..Default::default() - })), - None, - ) - } - Command::Initialize(_) => ( - Ok(ResponseBody::Initialize(types::Capabilities { - supports_breakpoint_locations_request: Some(true), - supports_configuration_done_request: Some(true), - ..Default::default() - })), - None, - ), - Command::Launch(ref args) => { - self.state.mode = Some(StartDebuggingRequestKind::Launch); - if let Some(additional_data) = &args.additional_data { - if let Ok(data) = - serde_json::from_value::(additional_data.clone()) - { - self.state.program_path = PathBuf::from(data.program); - return (Ok(ResponseBody::Launch), None); - } - } - (Err(AdapterError::MissingConfiguration), Some(1)) - } - Command::Next(_) => { - match self.handle_next() { - Ok(true) => (Ok(ResponseBody::Next), None), - Ok(false) => { - // The tests finished executing - (Ok(ResponseBody::Next), Some(0)) - } - Err(e) => (Err(e), Some(1)), - } - } - Command::Pause(_) => { - // TODO: interpreter pause function - if let Some(executor) = self.state.executor() { - executor.interpreter.set_single_stepping(true); - } - (Ok(ResponseBody::Pause), None) + self.handle_breakpoint_locations_command(args) } - Command::Restart(_) => { - self.state.reset(); - (Ok(ResponseBody::Restart), None) - } - Command::Scopes(_) => ( - Ok(ResponseBody::Scopes(responses::ScopesResponse { - scopes: vec![ - Scope { - name: "Current VM Instruction".into(), - presentation_hint: Some(types::ScopePresentationhint::Registers), - variables_reference: INSTRUCTIONS_VARIABLE_REF, - ..Default::default() - }, - Scope { - name: "Registers".into(), - presentation_hint: Some(types::ScopePresentationhint::Registers), - variables_reference: REGISTERS_VARIABLE_REF, - ..Default::default() - }, - ], - })), - None, - ), - Command::SetBreakpoints(ref args) => match self.handle_set_breakpoints(args) { - Ok(breakpoints) => ( - Ok(ResponseBody::SetBreakpoints( - responses::SetBreakpointsResponse { breakpoints }, - )), - None, - ), - Err(e) => (Err(e), None), - }, - Command::StackTrace(_) => match self.handle_stack_trace() { - Ok(stack_frames) => ( - Ok(ResponseBody::StackTrace(responses::StackTraceResponse { - stack_frames, - total_frames: None, - })), - None, - ), - Err(e) => (Err(e), None), - }, + Command::ConfigurationDone => self.handle_configuration_done(), + Command::Continue(_) => self.handle_continue(), + Command::Disconnect(_) => HandlerResult::ok_with_exit(ResponseBody::Disconnect, 0), + Command::Evaluate(args) => self.handle_evaluate(args), + Command::Initialize(_) => self.handle_initialize(), + Command::Launch(ref args) => self.handle_launch(args), + Command::Next(_) => self.handle_next(), + Command::Pause(_) => self.handle_pause(), + Command::Restart(_) => self.handle_restart(), + Command::Scopes(_) => self.handle_scopes(), + Command::SetBreakpoints(ref args) => self.handle_set_breakpoints_command(args), + Command::StackTrace(_) => self.handle_stack_trace_command(), Command::StepIn(_) => { self.error("This feature is not currently supported.".into()); - (Ok(ResponseBody::StepIn), None) + HandlerResult::ok(ResponseBody::StepIn) } Command::StepOut(_) => { self.error("This feature is not currently supported.".into()); - (Ok(ResponseBody::StepOut), None) + HandlerResult::ok(ResponseBody::StepOut) } - Command::Terminate(_) => (Ok(ResponseBody::Terminate), Some(0)), - Command::TerminateThreads(_) => (Ok(ResponseBody::TerminateThreads), Some(0)), - Command::Threads => ( - Ok(ResponseBody::Threads(responses::ThreadsResponse { - threads: vec![types::Thread { - id: THREAD_ID, - name: "main".into(), - }], - })), - None, - ), - Command::Variables(ref args) => match self.handle_variables(args) { - Ok(variables) => ( - Ok(ResponseBody::Variables(responses::VariablesResponse { - variables, - })), - None, - ), - Err(e) => (Err(e), None), - }, - _ => (Err(AdapterError::UnhandledCommand { command }), None), + Command::Terminate(_) => HandlerResult::ok_with_exit(ResponseBody::Terminate, 0), + Command::TerminateThreads(_) => { + HandlerResult::ok_with_exit(ResponseBody::TerminateThreads, 0) + } + Command::Threads => self.handle_threads(), + Command::Variables(ref args) => self.handle_variables_command(args), + _ => HandlerResult::err(AdapterError::UnhandledCommand { + command: command.clone(), + }), } } + /// Checks whether debug session is ready to begin launching tests. + fn should_launch(&self) -> bool { + self.state.configuration_done + && !self.state.started_debugging + && matches!(self.state.mode, Some(StartDebuggingRequestKind::Launch)) + } + /// Logs a message to the client's debugger console output. fn log(&mut self, output: String) { let _ = self.server.send_event(Event::Output(OutputEventBody { @@ -293,53 +189,212 @@ impl DapServer { })); } + /// Logs test execution results in a cargo-test-like format, showing duration and gas usage for each test. fn log_test_results(&mut self) { if !self.state.executors.is_empty() { return; } - - let results = self - .state - .test_results + let test_results = &self.state.test_results; + let test_lines = test_results .iter() - .map(|result| { - let outcome = match result.passed() { - true => "ok", - false => "failed", - }; - + .map(|r| { + let outcome = if r.passed() { "ok" } else { "failed" }; format!( "test {} ... {} ({}ms, {} gas)", - result.name, + r.name, outcome, - result.duration.as_millis(), - result.gas_used + r.duration.as_millis(), + r.gas_used ) }) .collect::>() .join("\n"); - let final_outcome = match self.state.test_results.iter().any(|r| !r.passed()) { - true => "FAILED", - false => "OK", + + let passed = test_results.iter().filter(|r| r.passed()).count(); + let final_outcome = if passed == test_results.len() { + "OK" + } else { + "FAILED" }; - let passed = self - .state - .test_results - .iter() - .filter(|r| r.passed()) - .count(); - let failed = self - .state - .test_results - .iter() - .filter(|r| !r.passed()) - .count(); + self.log(format!( - "{}\nResult: {}. {} passed. {} failed.\n", - results, final_outcome, passed, failed + "{test_lines}\nResult: {final_outcome}. {passed} passed. {} failed.\n", + test_results.len() - passed )); } + /// Handles a `launch` request. Returns true if the server should continue running. + pub fn launch(&mut self) -> Result { + // Build tests for the given path. + let (pkg_to_debug, test_setup) = self.build_tests()?; + let entries = pkg_to_debug.bytecode.entries.iter().filter_map(|entry| { + if let Some(test_entry) = entry.kind.test() { + return Some((entry, test_entry)); + } + None + }); + + // Construct a TestExecutor for each test and store it + let executors: Vec = entries + .filter_map(|(entry, test_entry)| { + let offset = u32::try_from(entry.finalized.imm) + .expect("test instruction offset out of range"); + let name = entry.finalized.fn_name.clone(); + if test_entry.file_path.as_path() != self.state.program_path.as_path() { + return None; + } + + TestExecutor::build( + &pkg_to_debug.bytecode.bytes, + offset, + test_setup.clone(), + test_entry, + name.clone(), + ) + .ok() + }) + .collect(); + self.state.init_executors(executors); + + // Start debugging + self.start_debugging_tests(false) + } + + /// Builds the tests at the given [PathBuf] and stores the source maps. + pub(crate) fn build_tests(&mut self) -> Result<(BuiltPackage, TestSetup), AdapterError> { + if let Some(pkg) = &self.state.built_package { + if let Some(setup) = &self.state.test_setup { + return Ok((pkg.clone(), setup.clone())); + } + } + + // 1. Build the packages + let manifest_file = forc_pkg::manifest::ManifestFile::from_dir(&self.state.program_path) + .map_err(|err| AdapterError::BuildFailed { + reason: format!("read manifest file: {err:?}"), + })?; + let pkg_manifest: PackageManifestFile = + manifest_file + .clone() + .try_into() + .map_err(|err: anyhow::Error| AdapterError::BuildFailed { + reason: format!("package manifest: {err:?}"), + })?; + let member_manifests = + manifest_file + .member_manifests() + .map_err(|err| AdapterError::BuildFailed { + reason: format!("member manifests: {err:?}"), + })?; + let lock_path = manifest_file + .lock_path() + .map_err(|err| AdapterError::BuildFailed { + reason: format!("lock path: {err:?}"), + })?; + let build_plan = forc_pkg::BuildPlan::from_lock_and_manifests( + &lock_path, + &member_manifests, + false, + false, + &IPFSNode::default(), + ) + .map_err(|err| AdapterError::BuildFailed { + reason: format!("build plan: {err:?}"), + })?; + + let project_name = pkg_manifest.project_name(); + + let outputs = std::iter::once(build_plan.find_member_index(project_name).ok_or( + AdapterError::BuildFailed { + reason: format!("find built project: {project_name}"), + }, + )?) + .collect(); + + let built_packages = forc_pkg::build( + &build_plan, + BuildTarget::default(), + &BuildProfile { + optimization_level: sway_core::OptLevel::Opt0, + include_tests: true, + ..Default::default() + }, + &outputs, + &[], + &[], + ) + .map_err(|err| AdapterError::BuildFailed { + reason: format!("build packages: {err:?}"), + })?; + + // 2. Store the source maps + let mut pkg_to_debug: Option<&BuiltPackage> = None; + for (_, built_pkg) in &built_packages { + if built_pkg.descriptor.manifest_file == pkg_manifest { + pkg_to_debug = Some(built_pkg); + } + let source_map = &built_pkg.source_map; + + let paths = &source_map.paths; + source_map.map.iter().for_each(|(instruction, sm_span)| { + if let Some(path_buf) = paths.get(sm_span.path.0) { + let LineCol { line, .. } = sm_span.range.start; + let (line, instruction) = (line as i64, *instruction as Instruction); + + self.state + .source_map + .entry(path_buf.clone()) + .and_modify(|new_map| { + new_map + .entry(line) + .and_modify(|val| { + // Store the instructions in ascending order + match val.binary_search(&instruction) { + Ok(_) => {} // Ignore duplicates + Err(pos) => val.insert(pos, instruction), + } + }) + .or_insert(vec![instruction]); + }) + .or_insert(HashMap::from([(line, vec![instruction])])); + } else { + self.error(format!( + "Path missing from source map: {:?}", + sm_span.path.0 + )); + } + }); + } + + // 3. Build the tests + let built_package = pkg_to_debug.ok_or(AdapterError::BuildFailed { + reason: format!("find package: {project_name}"), + })?; + + let built = Built::Package(Arc::from(built_package.clone())); + + let built_tests = BuiltTests::from_built(built, &build_plan).map_err(|err| { + AdapterError::BuildFailed { + reason: format!("build tests: {err:?}"), + } + })?; + + let pkg_tests = match built_tests { + BuiltTests::Package(pkg_tests) => pkg_tests, + BuiltTests::Workspace(_) => { + return Err(AdapterError::BuildFailed { + reason: "package tests: workspace tests not supported".into(), + }) + } + }; + let test_setup = pkg_tests.setup().map_err(|err| AdapterError::BuildFailed { + reason: format!("test setup: {err:?}"), + })?; + self.state.built_package = Some(built_package.clone()); + self.state.test_setup = Some(test_setup.clone()); + Ok((built_package.clone(), test_setup)) + } + /// Sends the 'exited' event to the client and kills the server process. fn exit(&mut self, exit_code: i64) { let _ = self @@ -422,3 +477,49 @@ impl DapServer { Ok(false) } } + +/// Represents the result of a DAP handler operation, combining the response/error and an optional exit code +#[derive(Debug)] +pub struct HandlerResult { + response: Result, + exit_code: Option, +} + +impl HandlerResult { + /// Creates a new successful result with no exit code + pub fn ok(response: ResponseBody) -> Self { + Self { + response: Ok(response), + exit_code: None, + } + } + + /// Creates a new successful result with an exit code + pub fn ok_with_exit(response: ResponseBody, code: ExitCode) -> Self { + Self { + response: Ok(response), + exit_code: Some(code), + } + } + + /// Creates a new error result with an exit code + pub fn err_with_exit(error: AdapterError, code: ExitCode) -> Self { + Self { + response: Err(error), + exit_code: Some(code), + } + } + + /// Creates a new error result with no exit code + pub fn err(error: AdapterError) -> Self { + Self { + response: Err(error), + exit_code: None, + } + } + + /// Deconstructs the result into its original tuple form + pub fn into_tuple(self) -> (Result, Option) { + (self.response, self.exit_code) + } +} diff --git a/forc-plugins/forc-debug/src/server/state.rs b/forc-plugins/forc-debug/src/server/state.rs index 948869ead23..a99d5898791 100644 --- a/forc-plugins/forc-debug/src/server/state.rs +++ b/forc-plugins/forc-debug/src/server/state.rs @@ -1,12 +1,10 @@ -use super::AdapterError; -use crate::types::Breakpoints; -use crate::types::Instruction; -use crate::types::SourceMap; +use crate::{ + error::AdapterError, + types::{Breakpoints, Instruction, SourceMap}, +}; use dap::types::StartDebuggingRequestKind; use forc_pkg::BuiltPackage; -use forc_test::execute::TestExecutor; -use forc_test::setup::TestSetup; -use forc_test::TestResult; +use forc_test::{execute::TestExecutor, setup::TestSetup, TestResult}; use std::path::PathBuf; #[derive(Default, Debug, Clone)] @@ -65,7 +63,7 @@ impl ServerState { self.source_map .iter() .find_map(|(source_path, source_map)| { - for (&line, instructions) in source_map.iter() { + for (&line, instructions) in source_map { // Divide by 4 to get the opcode offset rather than the program counter offset. let instruction_offset = pc / 4; if instructions @@ -75,7 +73,6 @@ impl ServerState { return Some((source_path, line)); } } - None }) .ok_or(AdapterError::MissingSourceMap { pc }) diff --git a/forc-plugins/forc-debug/src/server/util.rs b/forc-plugins/forc-debug/src/server/util.rs index ed24363c17b..513b071e192 100644 --- a/forc-plugins/forc-debug/src/server/util.rs +++ b/forc-plugins/forc-debug/src/server/util.rs @@ -27,6 +27,9 @@ impl IdGenerator { } } +/// Converts a filesystem path into a DAP Source object, which is used by the debug adapter +/// to identify source locations. Only sets the path field, leaving other Source fields at +/// their default values. pub(crate) fn path_into_source(path: &Path) -> Source { Source { path: Some(path.to_string_lossy().into_owned()), diff --git a/forc-plugins/forc-debug/src/types.rs b/forc-plugins/forc-debug/src/types.rs index a7f9828ddc5..4eb9b194eea 100644 --- a/forc-plugins/forc-debug/src/types.rs +++ b/forc-plugins/forc-debug/src/types.rs @@ -1,9 +1,8 @@ use dap::types::Breakpoint; -use std::collections::HashMap; -use std::path::PathBuf; +use std::{collections::HashMap, path::PathBuf}; -pub type DynResult = std::result::Result>; pub type Line = i64; +pub type ExitCode = i64; pub type Instruction = u64; pub type FileSourceMap = HashMap>; pub type SourceMap = HashMap; diff --git a/forc-plugins/forc-debug/tests/server_integration.rs b/forc-plugins/forc-debug/tests/server_integration.rs index 5f33e658b3f..5bd291b63a4 100644 --- a/forc-plugins/forc-debug/tests/server_integration.rs +++ b/forc-plugins/forc-debug/tests/server_integration.rs @@ -7,8 +7,12 @@ use dap::{ use forc_debug::server::{ AdditionalData, DapServer, INSTRUCTIONS_VARIABLE_REF, REGISTERS_VARIABLE_REF, }; -use std::sync::Mutex; -use std::{env, io::Write, path::PathBuf, sync::Arc}; +use std::{ + env, + io::Write, + path::PathBuf, + sync::{Arc, Mutex}, +}; pub fn sway_workspace_dir() -> PathBuf { env::current_dir().unwrap().parent().unwrap().to_path_buf() @@ -59,12 +63,16 @@ fn test_server_attach_mode() { let mut server = DapServer::new(input, output); // Initialize request - let (result, exit_code) = server.handle_command(Command::Initialize(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Initialize(Default::default())) + .into_tuple(); assert!(matches!(result, Ok(ResponseBody::Initialize(_)))); assert!(exit_code.is_none()); // Attach request - let (result, exit_code) = server.handle_command(Command::Attach(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Attach(Default::default())) + .into_tuple(); assert!(matches!(result, Ok(ResponseBody::Attach))); assert_eq!(exit_code, Some(0)); assert_not_supported_event(output_capture.take_event()); @@ -81,7 +89,9 @@ fn test_server_launch_mode() { let source_str = program_path.to_string_lossy().to_string(); // Initialize request - let (result, exit_code) = server.handle_command(Command::Initialize(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Initialize(Default::default())) + .into_tuple(); assert!(matches!(result, Ok(ResponseBody::Initialize(_)))); assert!(exit_code.is_none()); @@ -90,16 +100,18 @@ fn test_server_launch_mode() { program: source_str.clone(), }) .unwrap(); - let (result, exit_code) = server.handle_command(Command::Launch(LaunchRequestArguments { - additional_data: Some(additional_data), - ..Default::default() - })); + let (result, exit_code) = server + .handle_command(&Command::Launch(LaunchRequestArguments { + additional_data: Some(additional_data), + ..Default::default() + })) + .into_tuple(); assert!(matches!(result, Ok(ResponseBody::Launch))); assert!(exit_code.is_none()); // Set Breakpoints - let (result, exit_code) = - server.handle_command(Command::SetBreakpoints(SetBreakpointsArguments { + let (result, exit_code) = server + .handle_command(&Command::SetBreakpoints(SetBreakpointsArguments { source: Source { path: Some(source_str.clone()), ..Default::default() @@ -119,7 +131,8 @@ fn test_server_launch_mode() { }, ]), ..Default::default() - })); + })) + .into_tuple(); match result.expect("set breakpoints result") { ResponseBody::SetBreakpoints(res) => { assert!(res.breakpoints.len() == 3); @@ -129,17 +142,19 @@ fn test_server_launch_mode() { assert!(exit_code.is_none()); // Configuration Done request - let (result, exit_code) = server.handle_command(Command::ConfigurationDone); + let (result, exit_code) = server + .handle_command(&Command::ConfigurationDone) + .into_tuple(); assert!(matches!(result, Ok(ResponseBody::ConfigurationDone))); assert!(exit_code.is_none()); // Launch, should hit first breakpoint - let keep_running = server.handle_launch().expect("launched without error"); + let keep_running = server.launch().expect("launched without error"); assert!(keep_running); assert_stopped_breakpoint_event(output_capture.take_event(), 0); // Threads request - let (result, exit_code) = server.handle_command(Command::Threads); + let (result, exit_code) = server.handle_command(&Command::Threads).into_tuple(); match result.expect("threads result") { ResponseBody::Threads(res) => { assert_eq!(res.threads.len(), 1); @@ -149,7 +164,9 @@ fn test_server_launch_mode() { assert!(exit_code.is_none()); // Stack Trace request - let (result, exit_code) = server.handle_command(Command::StackTrace(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::StackTrace(Default::default())) + .into_tuple(); match result.expect("stack trace result") { ResponseBody::StackTrace(res) => { assert_eq!(res.stack_frames.len(), 1); @@ -159,7 +176,9 @@ fn test_server_launch_mode() { assert!(exit_code.is_none()); // Scopes request - let (result, exit_code) = server.handle_command(Command::Scopes(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Scopes(Default::default())) + .into_tuple(); match result.expect("scopes result") { ResponseBody::Scopes(res) => { assert_eq!(res.scopes.len(), 2); @@ -169,10 +188,12 @@ fn test_server_launch_mode() { assert!(exit_code.is_none()); // Variables request - registers - let (result, exit_code) = server.handle_command(Command::Variables(VariablesArguments { - variables_reference: REGISTERS_VARIABLE_REF, - ..Default::default() - })); + let (result, exit_code) = server + .handle_command(&Command::Variables(VariablesArguments { + variables_reference: REGISTERS_VARIABLE_REF, + ..Default::default() + })) + .into_tuple(); match result.expect("registers variables result") { ResponseBody::Variables(res) => { assert_eq!(res.variables.len(), 64); @@ -182,10 +203,12 @@ fn test_server_launch_mode() { assert!(exit_code.is_none()); // Variables request - VM instructions - let (result, exit_code) = server.handle_command(Command::Variables(VariablesArguments { - variables_reference: INSTRUCTIONS_VARIABLE_REF, - ..Default::default() - })); + let (result, exit_code) = server + .handle_command(&Command::Variables(VariablesArguments { + variables_reference: INSTRUCTIONS_VARIABLE_REF, + ..Default::default() + })) + .into_tuple(); match result.expect("instructions variables result") { ResponseBody::Variables(res) => { let expected = vec![ @@ -201,37 +224,49 @@ fn test_server_launch_mode() { assert!(exit_code.is_none()); // Next request - let (result, exit_code) = server.handle_command(Command::Next(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Next(Default::default())) + .into_tuple(); assert!(result.is_ok()); assert!(exit_code.is_none()); assert_stopped_next_event(output_capture.take_event()); // Step In request - let (result, exit_code) = server.handle_command(Command::StepIn(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::StepIn(Default::default())) + .into_tuple(); assert!(result.is_ok()); assert!(exit_code.is_none()); assert_not_supported_event(output_capture.take_event()); // Step Out request - let (result, exit_code) = server.handle_command(Command::StepOut(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::StepOut(Default::default())) + .into_tuple(); assert!(result.is_ok()); assert!(exit_code.is_none()); assert_not_supported_event(output_capture.take_event()); // Continue request, should hit 2nd breakpoint - let (result, exit_code) = server.handle_command(Command::Continue(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Continue(Default::default())) + .into_tuple(); assert!(result.is_ok()); assert!(exit_code.is_none()); assert_stopped_breakpoint_event(output_capture.take_event(), 1); // Continue request, should hit 3rd breakpoint - let (result, exit_code) = server.handle_command(Command::Continue(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Continue(Default::default())) + .into_tuple(); assert!(result.is_ok()); assert!(exit_code.is_none()); assert_stopped_breakpoint_event(output_capture.take_event(), 2); // Continue request, should exit cleanly - let (result, exit_code) = server.handle_command(Command::Continue(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Continue(Default::default())) + .into_tuple(); assert!(result.is_ok()); assert_eq!(exit_code, Some(0)); From 0ccf47bbf991617af4e7f238f704a8ab5de5d184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Matos?= Date: Wed, 4 Dec 2024 15:15:08 +0000 Subject: [PATCH 36/52] Fix handling of associated constants in ABI/traits (#6768) ## Description [Fix handling of initialized associated constants in ABIs and traits.](https://github.com/FuelLabs/sway/commit/88fee13a142e6f7bbf54f2abbfae88783904cb97) [Fix impl trait associated constant reference wrongly resolving to the ABI value](https://github.com/FuelLabs/sway/commit/3a401f659daf9a0fec50b5af28d80b5dec42cb01) Fixes https://github.com/FuelLabs/sway/issues/6343 and https://github.com/FuelLabs/sway/issues/6310. ## 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). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --------- Co-authored-by: Sophie Dankel <47993817+sdankel@users.noreply.github.com> Co-authored-by: Joshua Batty --- .../ast_node/declaration/abi.rs | 47 +++--- .../ast_node/declaration/impl_trait.rs | 143 ++++++++++++++---- .../ast_node/declaration/trait.rs | 36 ++++- .../src/semantic_analysis/ast_node/modes.rs | 1 + .../namespace/lexical_scope.rs | 3 + .../semantic_analysis/type_check_context.rs | 2 +- .../to_parsed_lang/convert_parse_tree.rs | 2 +- sway-error/src/error.rs | 3 + .../language/associated_const_abi/src/main.sw | 31 ++-- 9 files changed, 189 insertions(+), 79 deletions(-) diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs index 0274195845b..a22fd3925f6 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use sway_error::error::CompileError; use sway_types::{Ident, Named, Span, Spanned}; @@ -163,31 +163,19 @@ impl ty::TyAbiDecl { ctx.engines.de().insert(const_decl.clone(), Some(&decl_id)); new_interface_surface .push(ty::TyTraitInterfaceItem::Constant(decl_ref.clone())); - - let const_name = const_decl.call_path.suffix.clone(); - ctx.insert_symbol( - handler, - const_name.clone(), - ty::TyDecl::ConstantDecl(ty::ConstantDecl { - decl_id: *decl_ref.id(), - }), - )?; - - const_name + const_decl.call_path.suffix.clone() } TraitItem::Type(decl_id) => { let type_decl = engines.pe().get_trait_type(&decl_id).as_ref().clone(); handler.emit_err(CompileError::AssociatedTypeNotSupportedInAbi { span: type_decl.span.clone(), }); - let type_decl = ty::TyTraitType::type_check(handler, ctx.by_ref(), type_decl)?; let decl_ref = ctx.engines().de().insert(type_decl.clone(), Some(&decl_id)); new_interface_surface .push(ty::TyTraitInterfaceItem::Type(decl_ref.clone())); - type_decl.name } TraitItem::Error(_, _) => { @@ -276,6 +264,8 @@ impl ty::TyAbiDecl { (false, Span::dummy()) }; + let mut const_symbols = HashMap::::new(); + handler.scope(|handler| { for item in interface_surface.iter() { match item { @@ -339,9 +329,8 @@ impl ty::TyAbiDecl { let const_decl = decl_engine.get_constant(decl_ref); let const_name = const_decl.call_path.suffix.clone(); all_items.push(TyImplItem::Constant(decl_ref.clone())); - let _ = ctx.insert_symbol( - handler, - const_name.clone(), + const_symbols.insert( + const_name, ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id: *decl_ref.id(), }), @@ -397,10 +386,24 @@ impl ty::TyAbiDecl { } ty::TyTraitItem::Constant(decl_ref) => { let const_decl = decl_engine.get_constant(decl_ref); - all_items.push(TyImplItem::Constant(decl_engine.insert_arc( + let const_name = const_decl.name().clone(); + let const_has_value = const_decl.value.is_some(); + let decl_id = decl_engine.insert_arc( const_decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref(), - ))); + ); + all_items.push(TyImplItem::Constant(decl_id.clone())); + + // If this non-interface item has a value, then we want to overwrite the + // the previously inserted constant symbol from the interface surface. + if const_has_value { + const_symbols.insert( + const_name, + ty::TyDecl::ConstantDecl(ty::ConstantDecl { + decl_id: *decl_id.id(), + }), + ); + } } ty::TyTraitItem::Type(decl_ref) => { let type_decl = decl_engine.get_type(decl_ref); @@ -411,6 +414,12 @@ impl ty::TyAbiDecl { } } } + + // Insert the constants into the namespace. + for (name, decl) in const_symbols.into_iter() { + let _ = ctx.insert_symbol(handler, name, decl); + } + // Insert the methods of the ABI into the namespace. // Specifically do not check for conflicting definitions because // this is just a temporary namespace for type checking and diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index 1e5b9fdfd24..87e2f23fcee 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -9,7 +9,7 @@ use sway_error::{ error::{CompileError, InterfaceName}, handler::{ErrorEmitted, Handler}, }; -use sway_types::{Ident, Span, Spanned}; +use sway_types::{Ident, Named, Span, Spanned}; use crate::{ decl_engine::{parsed_id::ParsedDeclId, *}, @@ -17,8 +17,8 @@ use crate::{ language::{ parsed::*, ty::{ - self, TyConstantDecl, TyDecl, TyFunctionDecl, TyImplItem, TyImplSelfOrTrait, - TyTraitInterfaceItem, TyTraitItem, TyTraitType, + self, ConstantDecl, TyConstantDecl, TyDecl, TyFunctionDecl, TyImplItem, + TyImplSelfOrTrait, TyTraitInterfaceItem, TyTraitItem, TyTraitType, }, *, }, @@ -888,6 +888,54 @@ fn type_check_trait_implementation( } } + for item in impl_items { + match item { + ImplItem::Fn(_impl_method_id) => {} + ImplItem::Constant(decl_id) => { + let const_decl = engines.pe().get_constant(decl_id).as_ref().clone(); + let mut const_decl = type_check_const_decl( + handler, + ctx.by_ref().with_type_subst(&trait_type_mapping), + &const_decl, + trait_name, + is_contract, + &impld_item_refs, + &constant_checklist, + ) + .unwrap_or_else(|_| ty::TyConstantDecl::error(ctx.engines(), const_decl.clone())); + + const_decl.subst(&SubstTypesContext::new( + engines, + &trait_type_mapping, + !ctx.code_block_first_pass(), + )); + + // Remove this constant from the checklist. + let name = const_decl.call_path.suffix.clone(); + constant_checklist.remove(&name); + + // Add this constant to the "impld decls". + let decl_ref = decl_engine.insert(const_decl, Some(decl_id)); + impld_item_refs.insert( + (name.clone(), implementing_for), + TyTraitItem::Constant(decl_ref.clone()), + ); + + let prev_const_shadowing_mode = ctx.const_shadowing_mode; + ctx.const_shadowing_mode = ConstShadowingMode::Allow; + let _ = ctx.insert_symbol( + handler, + name, + TyDecl::ConstantDecl(ConstantDecl { + decl_id: *decl_ref.id(), + }), + ); + ctx.const_shadowing_mode = prev_const_shadowing_mode; + } + ImplItem::Type(_) => {} + } + } + for item in impl_items { match item { ImplItem::Fn(impl_method_id) => { @@ -919,33 +967,7 @@ fn type_check_trait_implementation( let decl_ref = decl_engine.insert(impl_method, Some(impl_method_id)); impld_item_refs.insert((name, implementing_for), TyTraitItem::Fn(decl_ref)); } - ImplItem::Constant(decl_id) => { - let const_decl = engines.pe().get_constant(decl_id).as_ref().clone(); - let mut const_decl = type_check_const_decl( - handler, - ctx.by_ref().with_type_subst(&trait_type_mapping), - &const_decl, - trait_name, - is_contract, - &impld_item_refs, - &constant_checklist, - ) - .unwrap_or_else(|_| ty::TyConstantDecl::error(ctx.engines(), const_decl.clone())); - - const_decl.subst(&SubstTypesContext::new( - engines, - &trait_type_mapping, - !ctx.code_block_first_pass(), - )); - - // Remove this constant from the checklist. - let name = const_decl.call_path.suffix.clone(); - constant_checklist.remove(&name); - - // Add this constant to the "impld decls". - let decl_ref = decl_engine.insert(const_decl, Some(decl_id)); - impld_item_refs.insert((name, implementing_for), TyTraitItem::Constant(decl_ref)); - } + ImplItem::Constant(_decl_id) => {} ImplItem::Type(_) => {} } } @@ -1305,6 +1327,50 @@ fn type_check_impl_method( }) } +fn trait_const_item_value( + trait_decl: TyDecl, + engines: &Engines, + const_decl: &TyConstantDecl, +) -> Option { + fn get_const_decl_from_trait_items( + engines: &Engines, + items: &[TyTraitInterfaceItem], + name: &Ident, + ) -> Option> { + for item in items.iter() { + match item { + TyTraitInterfaceItem::Constant(decl) => { + let const_decl = engines.de().get_constant(decl.id()); + if const_decl.name() == name { + return Some(const_decl); + } + } + _ => continue, + } + } + None + } + + let trait_or_abi_const_decl = match trait_decl { + TyDecl::TraitDecl(decl) => get_const_decl_from_trait_items( + engines, + &engines.de().get_trait(&decl.decl_id).interface_surface, + const_decl.name(), + ), + TyDecl::AbiDecl(decl) => get_const_decl_from_trait_items( + engines, + &engines.de().get_abi(&decl.decl_id).interface_surface, + const_decl.name(), + ), + _ => unreachable!(), + }; + + match trait_or_abi_const_decl { + Some(trait_or_abi_const_decl) => trait_or_abi_const_decl.value.clone(), + None => None, + } +} + #[allow(clippy::too_many_arguments)] fn type_check_const_decl( handler: &Handler, @@ -1336,10 +1402,25 @@ fn type_check_const_decl( }; // type check the constant declaration - let const_decl = ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl.clone())?; + let mut const_decl = ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl.clone())?; let const_name = const_decl.call_path.suffix.clone(); + // Ensure that there is an expression if the constant in the base trait is not defined. + let trait_decl = ctx.resolve_call_path(handler, trait_name)?; + + let trait_const_item_value = trait_const_item_value(trait_decl, engines, &const_decl); + if trait_const_item_value.is_none() && const_decl.value.is_none() { + return Err(handler.emit_err(CompileError::ConstantRequiresExpression { + span: const_decl.span.clone(), + })); + } + + // Ensure the constant decl has a value, if none was set then it inherits the base trait/abi value. + if const_decl.value.is_none() { + const_decl.value = trait_const_item_value; + } + // Ensure that there aren't multiple definitions of this constant if impld_constant_ids.contains_key(&(const_name.clone(), self_type_id)) { return Err( diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs index 2f4504c1b90..640fbc09b72 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; use parsed_id::ParsedDeclId; use sway_error::{ @@ -6,7 +6,7 @@ use sway_error::{ handler::{ErrorEmitted, Handler}, warning::{CompileWarning, Warning}, }; -use sway_types::{style::is_upper_camel_case, Ident, Spanned}; +use sway_types::{style::is_upper_camel_case, Ident, Named, Spanned}; use crate::{ decl_engine::*, @@ -510,6 +510,8 @@ impl TyTraitDecl { .collect(), ); + let mut const_symbols = HashMap::::new(); + for item in interface_surface.iter() { match item { ty::TyTraitInterfaceItem::TraitFn(decl_ref) => { @@ -527,11 +529,10 @@ impl TyTraitDecl { } ty::TyTraitInterfaceItem::Constant(decl_ref) => { let const_decl = decl_engine.get_constant(decl_ref); - let const_name = const_decl.call_path.suffix.clone(); all_items.push(TyImplItem::Constant(decl_ref.clone())); - let _ = ctx.insert_symbol( - handler, - const_name.clone(), + let const_name = const_decl.call_path.suffix.clone(); + const_symbols.insert( + const_name, ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id: *decl_ref.id(), }), @@ -568,10 +569,24 @@ impl TyTraitDecl { &type_mapping, !ctx.code_block_first_pass(), )); - all_items.push(TyImplItem::Constant(decl_engine.insert( + let const_name = const_decl.name().clone(); + let const_has_value = const_decl.value.is_some(); + let decl_id = decl_engine.insert( const_decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref(), - ))); + ); + all_items.push(TyImplItem::Constant(decl_id.clone())); + + // If this non-interface item has a value, then we want to overwrite the + // the previously inserted constant symbol from the interface surface. + if const_has_value { + const_symbols.insert( + const_name, + ty::TyDecl::ConstantDecl(ty::ConstantDecl { + decl_id: *decl_id.id(), + }), + ); + } } ty::TyTraitItem::Type(decl_ref) => { let mut type_decl = (*decl_engine.get_type(decl_ref)).clone(); @@ -588,6 +603,11 @@ impl TyTraitDecl { } } + // Insert the constants into the namespace. + for (name, decl) in const_symbols.into_iter() { + let _ = ctx.insert_symbol(handler, name, decl); + } + // Insert the methods of the trait into the namespace. // Specifically do not check for conflicting definitions because // this is just a temporary namespace for type checking and diff --git a/sway-core/src/semantic_analysis/ast_node/modes.rs b/sway-core/src/semantic_analysis/ast_node/modes.rs index b2e3f25aaf4..b4d5a4aaf6c 100644 --- a/sway-core/src/semantic_analysis/ast_node/modes.rs +++ b/sway-core/src/semantic_analysis/ast_node/modes.rs @@ -9,6 +9,7 @@ pub enum AbiMode { #[derive(Clone, Copy, PartialEq, Eq, Default)] pub enum ConstShadowingMode { + Allow, Sequential, #[default] ItemStyle, diff --git a/sway-core/src/semantic_analysis/namespace/lexical_scope.rs b/sway-core/src/semantic_analysis/namespace/lexical_scope.rs index a3b549abae4..c0773f55110 100644 --- a/sway-core/src/semantic_analysis/namespace/lexical_scope.rs +++ b/sway-core/src/semantic_analysis/namespace/lexical_scope.rs @@ -640,6 +640,9 @@ impl Items { is_alias: bool, item: &ResolvedDeclaration, const_shadowing_mode: ConstShadowingMode| { + if const_shadowing_mode == ConstShadowingMode::Allow { + return; + } match (decl, item) { // TODO: Do not handle any shadowing errors while handling parsed declarations yet, // or else we will emit errors in a different order from the source code order. diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index 72eec9b4822..9078be6ff4d 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -82,7 +82,7 @@ pub struct TypeCheckContext<'a> { /// Whether or not a const declaration shadows previous const declarations sequentially. /// /// This is `Sequential` while checking const declarations in functions, otherwise `ItemStyle`. - const_shadowing_mode: ConstShadowingMode, + pub(crate) const_shadowing_mode: ConstShadowingMode, /// Whether or not a generic type parameters shadows previous generic type parameters. /// /// This is `Disallow` everywhere except while checking type parameters bounds in struct instantiation. 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 98b554311a6..9dc3792c07d 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 @@ -765,7 +765,7 @@ pub fn item_impl_to_declaration( ) .map(ImplItem::Fn), sway_ast::ItemImplItem::Const(const_item) => item_const_to_constant_declaration( - context, handler, engines, const_item, attributes, true, + context, handler, engines, const_item, attributes, false, ) .map(ImplItem::Constant), sway_ast::ItemImplItem::Type(type_item) => trait_type_to_trait_type_declaration( diff --git a/sway-error/src/error.rs b/sway-error/src/error.rs index fb129fa9903..d9ce634fa1b 100644 --- a/sway-error/src/error.rs +++ b/sway-error/src/error.rs @@ -679,6 +679,8 @@ pub enum CompileError { span: Span, prefix_span: Span, }, + #[error("Constant requires expression.")] + ConstantRequiresExpression { span: Span }, #[error("Constants cannot be shadowed. {shadowing_source} \"{name}\" shadows constant of the same name.")] ConstantsCannotBeShadowed { /// Defines what shadows the constant. @@ -1161,6 +1163,7 @@ impl Spanned for CompileError { ContractStorageFromExternalContext { span, .. } => span.clone(), InvalidOpcodeFromPredicate { span, .. } => span.clone(), ArrayOutOfBounds { span, .. } => span.clone(), + ConstantRequiresExpression { span, .. } => span.clone(), ConstantsCannotBeShadowed { name, .. } => name.span(), ConfigurablesCannotBeShadowed { name, .. } => name.span(), ConfigurablesCannotBeMatchedAgainst { name, .. } => name.span(), diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_abi/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_abi/src/main.sw index 4486078f32b..ec8dab4f17b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_abi/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_abi/src/main.sw @@ -2,15 +2,12 @@ contract; abi A { const A_WITH_DEFAULT: u32 = 3; - // TODO: Uncomment this case when https://github.com/FuelLabs/sway/issues/6348 is fixed. - // const A_NO_DEFAULT: u32; + const A_NO_DEFAULT: u32; const COMMON_1: u32 = 5; - // TODO: Uncomment this version (without default) when https://github.com/FuelLabs/sway/issues/6348 is fixed. - // const COMMON_2: u32; - const COMMON_2: u32 = 111; // TODO: Remove this one in favor of the one without default. + const COMMON_2: u32; fn a_with_default() -> u32; - // fn a_no_default() -> u32; + fn a_no_default() -> u32; fn common_1() -> u32; fn common_2() -> u32; @@ -34,9 +31,7 @@ abi A { } abi B { - // TODO: Uncomment this version (without default) when https://github.com/FuelLabs/sway/issues/6348 is fixed. - // const COMMON_1: u32; - const COMMON_1: u32 = 111; // TODO: Remove this one in favor of the one without default. + const COMMON_1: u32; const COMMON_2: u32 = 7; fn common_1() -> u32; @@ -54,7 +49,7 @@ abi B { impl A for Contract { const A_WITH_DEFAULT: u32 = 13; - // const A_NO_DEFAULT: u32 = 133; + const A_NO_DEFAULT: u32 = 133; const COMMON_1: u32 = 15; const COMMON_2: u32 = 155; @@ -62,9 +57,9 @@ impl A for Contract { Self::A_WITH_DEFAULT } - // fn a_no_default() -> u32 { - // Self::A_NO_DEFAULT - // } + fn a_no_default() -> u32 { + Self::A_NO_DEFAULT + } fn common_1() -> u32 { Self::COMMON_1 @@ -92,14 +87,12 @@ impl B for Contract { fn test() { let a = abi(A, CONTRACT_ID); // TODO: Enable these asserts once these bugs are fixed: - // https://github.com/FuelLabs/sway/issues/6310 // https://github.com/FuelLabs/sway/issues/6306 - // https://github.com/FuelLabs/sway/issues/6348 - // assert_eq(13, a.a_with_default()); + assert_eq(13, a.a_with_default()); // assert_eq(13, a.a_implemented_with_default()); - // assert_eq(133, a.a_no_default()); + assert_eq(133, a.a_no_default()); // assert_eq(133, a.a_implemented_no_default()); // assert_eq(15, a.common_1()); @@ -110,9 +103,9 @@ fn test() { let b = abi(B, CONTRACT_ID); - // assert_eq(177, b.common_1()); + assert_eq(177, b.common_1()); // assert_eq(177, b.b_implemented_common_1()); - // assert_eq(17, b.common_2()); + assert_eq(17, b.common_2()); // assert_eq(17, b.b_implemented_common_2()); } From bda4d4453c7f0b4b7f340eb0ca1434eb5cab3c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Matos?= Date: Fri, 6 Dec 2024 21:20:57 +0000 Subject: [PATCH 37/52] Change `SubstTypesContext` to contain an optional `TypeSubstMap`. (#6773) ## Description Changes `SubstTypesContext` to contain an optional `TypeSubstMap`. This is to make this usable from collection context where no type substitution needs to be done. ## 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). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --- sway-core/src/decl_engine/ref.rs | 2 +- sway-core/src/type_system/id.rs | 5 +++- .../src/type_system/substitute/subst_types.rs | 26 ++++++++++++------- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/sway-core/src/decl_engine/ref.rs b/sway-core/src/decl_engine/ref.rs index 4fb8f1bb87f..d3b2d15feae 100644 --- a/sway-core/src/decl_engine/ref.rs +++ b/sway-core/src/decl_engine/ref.rs @@ -102,7 +102,7 @@ where let decl_engine = ctx.engines.de(); if ctx .type_subst_map - .source_ids_contains_concrete_type(ctx.engines) + .is_some_and(|tsm| tsm.source_ids_contains_concrete_type(ctx.engines)) || !decl_engine.get(&self.id).is_concrete(ctx.engines) { let mut decl = (*decl_engine.get(&self.id)).clone(); diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index 5e8f5bba90e..f429a0d2283 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -95,7 +95,10 @@ impl CollectTypesMetadata for TypeId { impl SubstTypes for TypeId { fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges { let type_engine = ctx.engines.te(); - if let Some(matching_id) = ctx.type_subst_map.find_match(*self, ctx.engines) { + if let Some(matching_id) = ctx + .type_subst_map + .and_then(|tsm| tsm.find_match(*self, ctx.engines)) + { if !matches!(&*type_engine.get(matching_id), TypeInfo::ErrorRecovery(_)) { *self = matching_id; HasChanges::Yes diff --git a/sway-core/src/type_system/substitute/subst_types.rs b/sway-core/src/type_system/substitute/subst_types.rs index f5107ebd59a..8b2ea5068e1 100644 --- a/sway-core/src/type_system/substitute/subst_types.rs +++ b/sway-core/src/type_system/substitute/subst_types.rs @@ -24,31 +24,39 @@ impl std::ops::BitOr for HasChanges { } } -pub struct SubstTypesContext<'a, 'b> { - pub engines: &'a Engines, - pub type_subst_map: &'b TypeSubstMap, +pub struct SubstTypesContext<'eng, 'tsm> { + pub engines: &'eng Engines, + pub type_subst_map: Option<&'tsm TypeSubstMap>, pub subst_function_body: bool, } -impl<'a, 'b> SubstTypesContext<'a, 'b> { +impl<'eng, 'tsm> SubstTypesContext<'eng, 'tsm> { pub fn new( - engines: &'a Engines, - type_subst_map: &'b TypeSubstMap, + engines: &'eng Engines, + type_subst_map: &'tsm TypeSubstMap, subst_function_body: bool, - ) -> SubstTypesContext<'a, 'b> { + ) -> SubstTypesContext<'eng, 'tsm> { SubstTypesContext { engines, - type_subst_map, + type_subst_map: Some(type_subst_map), subst_function_body, } } + + pub fn dummy(engines: &'eng Engines) -> SubstTypesContext<'eng, 'tsm> { + SubstTypesContext { + engines, + type_subst_map: None, + subst_function_body: false, + } + } } pub trait SubstTypes { fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges; fn subst(&mut self, ctx: &SubstTypesContext) -> HasChanges { - if ctx.type_subst_map.is_empty() { + if ctx.type_subst_map.is_some_and(|tsm| tsm.is_empty()) { HasChanges::No } else { self.subst_inner(ctx) From ff8291a2b1a7997f257120b89aeec25ac3bd8264 Mon Sep 17 00:00:00 2001 From: Cameron Carstens Date: Sat, 7 Dec 2024 01:01:54 +0000 Subject: [PATCH 38/52] Add `mod` to `U128` (#6771) ## Description The `mod` trait implementation was missing for `U128`. This has been added. ## 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). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. Co-authored-by: K1-R1 <77465250+K1-R1@users.noreply.github.com> Co-authored-by: IGI-111 --- sway-lib-std/src/u128.sw | 11 + .../revert_inline_tests/src/main.sw | 2 +- .../u128_inline_tests/src/main.sw | 548 +++++++++++------- 3 files changed, 339 insertions(+), 222 deletions(-) diff --git a/sway-lib-std/src/u128.sw b/sway-lib-std/src/u128.sw index 8eb22317b64..ef016cfe560 100644 --- a/sway-lib-std/src/u128.sw +++ b/sway-lib-std/src/u128.sw @@ -668,6 +668,17 @@ impl core::ops::Divide for U128 { } } +impl core::ops::Mod for U128 { + fn modulo(self, other: Self) -> Self { + assert(other != Self::zero()); + + // a mod b = a - b * (a / b) + let quotient = self / other; + let product = quotient * other; + self - product + } +} + fn u64_checked_add(a: u64, b: u64) -> Option { let of = asm(a: a, b: b, res) { add res a b; diff --git a/test/src/in_language_tests/test_programs/revert_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/revert_inline_tests/src/main.sw index 64c74e30b63..e11a6f413cd 100644 --- a/test/src/in_language_tests/test_programs/revert_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/revert_inline_tests/src/main.sw @@ -18,4 +18,4 @@ fn pass_revert_require() { #[test(should_revert)] fn revert_revert_with_log() { revert_with_log("error") -} \ No newline at end of file +} diff --git a/test/src/in_language_tests/test_programs/u128_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/u128_inline_tests/src/main.sw index 4d7acda31fb..584a1716ad4 100644 --- a/test/src/in_language_tests/test_programs/u128_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/u128_inline_tests/src/main.sw @@ -1,6 +1,14 @@ library; -use std::{u128::U128, registers::flags, flags::{set_flags, disable_panic_on_unsafe_math, disable_panic_on_overflow}}; +use std::{ + flags::{ + disable_panic_on_overflow, + disable_panic_on_unsafe_math, + set_flags, + }, + registers::flags, + u128::U128, +}; #[test] fn u128_from_u8() { @@ -686,6 +694,60 @@ fn u128_root() { assert(root_of_u_128 == U128::from((0, 1))); } +#[test] +fn u128_mod() { + let u128_zero = U128::zero(); + let u128_1 = U128::from((0, 1)); + let u128_2 = U128::from((0, 2)); + let u128_3 = U128::from((0, 3)); + let u128_max = U128::max(); + + assert(u128_zero % u128_1 == u128_zero); + assert(u128_zero % u128_2 == u128_zero); + assert(u128_zero % u128_3 == u128_zero); + assert(u128_zero % u128_max == u128_zero); + + assert(u128_1 % u128_1 == u128_zero); + assert(U128::from((0, 10)) % u128_1 == u128_zero); + assert(U128::from((0, 10000)) % u128_1 == u128_zero); + assert(u128_max % u128_1 == u128_zero); + + assert(u128_2 % u128_2 == u128_zero); + assert(u128_3 % u128_2 == u128_1); + assert(U128::from((0, 10)) % u128_2 == u128_zero); + assert(U128::from((0, 10000)) % u128_2 == u128_zero); + assert(U128::from((0, 10001)) % u128_2 == u128_1); + assert(U128::from((0, u64::max())) % u128_2 == u128_1); + assert(U128::from((u64::max(), 0)) % u128_2 == u128_zero); + assert(U128::from((u64::max(), 1)) % u128_2 == u128_1); + assert(u128_max % u128_2 == u128_1); + + assert(u128_3 % u128_3 == u128_zero); + assert(u128_2 % u128_3 == u128_2); + assert(u128_1 % u128_3 == u128_1); + assert(U128::from((0, 30000)) % u128_3 == u128_zero); + assert(U128::from((0, 30001)) % u128_3 == u128_1); + assert(U128::from((0, 30002)) % u128_3 == u128_2); + assert(U128::from((u64::max(), 0)) % u128_3 == u128_zero); + assert(U128::from((u64::max(), 1)) % u128_3 == u128_1); + assert(U128::from((u64::max(), 2)) % u128_3 == u128_2); + assert(u128_max % u128_3 == u128_zero); + + assert(U128::from((u64::max(), 0)) % U128::from((u64::max(), 0)) == u128_zero); + assert(U128::from((u64::max(), 1)) % U128::from((u64::max(), 0)) == u128_1); + assert(U128::from((u64::max(), 2)) % U128::from((u64::max(), 0)) == u128_2); + assert(U128::from((u64::max(), 3)) % U128::from((u64::max(), 0)) == u128_3); + assert(u128_max % U128::from((u64::max(), 0)) == U128::from((0, u64::max()))); +} + +#[test(should_revert)] +fn revert_u128_mod_zero() { + let a = U128::from((0, 1)); + let b = U128::zero(); + + let result = a % b; +} + #[test] fn u128_log() { let prior_flags = flags(); @@ -781,228 +843,272 @@ fn parity_u128_log_with_ruint() { // Failure cases found by comparing parity with ruint implementation of U128 // https://docs.rs/ruint/latest/src/ruint/log.rs.html#45-89 let a = [ - 2, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, - 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 15, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, - 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 29, - 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, - 41, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, - 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, - 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 60, 60, - 60, 60, 61, 61, 61, 62, 62, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 70, - 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, - 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 83, 83, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, - 86, 86, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, - 88, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 90, - 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, - 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 98, 98, 98, 98, 98, 98, 98, - 98, 98, 98, 98, 98, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 100, 100, 100, 100, 100, - 100, 100, 100, 100, + 2, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, + 14, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, + 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 29, 29, 29, + 29, 29, 30, 30, 30, 30, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, + 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 60, 60, 60, + 60, 61, 61, 61, 62, 62, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100, 100, ]; let b = [ - 3, 3, 5, 6, 7, 3, 6, 7, 3, 7, 3, 3, 9, 10, 11, 12, 13, 14, 15, 3, 10, 11, 12, 13, 14, 15, - 3, 11, 12, 13, 14, 15, 3, 12, 13, 14, 15, 3, 13, 14, 15, 3, 14, 15, 3, 15, 3, 3, 5, 6, 7, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 3, 5, 6, 7, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, - 6, 7, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, - 6, 7, 25, 26, 27, 28, 29, 30, 31, 3, 6, 7, 26, 27, 28, 29, 30, 31, 3, 6, 7, 27, 28, 29, 30, - 31, 3, 6, 7, 28, 29, 30, 31, 3, 6, 7, 29, 30, 31, 3, 6, 7, 30, 31, 3, 6, 7, 31, 3, 6, 7, 3, - 6, 7, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 6, 7, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 6, 7, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 3, 6, 7, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 3, 7, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 3, 7, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 3, 7, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 3, 7, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 63, 3, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 56, 57, 58, - 59, 60, 61, 62, 63, 3, 57, 58, 59, 60, 61, 62, 63, 3, 58, 59, 60, 61, 62, 63, 3, 59, 60, - 61, 62, 63, 3, 60, 61, 62, 63, 3, 61, 62, 63, 3, 62, 63, 3, 63, 3, 3, 5, 6, 7, 9, 10, 11, - 12, 13, 14, 15, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, - 12, 13, 14, 15, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, - 13, 14, 15, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, - 15, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 69, 70, - 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, - 10, 11, 12, 13, 14, 15, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 74, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, - 11, 12, 13, 14, 15, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, - 7, 9, 10, 11, 12, 13, 14, 15, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, - 10, 11, 12, 13, 14, 15, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, - 7, 10, 11, 12, 13, 14, 15, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, - 14, 15, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, - 12, 13, 14, 15, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, - 11, 12, 13, 14, 15, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, - 11, 12, 13, 14, 15, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, - 12, 13, 14, 15, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, - 14, 15, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 93, 94, 95, 96, 97, - 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, - 10, 11, 12, 13, 14, 15, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 96, - 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, - 12, 13, 14, 15, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 99, 100, 3, 5, 6, 7, 10, - 11, 12, 13, 14, 15, 100, 3, 5, 6, 7, 11, 12, 13, 14, 15, + 3, 3, 5, 6, 7, 3, 6, 7, 3, 7, 3, 3, 9, 10, 11, 12, 13, 14, 15, 3, 10, 11, + 12, 13, 14, 15, 3, 11, 12, 13, 14, 15, 3, 12, 13, 14, 15, 3, 13, 14, 15, 3, + 14, 15, 3, 15, 3, 3, 5, 6, 7, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 3, 5, 6, 7, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 3, 5, 6, 7, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, + 5, 6, 7, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 3, 5, 6, 7, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 24, + 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 25, 26, 27, 28, 29, 30, 31, 3, 6, + 7, 26, 27, 28, 29, 30, 31, 3, 6, 7, 27, 28, 29, 30, 31, 3, 6, 7, 28, 29, 30, + 31, 3, 6, 7, 29, 30, 31, 3, 6, 7, 30, 31, 3, 6, 7, 31, 3, 6, 7, 3, 6, 7, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 6, 7, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 3, 6, 7, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 6, + 7, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 3, 7, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, + 7, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 3, 7, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 3, 7, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 3, 7, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 3, 7, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 3, 7, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 3, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 3, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 3, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 3, 56, 57, 58, 59, 60, 61, 62, 63, 3, 57, 58, 59, 60, 61, + 62, 63, 3, 58, 59, 60, 61, 62, 63, 3, 59, 60, 61, 62, 63, 3, 60, 61, 62, 63, + 3, 61, 62, 63, 3, 62, 63, 3, 63, 3, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, + 6, 7, 9, 10, 11, 12, 13, 14, 15, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, + 14, 15, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, + 7, 9, 10, 11, 12, 13, 14, 15, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, + 6, 7, 9, 10, 11, 12, 13, 14, 15, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, + 13, 14, 15, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, + 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, + 11, 12, 13, 14, 15, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, + 15, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, + 7, 10, 11, 12, 13, 14, 15, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, + 5, 6, 7, 10, 11, 12, 13, 14, 15, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, + 5, 6, 7, 10, 11, 12, 13, 14, 15, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, + 7, 10, 11, 12, 13, 14, 15, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, + 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 97, 98, 99, 100, + 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 100, 3, 5, 6, 7, 11, + 12, 13, 14, 15, ]; let expected = [ - 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, - 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 2, 0, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 3, 1, 1, 0, - 0, 0, 3, 1, 1, 0, 0, 3, 1, 1, 0, 3, 1, 1, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 3, 0, 3, 3, 2, 2, 2, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, - 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, - 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, - 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, - 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 4, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, + 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 2, 0, 2, 2, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 3, + 1, 1, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 3, 1, 1, 0, 0, 3, 1, 1, 0, 3, 1, 1, 3, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 3, 0, 3, 3, 2, + 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, + 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, + 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, + 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, ]; @@ -1065,7 +1171,7 @@ fn u128_overflowing_pow() { let a = U128::max(); let res = a.pow(2); - + assert(res == U128::from((0, 0))); set_flags(prior_flags); @@ -1081,4 +1187,4 @@ fn u128_unsafemath_log2() { assert(res == U128::zero()); set_flags(prior_flags); -} \ No newline at end of file +} From 36849be1e0048ff10cf39ce261a154b434e5e6fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Matos?= Date: Wed, 11 Dec 2024 04:56:09 +0000 Subject: [PATCH 39/52] Associate lexical scopes with their respective declarations. (#6780) This adds a mapping from a lexical scope to the declaration that lexically corresponds to it. This is necessary for some upcoming collection context PR. ## 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). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --- .../semantic_analysis/ast_node/code_block.rs | 23 +++++++----- .../ast_node/declaration/abi.rs | 10 ++--- .../ast_node/declaration/enum.rs | 12 +++--- .../ast_node/declaration/function.rs | 10 ++--- .../ast_node/declaration/impl_trait.rs | 37 +++++++++++-------- .../ast_node/declaration/struct.rs | 15 ++++---- .../ast_node/declaration/trait.rs | 10 ++--- .../ast_node/declaration/trait_fn.rs | 12 +++--- .../ast_node/expression/typed_expression.rs | 2 +- .../namespace/lexical_scope.rs | 3 ++ .../src/semantic_analysis/namespace/module.rs | 7 +++- .../symbol_collection_context.rs | 13 ++++--- 12 files changed, 80 insertions(+), 74 deletions(-) diff --git a/sway-core/src/semantic_analysis/ast_node/code_block.rs b/sway-core/src/semantic_analysis/ast_node/code_block.rs index c82523f9395..02cf5e581e7 100644 --- a/sway-core/src/semantic_analysis/ast_node/code_block.rs +++ b/sway-core/src/semantic_analysis/ast_node/code_block.rs @@ -11,15 +11,20 @@ impl ty::TyCodeBlock { ctx: &mut SymbolCollectionContext, code_block: &CodeBlock, ) -> Result<(), ErrorEmitted> { - let _ = ctx.scoped(engines, code_block.whole_block_span.clone(), |scoped_ctx| { - let _ = code_block - .contents - .iter() - .map(|node| ty::TyAstNode::collect(handler, engines, scoped_ctx, node)) - .filter_map(|res| res.ok()) - .collect::>(); - Ok(()) - }); + let _ = ctx.scoped( + engines, + code_block.whole_block_span.clone(), + None, + |scoped_ctx| { + let _ = code_block + .contents + .iter() + .map(|node| ty::TyAstNode::collect(handler, engines, scoped_ctx, node)) + .filter_map(|res| res.ok()) + .collect::>(); + Ok(()) + }, + ); Ok(()) } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs index a22fd3925f6..30db0276496 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs @@ -39,14 +39,10 @@ impl ty::TyAbiDecl { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let abi_decl = engines.pe().get_abi(decl_id); - ctx.insert_parsed_symbol( - handler, - engines, - abi_decl.name.clone(), - Declaration::AbiDeclaration(*decl_id), - )?; + let decl = Declaration::AbiDeclaration(*decl_id); + ctx.insert_parsed_symbol(handler, engines, abi_decl.name.clone(), decl.clone())?; - let _ = ctx.scoped(engines, abi_decl.span.clone(), |scoped_ctx| { + let _ = ctx.scoped(engines, abi_decl.span.clone(), Some(decl), |scoped_ctx| { abi_decl.interface_surface.iter().for_each(|item| { let _ = TyTraitItem::collect(handler, engines, scoped_ctx, item); }); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs index 5e4839c0172..5f564978960 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -16,15 +16,13 @@ impl ty::TyEnumDecl { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let enum_decl = engines.pe().get_enum(decl_id); - ctx.insert_parsed_symbol( - handler, - engines, - enum_decl.name.clone(), - Declaration::EnumDeclaration(*decl_id), - )?; + let decl = Declaration::EnumDeclaration(*decl_id); + ctx.insert_parsed_symbol(handler, engines, enum_decl.name.clone(), decl.clone())?; // create a namespace for the decl, used to create a scope for generics - let _ = ctx.scoped(engines, enum_decl.span.clone(), |mut _ctx| Ok(())); + let _ = ctx.scoped(engines, enum_decl.span.clone(), Some(decl), |mut _ctx| { + Ok(()) + }); Ok(()) } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs index 69603909545..2b1fcd5d5a2 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -28,15 +28,11 @@ impl ty::TyFunctionDecl { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let fn_decl = engines.pe().get_function(decl_id); - let _ = ctx.insert_parsed_symbol( - handler, - engines, - fn_decl.name.clone(), - Declaration::FunctionDeclaration(*decl_id), - ); + let decl = Declaration::FunctionDeclaration(*decl_id); + let _ = ctx.insert_parsed_symbol(handler, engines, fn_decl.name.clone(), decl.clone()); // create a namespace for the function - let _ = ctx.scoped(engines, fn_decl.span.clone(), |scoped_ctx| { + let _ = ctx.scoped(engines, fn_decl.span.clone(), Some(decl), |scoped_ctx| { TyCodeBlock::collect(handler, engines, scoped_ctx, &fn_decl.body) }); Ok(()) diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index 87e2f23fcee..f881cbbef60 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -39,27 +39,34 @@ impl TyImplSelfOrTrait { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let impl_trait = engines.pe().get_impl_self_or_trait(decl_id); + + let decl = Declaration::ImplSelfOrTrait(*decl_id); ctx.insert_parsed_symbol( handler, engines, impl_trait.trait_name.suffix.clone(), - Declaration::ImplSelfOrTrait(*decl_id), + decl.clone(), )?; - let _ = ctx.scoped(engines, impl_trait.block_span.clone(), |scoped_ctx| { - impl_trait.items.iter().for_each(|item| match item { - ImplItem::Fn(decl_id) => { - let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, decl_id); - } - ImplItem::Constant(decl_id) => { - let _ = TyConstantDecl::collect(handler, engines, scoped_ctx, decl_id); - } - ImplItem::Type(decl_id) => { - let _ = TyTraitType::collect(handler, engines, scoped_ctx, decl_id); - } - }); - Ok(()) - }); + let _ = ctx.scoped( + engines, + impl_trait.block_span.clone(), + Some(decl), + |scoped_ctx| { + impl_trait.items.iter().for_each(|item| match item { + ImplItem::Fn(decl_id) => { + let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, decl_id); + } + ImplItem::Constant(decl_id) => { + let _ = TyConstantDecl::collect(handler, engines, scoped_ctx, decl_id); + } + ImplItem::Type(decl_id) => { + let _ = TyTraitType::collect(handler, engines, scoped_ctx, decl_id); + } + }); + Ok(()) + }, + ); Ok(()) } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs index 4ad0a268284..18e7a6e394e 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -16,15 +16,16 @@ impl ty::TyStructDecl { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let struct_decl = engines.pe().get_struct(decl_id); - ctx.insert_parsed_symbol( - handler, - engines, - struct_decl.name.clone(), - Declaration::StructDeclaration(*decl_id), - )?; + let decl = Declaration::StructDeclaration(*decl_id); + ctx.insert_parsed_symbol(handler, engines, struct_decl.name.clone(), decl.clone())?; // create a namespace for the decl, used to create a scope for generics - let _ = ctx.scoped(engines, struct_decl.span.clone(), |_scoped_ctx| Ok(())); + let _ = ctx.scoped( + engines, + struct_decl.span.clone(), + Some(decl), + |_scoped_ctx| Ok(()), + ); Ok(()) } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs index 640fbc09b72..e25a568cb3d 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -53,15 +53,11 @@ impl TyTraitDecl { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let trait_decl = engines.pe().get_trait(decl_id); - ctx.insert_parsed_symbol( - handler, - engines, - trait_decl.name.clone(), - Declaration::TraitDeclaration(*decl_id), - )?; + let decl = Declaration::TraitDeclaration(*decl_id); + ctx.insert_parsed_symbol(handler, engines, trait_decl.name.clone(), decl.clone())?; // A temporary namespace for checking within the trait's scope. - let _ = ctx.scoped(engines, trait_decl.span.clone(), |scoped_ctx| { + let _ = ctx.scoped(engines, trait_decl.span.clone(), Some(decl), |scoped_ctx| { trait_decl.interface_surface.iter().for_each(|item| { let _ = TyTraitItem::collect(handler, engines, scoped_ctx, item); }); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs index fc2b0fc6c3f..0777b17bcf5 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs @@ -24,13 +24,11 @@ impl ty::TyTraitFn { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let trait_fn = engines.pe().get_trait_fn(decl_id); - ctx.insert_parsed_symbol( - handler, - engines, - trait_fn.name.clone(), - Declaration::TraitFnDeclaration(*decl_id), - )?; - let _ = ctx.scoped(engines, trait_fn.span.clone(), |_scoped_ctx| Ok(())); + let decl = Declaration::TraitFnDeclaration(*decl_id); + ctx.insert_parsed_symbol(handler, engines, trait_fn.name.clone(), decl.clone())?; + let _ = ctx.scoped(engines, trait_fn.span.clone(), Some(decl), |_scoped_ctx| { + Ok(()) + }); Ok(()) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 0fa64d14598..06220dcac74 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -216,7 +216,7 @@ impl ty::TyExpression { .iter() .map(|branch| { // create a new namespace for this branch result - ctx.scoped(engines, branch.span.clone(), |scoped_ctx| { + ctx.scoped(engines, branch.span.clone(), None, |scoped_ctx| { Self::collect(handler, engines, scoped_ctx, &branch.result) }) .0 diff --git a/sway-core/src/semantic_analysis/namespace/lexical_scope.rs b/sway-core/src/semantic_analysis/namespace/lexical_scope.rs index c0773f55110..308b5c0b989 100644 --- a/sway-core/src/semantic_analysis/namespace/lexical_scope.rs +++ b/sway-core/src/semantic_analysis/namespace/lexical_scope.rs @@ -71,6 +71,9 @@ pub struct LexicalScope { pub children: Vec, /// The parent scope associated with this scope. Will be None for a root scope. pub parent: Option, + /// The declaration associated with this scope. This will initially be a [ParsedDeclId], + /// but can be replaced to be a [DeclId] once the declaration is type checked. + pub declaration: Option, } /// The set of items that exist within some lexical scope via declaration or importing. diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index 319f4abb247..af89e4469c9 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -277,11 +277,16 @@ impl Module { } /// Pushes a new scope to the module's lexical scope hierarchy. - pub fn push_new_lexical_scope(&mut self, span: Span) -> LexicalScopeId { + pub fn push_new_lexical_scope( + &mut self, + span: Span, + declaration: Option, + ) -> LexicalScopeId { let previous_scope_id = self.current_lexical_scope_id(); let new_scoped_id = { self.lexical_scopes.push(LexicalScope { parent: Some(previous_scope_id), + declaration, ..Default::default() }); self.lexical_scopes.len() - 1 diff --git a/sway-core/src/semantic_analysis/symbol_collection_context.rs b/sway-core/src/semantic_analysis/symbol_collection_context.rs index 2a3be6aa35d..f831c2226ea 100644 --- a/sway-core/src/semantic_analysis/symbol_collection_context.rs +++ b/sway-core/src/semantic_analysis/symbol_collection_context.rs @@ -1,7 +1,6 @@ use crate::{ language::{parsed::Declaration, Visibility}, - namespace::LexicalScopeId, - namespace::ModulePath, + namespace::{LexicalScopeId, ModulePath, ResolvedDeclaration}, semantic_analysis::Namespace, Engines, }; @@ -41,12 +40,14 @@ impl SymbolCollectionContext { &mut self, engines: &Engines, span: Span, + decl: Option, with_scoped_ctx: impl FnOnce(&mut SymbolCollectionContext) -> Result, ) -> (Result, LexicalScopeId) { - let lexical_scope_id: LexicalScopeId = self - .namespace - .module_mut(engines) - .write(engines, |m| m.push_new_lexical_scope(span.clone())); + let decl = decl.map(ResolvedDeclaration::Parsed); + let lexical_scope_id: LexicalScopeId = + self.namespace.module_mut(engines).write(engines, |m| { + m.push_new_lexical_scope(span.clone(), decl.clone()) + }); let ret = with_scoped_ctx(self); self.namespace .module_mut(engines) From f7e4fb42efeaba9711baa4f0b9b264e3c568718a Mon Sep 17 00:00:00 2001 From: Alexandr Date: Thu, 12 Dec 2024 05:33:16 +0100 Subject: [PATCH 40/52] typo-Update deploy.rs (#6783) Description: Fixed errors and inaccuracies in the project's textual materials. Type of Change: Fixing errors (typos, grammatical mistakes, etc.) Testing: Changes have been reviewed to ensure no new errors were introduced. Impact: Improved readability of texts and documentation. Additional Notes: Regular text audits are recommended to maintain a high standard of quality. Co-authored-by: Sophie Dankel <47993817+sdankel@users.noreply.github.com> --- forc-plugins/forc-client/tests/deploy.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forc-plugins/forc-client/tests/deploy.rs b/forc-plugins/forc-client/tests/deploy.rs index aeb1e45bf52..7f881bb15d9 100644 --- a/forc-plugins/forc-client/tests/deploy.rs +++ b/forc-plugins/forc-client/tests/deploy.rs @@ -1303,7 +1303,7 @@ async fn offset_shifted_abi_works() { let loader_with_configs_from_sdk = call_with_sdk_generated_overrides(&node_url, contract_id).await; - // Genearating the forc-deploy loader bytecode and loader abi. + // Generating the forc-deploy loader bytecode and loader abi. let loader_with_configs_from_forc = call_with_forc_generated_overrides(&node_url, contract_id).await; pretty_assertions::assert_eq!(loader_with_configs_from_forc, loader_with_configs_from_sdk); From 192f16382837fadbc625d8689e366f21b54eeda5 Mon Sep 17 00:00:00 2001 From: Cameron Carstens Date: Thu, 12 Dec 2024 07:26:49 +0000 Subject: [PATCH 41/52] Update `output_asset_to()` and `output_asset_id()` to handle `Output::Variable` (#6781) ## Description Allows for fetching of the `AssetId` and the to `Address` from an `Output::Variable`. ## 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). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --------- Co-authored-by: K1-R1 <77465250+K1-R1@users.noreply.github.com> Co-authored-by: IGI-111 --- sway-lib-std/src/outputs.sw | 11 ++ test/src/sdk-harness/Forc.lock | 2 +- test/src/sdk-harness/Forc.toml | 2 +- .../test_artifacts/tx_contract/src/main.sw | 3 +- .../tx_output_change_contract/src/main.sw | 13 -- .../Forc.toml | 2 +- .../tx_output_contract/src/main.sw | 35 ++++++ .../tx_output_predicate/src/main.sw | 2 +- .../tx_type_predicate/src/main.sw | 2 +- .../tx_witness_predicate/src/main.sw | 11 +- .../test_projects/tx_fields/mod.rs | 115 +++++++++++++----- 11 files changed, 147 insertions(+), 51 deletions(-) delete mode 100644 test/src/sdk-harness/test_artifacts/tx_output_change_contract/src/main.sw rename test/src/sdk-harness/test_artifacts/{tx_output_change_contract => tx_output_contract}/Forc.toml (81%) create mode 100644 test/src/sdk-harness/test_artifacts/tx_output_contract/src/main.sw diff --git a/sway-lib-std/src/outputs.sw b/sway-lib-std/src/outputs.sw index 69ccac1b23b..527a94de2fc 100644 --- a/sway-lib-std/src/outputs.sw +++ b/sway-lib-std/src/outputs.sw @@ -28,6 +28,9 @@ pub const GTF_OUTPUT_COIN_ASSET_ID = 0x303; // pub const GTF_OUTPUT_CONTRACT_CREATED_CONTRACT_ID = 0x307; // pub const GTF_OUTPUT_CONTRACT_CREATED_STATE_ROOT = 0x308; +const OUTPUT_VARIABLE_ASSET_ID_OFFSET = 48; +const OUTPUT_VARIABLE_TO_OFFSET = 8; + /// The output type for a transaction. pub enum Output { /// A coin output. @@ -228,6 +231,10 @@ pub fn output_asset_id(index: u64) -> Option { match output_type(index) { Some(Output::Coin) => Some(AssetId::from(__gtf::(index, GTF_OUTPUT_COIN_ASSET_ID))), Some(Output::Change) => Some(AssetId::from(__gtf::(index, GTF_OUTPUT_COIN_ASSET_ID))), + Some(Output::Variable) => { + let ptr = output_pointer(index).unwrap(); + Some(AssetId::from(ptr.add_uint_offset(OUTPUT_VARIABLE_ASSET_ID_OFFSET).read::())) + }, _ => None, } } @@ -260,6 +267,10 @@ pub fn output_asset_to(index: u64) -> Option
{ match output_type(index) { Some(Output::Coin) => Some(__gtf::
(index, GTF_OUTPUT_COIN_TO)), Some(Output::Change) => Some(__gtf::
(index, GTF_OUTPUT_COIN_TO)), + Some(Output::Variable) => { + let ptr = output_pointer(index).unwrap(); + Some(Address::from(ptr.add_uint_offset(OUTPUT_VARIABLE_TO_OFFSET).read::())) + }, _ => None, } } diff --git a/test/src/sdk-harness/Forc.lock b/test/src/sdk-harness/Forc.lock index 6db035f3459..ee70e29936a 100644 --- a/test/src/sdk-harness/Forc.lock +++ b/test/src/sdk-harness/Forc.lock @@ -420,7 +420,7 @@ source = "member" dependencies = ["std"] [[package]] -name = "tx_output_change_contract" +name = "tx_output_contract" source = "member" dependencies = ["std"] diff --git a/test/src/sdk-harness/Forc.toml b/test/src/sdk-harness/Forc.toml index e6b081c63d0..2f4dd422291 100644 --- a/test/src/sdk-harness/Forc.toml +++ b/test/src/sdk-harness/Forc.toml @@ -78,7 +78,7 @@ members = [ "test_artifacts/storage_vec/svec_u64", "test_artifacts/tx_contract", "test_artifacts/tx_input_count_predicate", - "test_artifacts/tx_output_change_contract", + "test_artifacts/tx_output_contract", "test_artifacts/tx_output_contract_creation_predicate", "test_artifacts/tx_output_count_predicate", "test_artifacts/tx_output_predicate", diff --git a/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw index ed80700620c..bce0730c604 100644 --- a/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw @@ -135,7 +135,8 @@ impl TxContractTest for Contract { let mut iter = 0; while iter < expected_data_bytes.len() { - if data.get(iter).unwrap() != expected_data_bytes.get(iter).unwrap() { + if data.get(iter).unwrap() != expected_data_bytes.get(iter).unwrap() + { return false } iter += 1; diff --git a/test/src/sdk-harness/test_artifacts/tx_output_change_contract/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_output_change_contract/src/main.sw deleted file mode 100644 index 32aeeb5e7c9..00000000000 --- a/test/src/sdk-harness/test_artifacts/tx_output_change_contract/src/main.sw +++ /dev/null @@ -1,13 +0,0 @@ -contract; - -use std::asset::transfer; - -abi TxOutputChangeContract { - fn send_assets(to: Address, asset: AssetId, amount: u64); -} - -impl TxOutputChangeContract for Contract { - fn send_assets(to: Address, asset: AssetId, amount: u64) { - transfer(Identity::Address(to), asset, amount); - } -} diff --git a/test/src/sdk-harness/test_artifacts/tx_output_change_contract/Forc.toml b/test/src/sdk-harness/test_artifacts/tx_output_contract/Forc.toml similarity index 81% rename from test/src/sdk-harness/test_artifacts/tx_output_change_contract/Forc.toml rename to test/src/sdk-harness/test_artifacts/tx_output_contract/Forc.toml index 5a053f78b77..824dbc61360 100644 --- a/test/src/sdk-harness/test_artifacts/tx_output_change_contract/Forc.toml +++ b/test/src/sdk-harness/test_artifacts/tx_output_contract/Forc.toml @@ -2,7 +2,7 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" -name = "tx_output_change_contract" +name = "tx_output_contract" [dependencies] std = { path = "../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_artifacts/tx_output_contract/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_output_contract/src/main.sw new file mode 100644 index 00000000000..3682db6ea9b --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/tx_output_contract/src/main.sw @@ -0,0 +1,35 @@ +contract; + +use std::asset::transfer; +use std::outputs::*; + +abi TxOutputContract { + fn send_assets_change(to: Address, asset: AssetId, amount: u64); + fn send_assets_variable(to: Address, asset: AssetId, index: u64) -> (Address, AssetId, u64); +} + +impl TxOutputContract for Contract { + fn send_assets_change(to: Address, asset: AssetId, amount: u64) { + transfer(Identity::Address(to), asset, amount); + } + + fn send_assets_variable(to: Address, asset: AssetId, index: u64) -> (Address, AssetId, u64) { + transfer(Identity::Address(to), asset, 1); + + get_variable_tx_params(index) + } +} + +fn get_variable_tx_params(index: u64) -> (Address, AssetId, u64) { + let tx_asset_id = output_asset_id(index); + let tx_to = output_asset_to(index); + let tx_amount = output_amount(index); + + let tx_output_type = output_type(index); + assert(tx_output_type.is_some() && tx_output_type.unwrap() == Output::Variable); + ( + tx_to.unwrap_or(Address::zero()), + tx_asset_id.unwrap_or(AssetId::zero()), + tx_amount.unwrap_or(0), + ) +} diff --git a/test/src/sdk-harness/test_artifacts/tx_output_predicate/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_output_predicate/src/main.sw index e639bd11833..6f6495c9a42 100644 --- a/test/src/sdk-harness/test_artifacts/tx_output_predicate/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/tx_output_predicate/src/main.sw @@ -1,6 +1,6 @@ predicate; -use std::outputs::{output_asset_id, output_asset_to, output_type, Output}; +use std::outputs::{Output, output_asset_id, output_asset_to, output_type}; fn main(index: u64, asset_id: b256, to: b256, expected_type: Output) -> bool { let tx_asset_id = output_asset_id(index); diff --git a/test/src/sdk-harness/test_artifacts/tx_type_predicate/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_type_predicate/src/main.sw index 59bd4f10714..44938b3c833 100644 --- a/test/src/sdk-harness/test_artifacts/tx_type_predicate/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/tx_type_predicate/src/main.sw @@ -1,6 +1,6 @@ predicate; -use std::tx::{tx_type, Transaction}; +use std::tx::{Transaction, tx_type}; fn main(expected_type: Transaction) -> bool { tx_type() == expected_type diff --git a/test/src/sdk-harness/test_artifacts/tx_witness_predicate/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_witness_predicate/src/main.sw index adb0ea9dbc9..294051eb0cb 100644 --- a/test/src/sdk-harness/test_artifacts/tx_witness_predicate/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/tx_witness_predicate/src/main.sw @@ -1,8 +1,13 @@ predicate; -use std::tx::{tx_witnesses_count, tx_witness_data_length, tx_witness_data}; +use std::tx::{tx_witness_data, tx_witness_data_length, tx_witnesses_count}; -fn main(index: u64, expected_count: u64, expected_length: u64, expected_data: [u8; 64]) -> bool { +fn main( + index: u64, + expected_count: u64, + expected_length: u64, + expected_data: [u8; 64], +) -> bool { let count: u64 = tx_witnesses_count(); let length: Option = tx_witness_data_length(index); let data: Option<[u8; 64]> = tx_witness_data(index); @@ -11,7 +16,7 @@ fn main(index: u64, expected_count: u64, expected_length: u64, expected_data: [u assert(length.is_some() && length.unwrap() == expected_length); assert(data.is_some()); - let data = data.unwrap(); + let data = data.unwrap(); let mut iter = 0; while iter < 64 { assert(data[iter] == expected_data[iter]); diff --git a/test/src/sdk-harness/test_projects/tx_fields/mod.rs b/test/src/sdk-harness/test_projects/tx_fields/mod.rs index 0ac934999c7..f7e7308737d 100644 --- a/test/src/sdk-harness/test_projects/tx_fields/mod.rs +++ b/test/src/sdk-harness/test_projects/tx_fields/mod.rs @@ -14,8 +14,8 @@ const MESSAGE_DATA: [u8; 3] = [1u8, 2u8, 3u8]; const TX_CONTRACT_BYTECODE_PATH: &str = "test_artifacts/tx_contract/out/release/tx_contract.bin"; const TX_OUTPUT_PREDICATE_BYTECODE_PATH: &str = "test_artifacts/tx_output_predicate/out/release/tx_output_predicate.bin"; -const TX_OUTPUT_CHANGE_CONTRACT_BYTECODE_PATH: &str = - "test_artifacts/tx_output_change_contract/out/release/tx_output_change_contract.bin"; +const TX_OUTPUT_CONTRACT_BYTECODE_PATH: &str = + "test_artifacts/tx_output_contract/out/release/tx_output_contract.bin"; const TX_FIELDS_PREDICATE_BYTECODE_PATH: &str = "test_projects/tx_fields/out/release/tx_fields.bin"; const TX_CONTRACT_CREATION_PREDICATE_BYTECODE_PATH: &str = "test_artifacts/tx_output_contract_creation_predicate/out/release/tx_output_contract_creation_predicate.bin"; @@ -28,8 +28,8 @@ const TX_INPUT_COUNT_PREDICATE_BYTECODE_PATH: &str = const TX_OUTPUT_COUNT_PREDICATE_BYTECODE_PATH: &str = "test_artifacts/tx_output_count_predicate/out/release/tx_output_count_predicate.bin"; -use crate::tx_fields::Transaction as SwayTransaction; use crate::tx_fields::Output as SwayOutput; +use crate::tx_fields::Transaction as SwayTransaction; abigen!( Contract( @@ -37,8 +37,8 @@ abigen!( abi = "test_artifacts/tx_contract/out/release/tx_contract-abi.json", ), Contract( - name = "TxOutputChangeContract", - abi = "test_artifacts/tx_output_change_contract/out/release/tx_output_change_contract-abi.json", + name = "TxOutputContract", + abi = "test_artifacts/tx_output_contract/out/release/tx_output_contract-abi.json", ), Predicate( name = "TestPredicate", @@ -172,7 +172,10 @@ async fn generate_predicate_inputs( (predicate_code, predicate_input, predicate_message) } -async fn setup_output_predicate(index: u64, expected_output_type: SwayOutput) -> (WalletUnlocked, WalletUnlocked, Predicate, AssetId, AssetId) { +async fn setup_output_predicate( + index: u64, + expected_output_type: SwayOutput, +) -> (WalletUnlocked, WalletUnlocked, Predicate, AssetId, AssetId) { let asset_id1 = AssetId::default(); let asset_id2 = AssetId::new([2u8; 32]); let wallets_config = WalletsConfig::new_multiple_assets( @@ -201,7 +204,12 @@ async fn setup_output_predicate(index: u64, expected_output_type: SwayOutput) -> let wallet2 = wallets.pop().unwrap(); let predicate_data = TestOutputPredicateEncoder::default() - .encode_data(index, Bits256([0u8; 32]), Bits256(*wallet1.address().hash()), expected_output_type) + .encode_data( + index, + Bits256([0u8; 32]), + Bits256(*wallet1.address().hash()), + expected_output_type, + ) .unwrap(); let predicate = Predicate::load_from(TX_OUTPUT_PREDICATE_BYTECODE_PATH) @@ -1547,7 +1555,8 @@ mod outputs { #[tokio::test] async fn can_get_tx_output_details() { - let (wallet, _, predicate, asset_id, _) = setup_output_predicate(0, SwayOutput::Coin).await; + let (wallet, _, predicate, asset_id, _) = + setup_output_predicate(0, SwayOutput::Coin).await; let balance = predicate.get_asset_balance(&asset_id).await.unwrap(); @@ -1678,32 +1687,39 @@ mod outputs { assert_eq!(predicate_balance, 0); } } - + #[tokio::test] async fn can_get_tx_output_change_details() { // Prepare predicate - let (wallet, _, predicate, asset_id, _) = setup_output_predicate(2, SwayOutput::Change).await; + let (wallet, _, predicate, asset_id, _) = + setup_output_predicate(2, SwayOutput::Change).await; let provider = wallet.try_provider().unwrap().clone(); let balance = predicate.get_asset_balance(&asset_id).await.unwrap(); // Deploy contract - let contract_id = Contract::load_from(TX_OUTPUT_CHANGE_CONTRACT_BYTECODE_PATH, LoadConfiguration::default()) - .unwrap() - .deploy(&wallet, TxPolicies::default()) - .await - .unwrap(); - - let instance = TxOutputChangeContract::new(contract_id.clone(), wallet.clone()); + let contract_id = Contract::load_from( + TX_OUTPUT_CONTRACT_BYTECODE_PATH, + LoadConfiguration::default(), + ) + .unwrap() + .deploy(&wallet, TxPolicies::default()) + .await + .unwrap(); + + let instance = TxOutputContract::new(contract_id.clone(), wallet.clone()); // Send tokens to the contract let _ = wallet .force_transfer_to_contract(&contract_id, 10, asset_id, TxPolicies::default()) - .await - .unwrap(); + .await + .unwrap(); // Build transaction - let call_handler = instance.methods().send_assets(wallet.clone().address(), asset_id, 10); + let call_handler = + instance + .methods() + .send_assets_change(wallet.clone().address(), asset_id, 10); let mut tb = call_handler.transaction_builder().await.unwrap(); // Inputs for predicate @@ -1714,20 +1730,21 @@ mod outputs { .unwrap(); // Outputs for predicate - let predicate_output = wallet.get_asset_outputs_for_amount( - &wallet.address(), - asset_id, - transfer_amount, - ); + let predicate_output = + wallet.get_asset_outputs_for_amount(&wallet.address(), asset_id, transfer_amount); // Append the inputs and outputs to the transaction tb.inputs.push(predicate_input.get(0).unwrap().clone()); tb.outputs.push(predicate_output.get(0).unwrap().clone()); - tb.outputs.push(SdkOutput::Change{to: wallet.address().into(), amount: 0, asset_id}); + tb.outputs.push(SdkOutput::Change { + to: wallet.address().into(), + amount: 0, + asset_id, + }); wallet.adjust_for_fee(&mut tb, 0).await.unwrap(); tb.add_signer(wallet.clone()).unwrap(); - + let tx = tb.build(provider.clone()).await.unwrap(); let _tx_id = provider.send_transaction(tx).await.unwrap(); @@ -1735,6 +1752,44 @@ mod outputs { let new_balance = predicate.get_asset_balance(&asset_id).await.unwrap(); assert!(balance - transfer_amount == new_balance); } + + #[tokio::test] + async fn can_get_tx_output_variable_details() { + // Prepare wallet + let (wallet, _, _, asset_id, _) = setup_output_predicate(1, SwayOutput::Variable).await; + + // Deploy contract + let contract_id = Contract::load_from( + TX_OUTPUT_CONTRACT_BYTECODE_PATH, + LoadConfiguration::default(), + ) + .unwrap() + .deploy(&wallet, TxPolicies::default()) + .await + .unwrap(); + + let instance = TxOutputContract::new(contract_id.clone(), wallet.clone()); + + // Send tokens to the contract + let _ = wallet + .force_transfer_to_contract(&contract_id, 10, asset_id, TxPolicies::default()) + .await + .unwrap(); + + // Run transaction with variable output + let (tx_to, tx_asset_id, tx_amount) = instance + .methods() + .send_assets_variable(wallet.clone().address(), asset_id, 2) + .with_variable_output_policy(VariableOutputPolicy::Exactly(1)) + .call() + .await + .unwrap() + .value; + + assert_eq!(tx_to, wallet.clone().address().into()); + assert_eq!(tx_asset_id, asset_id); + assert_eq!(tx_amount, 1); + } } mod revert { @@ -1743,7 +1798,8 @@ mod outputs { #[tokio::test] #[should_panic] async fn fails_output_predicate_when_incorrect_asset() { - let (wallet1, _, predicate, _, asset_id2) = setup_output_predicate(0, SwayOutput::Coin).await; + let (wallet1, _, predicate, _, asset_id2) = + setup_output_predicate(0, SwayOutput::Coin).await; let transfer_amount = 10; predicate @@ -1760,7 +1816,8 @@ mod outputs { #[tokio::test] #[should_panic] async fn fails_output_predicate_when_incorrect_to() { - let (_, wallet2, predicate, asset_id1, _) = setup_output_predicate(0, SwayOutput::Coin).await; + let (_, wallet2, predicate, asset_id1, _) = + setup_output_predicate(0, SwayOutput::Coin).await; let transfer_amount = 10; predicate From cf7b6664b576fe9f34b22be4816ae2ce46647de4 Mon Sep 17 00:00:00 2001 From: Matt <54373384+matt-user@users.noreply.github.com> Date: Fri, 20 Dec 2024 10:47:39 -0600 Subject: [PATCH 42/52] docs: add sway memory model (#6775) ## Description Developers get confused by Sway's memory model as it is different from Rust's. So I added this to the docs. closes https://app.asana.com/0/1207924201336629/1208429018056446 ## Checklist - [x] I have linked to any relevant issues. - [ ] 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). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] 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. --------- Co-authored-by: Sophie Dankel <47993817+sdankel@users.noreply.github.com> --- docs/book/spell-check-custom-words.txt | 6 +++++- docs/book/src/reference/rust_differences.md | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/book/spell-check-custom-words.txt b/docs/book/spell-check-custom-words.txt index 6e18232eaf0..3b51147b9ee 100644 --- a/docs/book/spell-check-custom-words.txt +++ b/docs/book/spell-check-custom-words.txt @@ -227,4 +227,8 @@ predicate-root forc-client crypto doc -fmt \ No newline at end of file +fmt +deallocated +deallocate +destructors +destructor \ No newline at end of file diff --git a/docs/book/src/reference/rust_differences.md b/docs/book/src/reference/rust_differences.md index c9505814b20..abd7d7b736d 100644 --- a/docs/book/src/reference/rust_differences.md +++ b/docs/book/src/reference/rust_differences.md @@ -34,3 +34,9 @@ struct MyStruct { field_two: bool, } ``` + +## Memory Allocation + +In Rust, the borrow checker implements Rust's [ownership system](https://doc.rust-lang.org/1.8.0/book/ownership.html) + +In Sway, there is no borrow checker. This means there is no concept of ownership, borrowing, or lifetimes. Instead, objects are copied and moved similar to C++. Also Sway does not have any destructors nor `Drop` traits. This means allocated memory lives for the entire transaction and is not deallocated until the end of the transaction. A transaction may allocate up to [64 MB](https://github.com/FuelLabs/fuel-vm/blob/a80f82ed7c793763de6a73ca72d946b311b0fd0b/fuel-vm/src/consts.rs#L26) of memory. From 8fe2bd6ed267d94e172350d0835de5a11d796cea Mon Sep 17 00:00:00 2001 From: Yash Jagtap Date: Mon, 6 Jan 2025 06:08:00 +0530 Subject: [PATCH 43/52] fix: typos cleanup (#6799) ## Description fixed 3 typos ## Checklist - [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). - [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. --- .../documentation/language/control-flow/match/single-line.md | 2 +- docs/reference/src/documentation/operations/namespace/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/src/documentation/language/control-flow/match/single-line.md b/docs/reference/src/documentation/language/control-flow/match/single-line.md index 376b226b387..04b308c883f 100644 --- a/docs/reference/src/documentation/language/control-flow/match/single-line.md +++ b/docs/reference/src/documentation/language/control-flow/match/single-line.md @@ -10,6 +10,6 @@ The left side of the arrow `=>` is the pattern that we are matching on and the r We check each arm starting from `0` and make our way down until we either find a match on our pattern or we reach the `catch_all` case. -The `|` operator can be used to produce a pattern that is a disjuction of other patterns. +The `|` operator can be used to produce a pattern that is a disjunction of other patterns. The `catch_all` case is equivalent to an `else` in [if expressions](../if-expressions.md) and it does not have to be called `catch_all`. Any pattern declared after a `catch_all` case will not be matched because once the compiler sees the first `catch_all` it stop performing further checks. diff --git a/docs/reference/src/documentation/operations/namespace/index.md b/docs/reference/src/documentation/operations/namespace/index.md index 171f78629a2..773caebffa0 100644 --- a/docs/reference/src/documentation/operations/namespace/index.md +++ b/docs/reference/src/documentation/operations/namespace/index.md @@ -1,6 +1,6 @@ # Address Namespace -Sway utilizies namespaces to distinguish between address types. +Sway utilizes namespaces to distinguish between address types. Having multiple address types enforces type-safety and expands the range of values that an address can take because the same value can be used across multiple types. From 76c060bf8b20c8fcbf5306a909b0c037fa1f3914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Ron=C4=8Devi=C4=87?= Date: Tue, 7 Jan 2025 09:28:00 +0100 Subject: [PATCH 44/52] Add testing of `storage_domains` to language and SDK tests (#6809) ## Description This PR extends the language and SDK tests on CI to also run with the `storage_domains` experimental feature turned on. This is a part of our general testing strategy for experimental features. For E2E tests, we test only a handful of selected tests with the target experimental feature turned on. For language and SDK tests, we want to run all of the tests for every experimental feature. ## Checklist - [ ] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] 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. --- .github/workflows/ci.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 35bbf0a657a..7438d9fee0f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -470,6 +470,10 @@ jobs: run: cargo run --locked --release -p forc -- build --release --locked --path ./test/src/sdk-harness - name: Cargo Test sway-lib-std run: cargo test --locked --release --manifest-path ./test/src/sdk-harness/Cargo.toml -- --nocapture + - name: Build All Tests - Experimental Feature 'storage_domains' + run: cargo run --locked --release -p forc -- build --experimental storage_domains --release --locked --path ./test/src/sdk-harness + - name: Cargo Test sway-lib-std - Experimental Feature 'storage_domains' + run: cargo test --locked --release --manifest-path ./test/src/sdk-harness/Cargo.toml -- --nocapture forc-run-benchmarks: runs-on: buildjet-4vcpu-ubuntu-2204 @@ -525,10 +529,16 @@ jobs: run: cargo install --locked --debug --path ./forc - name: Run Core Unit Tests run: forc build --path sway-lib-core && forc test --path sway-lib-core + - name: Run Core Unit Tests - Experimental feature 'storage_domains' + run: forc build --experimental storage_domains --path sway-lib-core && forc test --experimental storage_domains --path sway-lib-core - name: Run Std Unit Tests run: forc build --path sway-lib-std && forc test --path sway-lib-std + - name: Run Std Unit Tests - Experimental feature 'storage_domains' + run: forc build --experimental storage_domains --path sway-lib-std && forc test --experimental storage_domains --path sway-lib-std - name: Run In Language Unit Tests run: forc build --path test/src/in_language_tests && forc test --path test/src/in_language_tests + - name: Run In Language Unit Tests - Experimental feature 'storage_domains' + run: forc build --experimental storage_domains --path test/src/in_language_tests && forc test --experimental storage_domains --path test/src/in_language_tests forc-pkg-fuels-deps-check: runs-on: buildjet-4vcpu-ubuntu-2204 From 23576769d151167870a1454ce112f4f9d7271d8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Ron=C4=8Devi=C4=87?= Date: Tue, 7 Jan 2025 12:55:03 +0100 Subject: [PATCH 45/52] Refactor `swayfmt` to support arbitrary lexed trees (#6806) ## Description This PR refactors `swayfmt` to be able generate code from arbitrary lexed trees. Arbitrary means a lexed tree that can be fully or partially created in-memory by manipulating the tree structure in code. It does not need to necessarily be backed by source code. This is needed to be able to reuse `swayfmt` for generating source code from tools that analyze and modify Sway code, as explained in #6779. This PR makes the `swayfmt` independent of spans backed by the source code, by doing the following changes: - Keywords are rendered by using theirs `AS_STR` associated constants. - The `Token` trait is extended with the `AS_STR` associated constant, and tokens are rendered by using that constant. - `Ident`s are rendered by using theirs `as_str()` methods. This method takes the textual implementation from `Ident::name_override_opt` if it is provided, and ignores the span in that case. - `Literal`s are rendered based on the literal value and not their spans. The exception are numeric literals that do not have empty spans. Those are considered to be backed by source code and are rendered as written in code, e.g., `1_000_000u64`. The PR also fixes some existing bugs in `swayfmt`: - `use path::{single_import,};` will be formatted as `use path::single_import;` - `use path::{a,b,};` will be formatted as `use path::{a, b};` - partial addresses #6802 by rendering annotations for final values. - partial addresses #6805 by properly rendering final values, but still not using the expected field alignment. The PR also removes the `path` parameter from the `parse_file`. It was used only to provide an unnecessary dummy `source_id` which was always pointing to the package root file. Closes #6779. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] 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. --- Cargo.lock | 1 - .../advanced_storage_variables/src/main.sw | 2 +- examples/converting_types/src/byte_arrays.sw | 2 +- examples/converting_types/src/bytes.sw | 2 +- examples/wallet_smart_contract/src/main.sw | 2 +- forc-plugins/forc-fmt/src/main.rs | 33 +- sway-ast/src/expr/mod.rs | 12 + sway-ast/src/expr/op_code.rs | 8 + sway-ast/src/keywords.rs | 94 +++-- sway-ast/src/punctuated.rs | 13 + sway-lib-std/src/prelude.sw | 2 +- sway-lsp/src/capabilities/formatting.rs | 2 +- sway-types/src/ast.rs | 4 +- sway-types/src/span.rs | 4 + swayfmt/Cargo.toml | 1 - swayfmt/src/comments.rs | 12 +- swayfmt/src/formatter/mod.rs | 24 +- swayfmt/src/formatter/shape.rs | 6 + swayfmt/src/items/item_abi/mod.rs | 11 +- swayfmt/src/items/item_configurable/mod.rs | 46 +-- swayfmt/src/items/item_const.rs | 21 +- swayfmt/src/items/item_enum/mod.rs | 55 ++- swayfmt/src/items/item_fn/mod.rs | 44 ++- swayfmt/src/items/item_impl/mod.rs | 11 +- swayfmt/src/items/item_storage/mod.rs | 30 +- swayfmt/src/items/item_struct/mod.rs | 70 ++-- swayfmt/src/items/item_trait/mod.rs | 21 +- swayfmt/src/items/item_trait_type.rs | 17 +- swayfmt/src/items/item_type_alias.rs | 15 +- swayfmt/src/items/item_use/mod.rs | 87 +++-- swayfmt/src/items/item_use/tests.rs | 41 +++ swayfmt/src/module/mod.rs | 25 +- swayfmt/src/module/submodule.rs | 14 +- swayfmt/src/parse.rs | 11 +- swayfmt/src/utils/language/attribute.rs | 30 +- swayfmt/src/utils/language/expr/abi_cast.rs | 4 +- swayfmt/src/utils/language/expr/asm_block.rs | 17 +- swayfmt/src/utils/language/expr/assignable.rs | 33 +- .../src/utils/language/expr/collections.rs | 15 +- .../src/utils/language/expr/conditional.rs | 37 +- swayfmt/src/utils/language/expr/mod.rs | 197 +++++------ .../src/utils/language/expr/struct_field.rs | 16 +- swayfmt/src/utils/language/literal.rs | 56 ++- swayfmt/src/utils/language/path.rs | 33 +- swayfmt/src/utils/language/pattern.rs | 29 +- swayfmt/src/utils/language/punctuated.rs | 41 +-- swayfmt/src/utils/language/statement.rs | 27 +- swayfmt/src/utils/language/ty.rs | 115 +++---- swayfmt/src/utils/language/where_clause.rs | 25 +- swayfmt/src/utils/map/byte_span.rs | 4 +- swayfmt/src/utils/map/newline.rs | 7 +- swayfmt/tests/mod.rs | 322 +++++++++++++++++- 52 files changed, 1100 insertions(+), 651 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6df20e9c24..d3c21b0d08b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7869,7 +7869,6 @@ dependencies = [ "serde_ignored", "similar", "sway-ast", - "sway-core", "sway-error", "sway-parse", "sway-types", diff --git a/examples/advanced_storage_variables/src/main.sw b/examples/advanced_storage_variables/src/main.sw index 75054ab7149..c1afb9f4790 100644 --- a/examples/advanced_storage_variables/src/main.sw +++ b/examples/advanced_storage_variables/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::{bytes::Bytes, string::String,}; +use std::{bytes::Bytes, string::String}; // ANCHOR: temp_hash_import use std::hash::Hash; diff --git a/examples/converting_types/src/byte_arrays.sw b/examples/converting_types/src/byte_arrays.sw index d98931c163f..41c1ef543ba 100644 --- a/examples/converting_types/src/byte_arrays.sw +++ b/examples/converting_types/src/byte_arrays.sw @@ -1,7 +1,7 @@ library; // ANCHOR: to_byte_array_import -use std::array_conversions::{b256::*, u16::*, u256::*, u32::*, u64::*,}; +use std::array_conversions::{b256::*, u16::*, u256::*, u32::*, u64::*}; // ANCHOR_END: to_byte_array_import pub fn to_byte_array() { diff --git a/examples/converting_types/src/bytes.sw b/examples/converting_types/src/bytes.sw index 5460352b10d..3537eca8a51 100644 --- a/examples/converting_types/src/bytes.sw +++ b/examples/converting_types/src/bytes.sw @@ -1,7 +1,7 @@ library; // ANCHOR: to_bytes_import -use std::{bytes::Bytes, bytes_conversions::{b256::*, u16::*, u256::*, u32::*, u64::*,}}; +use std::{bytes::Bytes, bytes_conversions::{b256::*, u16::*, u256::*, u32::*, u64::*}}; // ANCHOR_END: to_bytes_import pub fn convert_to_bytes() { diff --git a/examples/wallet_smart_contract/src/main.sw b/examples/wallet_smart_contract/src/main.sw index 9343e818bdf..5ab406a6f3c 100644 --- a/examples/wallet_smart_contract/src/main.sw +++ b/examples/wallet_smart_contract/src/main.sw @@ -1,7 +1,7 @@ // ANCHOR: full_wallet contract; -use std::{asset::transfer, call_frames::msg_asset_id, context::msg_amount,}; +use std::{asset::transfer, call_frames::msg_asset_id, context::msg_amount}; // ANCHOR: abi_import use wallet_abi::Wallet; diff --git a/forc-plugins/forc-fmt/src/main.rs b/forc-plugins/forc-fmt/src/main.rs index 6a818ff245a..fffefbbd840 100644 --- a/forc-plugins/forc-fmt/src/main.rs +++ b/forc-plugins/forc-fmt/src/main.rs @@ -15,7 +15,6 @@ use std::{ path::{Path, PathBuf}, sync::Arc, }; -use sway_core::{BuildConfig, BuildTarget}; use sway_utils::{constants, find_parent_manifest_dir, get_sway_files, is_sway_file}; use swayfmt::Formatter; use taplo::formatter as taplo_fmt; @@ -77,13 +76,8 @@ fn run() -> Result<()> { if let Some(f) = app.file.as_ref() { let file_path = &PathBuf::from(f); - // If we're formatting a single file, find the nearest manifest if within a project. - // Otherwise, we simply provide 'None' to format_file(). - let manifest_file = find_parent_manifest_dir(file_path) - .map(|path| path.join(constants::MANIFEST_FILE_NAME)); - if is_sway_file(file_path) { - format_file(&app, file_path.to_path_buf(), manifest_file, &mut formatter)?; + format_file(&app, file_path.to_path_buf(), &mut formatter)?; return Ok(()); } @@ -142,12 +136,7 @@ fn get_sway_dirs(workspace_dir: PathBuf) -> Vec { /// - Ok(true) if executed successfully and formatted, /// - Ok(false) if executed successfully and not formatted, /// - Err if it fails to execute at all. -fn format_file( - app: &App, - file: PathBuf, - manifest_file: Option, - formatter: &mut Formatter, -) -> Result { +fn format_file(app: &App, file: PathBuf, formatter: &mut Formatter) -> Result { let file = file.canonicalize()?; if is_file_dirty(&file) { bail!( @@ -160,14 +149,7 @@ fn format_file( if let Ok(file_content) = fs::read_to_string(&file) { let mut edited = false; let file_content: Arc = Arc::from(file_content); - let build_config = manifest_file.map(|f| { - BuildConfig::root_from_file_name_and_manifest_path( - file.clone(), - f, - BuildTarget::default(), - ) - }); - match Formatter::format(formatter, file_content.clone(), build_config.as_ref()) { + match Formatter::format(formatter, file_content.clone()) { Ok(formatted_content) => { if app.check { if *file_content != formatted_content { @@ -213,12 +195,7 @@ fn format_workspace_at_dir(app: &App, workspace: &WorkspaceManifestFile, dir: &P for entry in read_dir.filter_map(|res| res.ok()) { let path = entry.path(); if is_sway_file(&path) { - format_file( - app, - path, - Some(workspace.dir().to_path_buf()), - &mut formatter, - )?; + format_file(app, path, &mut formatter)?; } } } @@ -295,7 +272,7 @@ fn format_pkg_at_dir(app: &App, dir: &Path, formatter: &mut Formatter) -> Result let mut contains_edits = false; for file in files { - contains_edits |= format_file(app, file, Some(manifest_file.clone()), formatter)?; + contains_edits |= format_file(app, file, formatter)?; } // format manifest using taplo formatter contains_edits |= format_manifest(app, manifest_file)?; diff --git a/sway-ast/src/expr/mod.rs b/sway-ast/src/expr/mod.rs index f27798c2d7f..52999a63dcf 100644 --- a/sway-ast/src/expr/mod.rs +++ b/sway-ast/src/expr/mod.rs @@ -306,6 +306,18 @@ impl ReassignmentOpVariant { ReassignmentOpVariant::ShrEquals => "rsh", } } + + pub fn as_str(&self) -> &'static str { + match self { + ReassignmentOpVariant::Equals => EqToken::AS_STR, + ReassignmentOpVariant::AddEquals => AddEqToken::AS_STR, + ReassignmentOpVariant::SubEquals => SubEqToken::AS_STR, + ReassignmentOpVariant::MulEquals => StarEqToken::AS_STR, + ReassignmentOpVariant::DivEquals => DivEqToken::AS_STR, + ReassignmentOpVariant::ShlEquals => ShlEqToken::AS_STR, + ReassignmentOpVariant::ShrEquals => ShrEqToken::AS_STR, + } + } } #[derive(Clone, Debug, Serialize)] diff --git a/sway-ast/src/expr/op_code.rs b/sway-ast/src/expr/op_code.rs index acfc54411eb..83c6d319743 100644 --- a/sway-ast/src/expr/op_code.rs +++ b/sway-ast/src/expr/op_code.rs @@ -123,6 +123,14 @@ macro_rules! define_op_codes ( } } + pub fn op_code_as_str(&self) -> &'static str { + match self { + $(Instruction::$op_name { .. } => { + $s + },)* + } + } + #[allow(clippy::vec_init_then_push)] pub fn register_arg_idents(&self) -> Vec { match self { diff --git a/sway-ast/src/keywords.rs b/sway-ast/src/keywords.rs index 0e3ea802da0..236b07cb8aa 100644 --- a/sway-ast/src/keywords.rs +++ b/sway-ast/src/keywords.rs @@ -98,10 +98,13 @@ pub trait Token: Spanned + Sized { /// Punctuations that will not follow the token. const NOT_FOLLOWED_BY: &'static [PunctKind]; + + /// What the string representation of the token is when lexing. + const AS_STR: &'static str; } macro_rules! define_token ( - ($ty_name:ident, $description:literal, [$($punct_kinds:ident),*], [$($not_followed_by:ident),*]) => { + ($ty_name:ident, $description:literal, $as_str:literal, [$($punct_kinds:ident),*], [$($not_followed_by:ident),*]) => { #[derive(Clone, Debug, Serialize)] pub struct $ty_name { span: Span, @@ -132,6 +135,7 @@ macro_rules! define_token ( const PUNCT_KINDS: &'static [PunctKind] = &[$(PunctKind::$punct_kinds,)*]; const NOT_FOLLOWED_BY: &'static [PunctKind] = &[$(PunctKind::$not_followed_by,)*]; + const AS_STR: &'static str = $as_str; } impl From<$ty_name> for Ident { @@ -142,93 +146,121 @@ macro_rules! define_token ( }; ); -define_token!(SemicolonToken, "a semicolon", [Semicolon], []); +define_token!(SemicolonToken, "a semicolon", ";", [Semicolon], []); define_token!( ForwardSlashToken, "a forward slash", + "/", [ForwardSlash], [Equals] ); define_token!( DoubleColonToken, "a double colon (::)", + "::", [Colon, Colon], [Colon] ); -define_token!(StarToken, "an asterisk (*)", [Star], [Equals]); -define_token!(DoubleStarToken, "`**`", [Star, Star], []); -define_token!(CommaToken, "a comma", [Comma], []); -define_token!(ColonToken, "a colon", [Colon], [Colon]); +define_token!(StarToken, "an asterisk (*)", "*", [Star], [Equals]); +define_token!(DoubleStarToken, "`**`", "**", [Star, Star], []); +define_token!(CommaToken, "a comma", ",", [Comma], []); +define_token!(ColonToken, "a colon", ":", [Colon], [Colon]); define_token!( RightArrowToken, "`->`", + "->", [Sub, GreaterThan], [GreaterThan, Equals] ); -define_token!(LessThanToken, "`<`", [LessThan], [LessThan, Equals]); +define_token!(LessThanToken, "`<`", "<", [LessThan], [LessThan, Equals]); define_token!( GreaterThanToken, "`>`", + ">", [GreaterThan], [GreaterThan, Equals] ); -define_token!(OpenAngleBracketToken, "`<`", [LessThan], []); -define_token!(CloseAngleBracketToken, "`>`", [GreaterThan], []); -define_token!(EqToken, "`=`", [Equals], [GreaterThan, Equals]); -define_token!(AddEqToken, "`+=`", [Add, Equals], []); -define_token!(SubEqToken, "`-=`", [Sub, Equals], []); -define_token!(StarEqToken, "`*=`", [Star, Equals], []); -define_token!(DivEqToken, "`/=`", [ForwardSlash, Equals], []); -define_token!(ShlEqToken, "`<<=`", [LessThan, LessThan, Equals], []); -define_token!(ShrEqToken, "`>>=`", [GreaterThan, GreaterThan, Equals], []); +define_token!(OpenAngleBracketToken, "`<`", "<", [LessThan], []); +define_token!(CloseAngleBracketToken, "`>`", ">", [GreaterThan], []); +define_token!(EqToken, "`=`", "=", [Equals], [GreaterThan, Equals]); +define_token!(AddEqToken, "`+=`", "+=", [Add, Equals], []); +define_token!(SubEqToken, "`-=`", "-=", [Sub, Equals], []); +define_token!(StarEqToken, "`*=`", "*=", [Star, Equals], []); +define_token!(DivEqToken, "`/=`", "/=", [ForwardSlash, Equals], []); +define_token!(ShlEqToken, "`<<=`", "<<=", [LessThan, LessThan, Equals], []); +define_token!( + ShrEqToken, + "`>>=`", + ">>=", + [GreaterThan, GreaterThan, Equals], + [] +); define_token!( FatRightArrowToken, "`=>`", + "=>", [Equals, GreaterThan], [GreaterThan, Equals] ); -define_token!(DotToken, "`.`", [Dot], []); -define_token!(DoubleDotToken, "`..`", [Dot, Dot], [Dot]); -define_token!(BangToken, "`!`", [Bang], [Equals]); -define_token!(PercentToken, "`%`", [Percent], []); -define_token!(AddToken, "`+`", [Add], [Equals]); -define_token!(SubToken, "`-`", [Sub], [Equals]); +define_token!(DotToken, "`.`", ".", [Dot], []); +define_token!(DoubleDotToken, "`..`", "..", [Dot, Dot], [Dot]); +define_token!(BangToken, "`!`", "!", [Bang], [Equals]); +define_token!(PercentToken, "`%`", "%", [Percent], []); +define_token!(AddToken, "`+`", "+", [Add], [Equals]); +define_token!(SubToken, "`-`", "-", [Sub], [Equals]); define_token!( ShrToken, "`>>`", + ">>", [GreaterThan, GreaterThan], [GreaterThan, Equals] ); -define_token!(ShlToken, "`<<`", [LessThan, LessThan], [LessThan, Equals]); -define_token!(AmpersandToken, "`&`", [Ampersand], [Ampersand]); -define_token!(CaretToken, "`^`", [Caret], []); -define_token!(PipeToken, "`|`", [Pipe], [Pipe]); +define_token!( + ShlToken, + "`<<`", + "<<", + [LessThan, LessThan], + [LessThan, Equals] +); +define_token!(AmpersandToken, "`&`", "&", [Ampersand], [Ampersand]); +define_token!(CaretToken, "`^`", "^", [Caret], []); +define_token!(PipeToken, "`|`", "|", [Pipe], [Pipe]); define_token!( DoubleEqToken, "`==`", + "==", [Equals, Equals], [Equals, GreaterThan] ); -define_token!(BangEqToken, "`!=`", [Bang, Equals], [Equals, GreaterThan]); +define_token!( + BangEqToken, + "`!=`", + "!=", + [Bang, Equals], + [Equals, GreaterThan] +); define_token!( GreaterThanEqToken, "`>=`", + ">=", [GreaterThan, Equals], [Equals, GreaterThan] ); define_token!( LessThanEqToken, "`<=`", + "<=", [LessThan, Equals], [Equals, GreaterThan] ); define_token!( DoubleAmpersandToken, "`&&`", + "&&", [Ampersand, Ampersand], [Ampersand] ); -define_token!(DoublePipeToken, "`||`", [Pipe, Pipe], [Pipe]); -define_token!(UnderscoreToken, "`_`", [Underscore], [Underscore]); -define_token!(HashToken, "`#`", [Sharp], []); -define_token!(HashBangToken, "`#!`", [Sharp, Bang], []); +define_token!(DoublePipeToken, "`||`", "||", [Pipe, Pipe], [Pipe]); +define_token!(UnderscoreToken, "`_`", "_", [Underscore], [Underscore]); +define_token!(HashToken, "`#`", "#", [Sharp], []); +define_token!(HashBangToken, "`#!`", "#!", [Sharp, Bang], []); diff --git a/sway-ast/src/punctuated.rs b/sway-ast/src/punctuated.rs index 9aa88c64495..af6cf423f89 100644 --- a/sway-ast/src/punctuated.rs +++ b/sway-ast/src/punctuated.rs @@ -20,6 +20,19 @@ impl Punctuated { final_value_opt: Some(Box::new(value)), } } + + /// Returns true if the [Punctuated] ends with the punctuation token. + /// E.g., `fn fun(x: u64, y: u64,)`. + pub fn has_trailing_punctuation(&self) -> bool { + !self.value_separator_pairs.is_empty() && self.final_value_opt.is_none() + } + + /// Returns true if the [Punctuated] has neither value separator pairs, + /// nor the final value. + /// E.g., `fn fun()`. + pub fn is_empty(&self) -> bool { + self.value_separator_pairs.is_empty() && self.final_value_opt.is_none() + } } impl IntoIterator for Punctuated { diff --git a/sway-lib-std/src/prelude.sw b/sway-lib-std/src/prelude.sw index f8d42cf0044..b86eb26ec31 100644 --- a/sway-lib-std/src/prelude.sw +++ b/sway-lib-std/src/prelude.sw @@ -27,7 +27,7 @@ pub use ::revert::{require, revert, revert_with_log}; pub use ::convert::From; // Primitive conversions -pub use ::primitive_conversions::{b256::*, str::*, u16::*, u256::*, u32::*, u64::*, u8::*,}; +pub use ::primitive_conversions::{b256::*, str::*, u16::*, u256::*, u32::*, u64::*, u8::*}; // Logging pub use ::logging::log; diff --git a/sway-lsp/src/capabilities/formatting.rs b/sway-lsp/src/capabilities/formatting.rs index e4b1596991b..06d5b58b59b 100644 --- a/sway-lsp/src/capabilities/formatting.rs +++ b/sway-lsp/src/capabilities/formatting.rs @@ -24,7 +24,7 @@ pub fn get_page_text_edit( ) -> Result { // we only format if code is correct let formatted_code = formatter - .format(text.clone(), None) + .format(text.clone()) .map_err(LanguageServerError::FormatError)?; let text_lines_count = text.split('\n').count(); diff --git a/sway-types/src/ast.rs b/sway-types/src/ast.rs index b137ad9bd09..4db1c3b6c7c 100644 --- a/sway-types/src/ast.rs +++ b/sway-types/src/ast.rs @@ -6,14 +6,14 @@ pub enum Delimiter { } impl Delimiter { - pub fn as_open_char(self) -> char { + pub const fn as_open_char(self) -> char { match self { Delimiter::Parenthesis => '(', Delimiter::Brace => '{', Delimiter::Bracket => '[', } } - pub fn as_close_char(self) -> char { + pub const fn as_close_char(self) -> char { match self { Delimiter::Parenthesis => ')', Delimiter::Brace => '}', diff --git a/sway-types/src/span.rs b/sway-types/src/span.rs index 99536c080ee..5ea94b3c2a0 100644 --- a/sway-types/src/span.rs +++ b/sway-types/src/span.rs @@ -203,6 +203,10 @@ impl Span { pub fn is_dummy(&self) -> bool { self.eq(&DUMMY_SPAN) } + + pub fn is_empty(&self) -> bool { + self.start == self.end + } } impl fmt::Debug for Span { diff --git a/swayfmt/Cargo.toml b/swayfmt/Cargo.toml index 85749c30ab2..71eb6d60824 100644 --- a/swayfmt/Cargo.toml +++ b/swayfmt/Cargo.toml @@ -16,7 +16,6 @@ ropey.workspace = true serde = { workspace = true, features = ["derive"] } serde_ignored.workspace = true sway-ast.workspace = true -sway-core.workspace = true sway-error.workspace = true sway-parse.workspace = true sway-types.workspace = true diff --git a/swayfmt/src/comments.rs b/swayfmt/src/comments.rs index e891ca15666..dfd5590d7f7 100644 --- a/swayfmt/src/comments.rs +++ b/swayfmt/src/comments.rs @@ -76,15 +76,18 @@ fn write_trailing_comment( } /// Given a range, writes comments contained within the range. This function -/// removes comments that are written here from the CommentMap for later use. +/// removes comments that are written here from the [CommentMap] for later use. /// -/// Most comment formatting should be done using `rewrite_with_comments` in +/// Most comment formatting should be done using [rewrite_with_comments] in /// the context of the AST, but in some cases (eg. at the end of module) we require this function. /// /// Returns: /// `Ok(true)` on successful execution with comments written, /// `Ok(false)` on successful execution and if there are no comments within the given range, /// `Err` if a FormatterError was encountered. +/// +/// The `range` can be an empty [Range], or have its start being greater then its end. +/// This is to support formatting arbitrary lexed trees, that are not necessarily backed by source code. pub fn write_comments( formatted_code: &mut FormattedCode, range: Range, @@ -127,7 +130,7 @@ pub fn write_comments( // We do a trim and truncate here to ensure that only a single whitespace separates // the inlined comment from the previous token. formatted_code.truncate(formatted_code.trim_end().len()); - write!(formatted_code, " {} ", comment.span().as_str(),)?; + write!(formatted_code, " {} ", comment.span().as_str())?; } CommentKind::Multilined => { write!( @@ -157,6 +160,9 @@ pub fn write_comments( /// This takes a given AST node's unformatted span, its leaf spans and its formatted code (a string) and /// parses the equivalent formatted version to get its leaf spans. We traverse the spaces between both /// formatted and unformatted leaf spans to find possible comments and inserts them between. +/// +/// The `unformatted_span` can be an empty [Span]. This is to support formatting arbitrary lexed trees, +/// that are not necessarily backed by source code. pub fn rewrite_with_comments( formatter: &mut Formatter, unformatted_span: Span, diff --git a/swayfmt/src/formatter/mod.rs b/swayfmt/src/formatter/mod.rs index 96ead29f09d..0802d0c7727 100644 --- a/swayfmt/src/formatter/mod.rs +++ b/swayfmt/src/formatter/mod.rs @@ -8,7 +8,8 @@ pub use crate::{ error::{ConfigError, FormatterError}, }; use std::{borrow::Cow, fmt::Write, path::Path, sync::Arc}; -use sway_core::BuildConfig; +use sway_ast::attribute::Annotated; +use sway_ast::Module; use sway_types::{SourceEngine, Spanned}; pub(crate) mod shape; @@ -80,10 +81,14 @@ impl Formatter { Ok(self) } - pub fn format( + pub fn format(&mut self, src: Arc) -> Result { + let annotated_module = parse_file(src)?; + self.format_module(&annotated_module) + } + + pub fn format_module( &mut self, - src: Arc, - build_config: Option<&BuildConfig>, + annotated_module: &Annotated, ) -> Result { // apply the width heuristics settings from the `Config` self.shape.apply_width_heuristics( @@ -92,9 +97,11 @@ impl Formatter { .heuristics_pref .to_width_heuristics(self.config.whitespace.max_width), ); - let src = src.trim(); - let path = build_config.map(|build_config| build_config.canonical_root_module()); + // Get the original trimmed source code. + let module_kind_span = annotated_module.value.kind.span(); + let src = module_kind_span.src().trim(); + // Formatted code will be pushed here with raw newline style. // Which means newlines are not converted into system-specific versions until `apply_newline_style()`. // Use the length of src as a hint of the memory size needed for `raw_formatted_code`, @@ -103,7 +110,6 @@ impl Formatter { self.with_comments_context(src)?; - let annotated_module = parse_file(&self.source_engine, Arc::from(src), path.clone())?; annotated_module.format(&mut raw_formatted_code, self)?; let mut formatted_code = String::from(&raw_formatted_code); @@ -117,14 +123,13 @@ impl Formatter { // Add newline sequences handle_newlines( - &self.source_engine, Arc::from(src), &annotated_module.value, Arc::from(formatted_code.clone()), - path, &mut formatted_code, self, )?; + // Replace newlines with specified `NewlineStyle` apply_newline_style( self.config.whitespace.newline_style, @@ -137,6 +142,7 @@ impl Formatter { Ok(formatted_code) } + pub(crate) fn with_shape(&mut self, new_shape: Shape, f: F) -> O where F: FnOnce(&mut Self) -> O, diff --git a/swayfmt/src/formatter/shape.rs b/swayfmt/src/formatter/shape.rs index 0630c73e851..9c9def85548 100644 --- a/swayfmt/src/formatter/shape.rs +++ b/swayfmt/src/formatter/shape.rs @@ -163,6 +163,12 @@ pub(crate) enum LineStyle { Multiline, } +impl LineStyle { + pub fn is_multiline(&self) -> bool { + matches!(self, Self::Multiline) + } +} + impl Default for LineStyle { fn default() -> Self { Self::Normal diff --git a/swayfmt/src/items/item_abi/mod.rs b/swayfmt/src/items/item_abi/mod.rs index ddf1fabe22f..e47fa3b269d 100644 --- a/swayfmt/src/items/item_abi/mod.rs +++ b/swayfmt/src/items/item_abi/mod.rs @@ -8,7 +8,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{keywords::Token, ItemAbi}; +use sway_ast::{ + keywords::{AbiToken, ColonToken, Keyword, Token}, + ItemAbi, +}; use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] @@ -22,12 +25,12 @@ impl Format for ItemAbi { ) -> Result<(), FormatterError> { let start_len = formatted_code.len(); // `abi name` - write!(formatted_code, "{} ", self.abi_token.span().as_str())?; + write!(formatted_code, "{} ", AbiToken::AS_STR)?; self.name.format(formatted_code, formatter)?; // ` : super_trait + super_trait` - if let Some((colon_token, traits)) = &self.super_traits { - write!(formatted_code, " {} ", colon_token.ident().as_str())?; + if let Some((_colon_token, traits)) = &self.super_traits { + write!(formatted_code, " {} ", ColonToken::AS_STR)?; traits.format(formatted_code, formatter)?; } diff --git a/swayfmt/src/items/item_configurable/mod.rs b/swayfmt/src/items/item_configurable/mod.rs index 550b8916d8d..c870b537a1d 100644 --- a/swayfmt/src/items/item_configurable/mod.rs +++ b/swayfmt/src/items/item_configurable/mod.rs @@ -10,7 +10,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{keywords::Token, ConfigurableField, ItemConfigurable}; +use sway_ast::{ + keywords::{ColonToken, ConfigurableToken, EqToken, Keyword, Token}, + CommaToken, ConfigurableField, ItemConfigurable, +}; use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] @@ -28,11 +31,7 @@ impl Format for ItemConfigurable { .with_code_line_from(LineStyle::Multiline, ExprKind::default()), |formatter| -> Result<(), FormatterError> { // Add configurable token - write!( - formatted_code, - "{}", - self.configurable_token.span().as_str() - )?; + write!(formatted_code, "{}", ConfigurableToken::AS_STR)?; let fields = self.fields.get(); // Handle opening brace @@ -44,19 +43,18 @@ impl Format for ItemConfigurable { match formatter.config.structures.field_alignment { FieldAlignment::AlignFields(configurable_field_align_threshold) => { writeln!(formatted_code)?; - let value_pairs = &fields + let configurable_fields = &fields .value_separator_pairs .iter() - // TODO: Handle annotations instead of stripping them - .map(|(configurable_field, comma_token)| { - (&configurable_field.value, comma_token) - }) + // TODO: Handle annotations instead of stripping them. + // See: https://github.com/FuelLabs/sway/issues/6802 + .map(|(configurable_field, _comma_token)| &configurable_field.value) .collect::>(); // In first iteration we are going to be collecting the lengths of the // struct fields. - let field_length: Vec = value_pairs + let field_length: Vec = configurable_fields .iter() - .map(|(configurable_field, _)| configurable_field.name.as_str().len()) + .map(|configurable_field| configurable_field.name.as_str().len()) .collect(); // Find the maximum length in the `field_length` vector that is still @@ -72,11 +70,10 @@ impl Format for ItemConfigurable { } }); - let value_pairs_iter = value_pairs.iter().enumerate(); - for (field_index, (configurable_field, comma_token)) in - value_pairs_iter.clone() + for (field_index, configurable_field) in + configurable_fields.iter().enumerate() { - write!(formatted_code, "{}", &formatter.indent_to_str()?)?; + write!(formatted_code, "{}", formatter.indent_to_str()?)?; // Add name configurable_field.name.format(formatted_code, formatter)?; @@ -94,24 +91,17 @@ impl Format for ItemConfigurable { } } // Add `:`, `ty` & `CommaToken` - write!( - formatted_code, - " {} ", - configurable_field.colon_token.ident().as_str(), - )?; + write!(formatted_code, " {} ", ColonToken::AS_STR)?; configurable_field.ty.format(formatted_code, formatter)?; - write!( - formatted_code, - " {} ", - configurable_field.eq_token.ident().as_str() - )?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; configurable_field .initializer .format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", comma_token.ident().as_str())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } if let Some(final_value) = &fields.final_value_opt { final_value.format(formatted_code, formatter)?; + writeln!(formatted_code)?; } } FieldAlignment::Off => fields.format(formatted_code, formatter)?, diff --git a/swayfmt/src/items/item_const.rs b/swayfmt/src/items/item_const.rs index e853f2a97dc..0d78ef24eeb 100644 --- a/swayfmt/src/items/item_const.rs +++ b/swayfmt/src/items/item_const.rs @@ -4,7 +4,10 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::{keywords::Token, ItemConst}; +use sway_ast::{ + keywords::{ColonToken, ConstToken, EqToken, Keyword, SemicolonToken, Token}, + ItemConst, PubToken, +}; use sway_types::Spanned; impl Format for ItemConst { @@ -17,26 +20,26 @@ impl Format for ItemConst { let start_len = formatted_code.len(); // Check if visibility token exists if so add it. - if let Some(visibility_token) = &self.visibility { - write!(formatted_code, "{} ", visibility_token.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // Add the const token - write!(formatted_code, "{} ", self.const_token.span().as_str())?; + write!(formatted_code, "{} ", ConstToken::AS_STR)?; // Add name of the const self.name.format(formatted_code, formatter)?; // Check if ty exists - if let Some((colon_token, ty)) = &self.ty_opt { + if let Some((_colon_token, ty)) = &self.ty_opt { // Add colon - write!(formatted_code, "{} ", colon_token.ident().as_str())?; + write!(formatted_code, "{} ", ColonToken::AS_STR)?; ty.format(formatted_code, formatter)?; } // Check if ` = ` exists - if let Some(eq_token) = &self.eq_token_opt { - write!(formatted_code, " {} ", eq_token.ident().as_str())?; + if self.eq_token_opt.is_some() { + write!(formatted_code, " {} ", EqToken::AS_STR)?; } // Check if expression exists @@ -44,7 +47,7 @@ impl Format for ItemConst { expr.format(formatted_code, formatter)?; } - write!(formatted_code, "{}", self.semicolon_token.ident().as_str())?; + write!(formatted_code, "{}", SemicolonToken::AS_STR)?; rewrite_with_comments::( formatter, diff --git a/swayfmt/src/items/item_enum/mod.rs b/swayfmt/src/items/item_enum/mod.rs index 561c2b436f6..11fa3d6c78d 100644 --- a/swayfmt/src/items/item_enum/mod.rs +++ b/swayfmt/src/items/item_enum/mod.rs @@ -11,11 +11,11 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::ItemEnum; -use sway_types::{ - ast::{Delimiter, PunctKind}, - Spanned, +use sway_ast::{ + keywords::{ColonToken, EnumToken, Keyword, Token}, + CommaToken, ItemEnum, PubToken, }; +use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] mod tests; @@ -34,11 +34,11 @@ impl Format for ItemEnum { // Required for comment formatting let start_len = formatted_code.len(); // If there is a visibility token add it to the formatted_code with a ` ` after it. - if let Some(visibility) = &self.visibility { - write!(formatted_code, "{} ", visibility.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // Add enum token and name - write!(formatted_code, "{} ", self.enum_token.span().as_str())?; + write!(formatted_code, "{} ", EnumToken::AS_STR)?; self.name.format(formatted_code, formatter)?; // Format `GenericParams`, if any if let Some(generics) = &self.generics { @@ -55,21 +55,22 @@ impl Format for ItemEnum { match formatter.config.structures.field_alignment { FieldAlignment::AlignFields(enum_variant_align_threshold) => { writeln!(formatted_code)?; - let value_pairs = &fields + let type_fields = &fields .value_separator_pairs .iter() - // TODO: Handle annotations instead of stripping them - .map(|pair| (&pair.0.value, &pair.1)) + // TODO: Handle annotations instead of stripping them. + // See: https://github.com/FuelLabs/sway/issues/6802 + .map(|(type_field, _comma_token)| &type_field.value) .collect::>(); // In first iteration we are going to be collecting the lengths of the enum variants. - let variant_length: Vec = value_pairs + let variants_lengths: Vec = type_fields .iter() - .map(|(type_field, _)| type_field.name.as_str().len()) + .map(|type_field| type_field.name.as_str().len()) .collect(); - // Find the maximum length in the variant_length vector that is still smaller than enum_field_align_threshold. + // Find the maximum length that is still smaller than the align threshold. let mut max_valid_variant_length = 0; - variant_length.iter().for_each(|length| { + variants_lengths.iter().for_each(|length| { if *length > max_valid_variant_length && *length < enum_variant_align_threshold { @@ -77,13 +78,12 @@ impl Format for ItemEnum { } }); - let value_pairs_iter = value_pairs.iter().enumerate(); - for (var_index, (type_field, comma_token)) in value_pairs_iter.clone() { - write!(formatted_code, "{}", &formatter.indent_to_str()?)?; + for (var_index, type_field) in type_fields.iter().enumerate() { + write!(formatted_code, "{}", formatter.indent_to_str()?)?; // Add name type_field.name.format(formatted_code, formatter)?; - let current_variant_length = variant_length[var_index]; + let current_variant_length = variants_lengths[var_index]; if current_variant_length < max_valid_variant_length { // We need to add alignment between : and ty // max_valid_variant_length: the length of the variant that we are taking as a reference to align @@ -96,23 +96,13 @@ impl Format for ItemEnum { } } // Add `:`, ty & `CommaToken` - write!( - formatted_code, - " {} ", - type_field.colon_token.span().as_str(), - )?; + write!(formatted_code, " {} ", ColonToken::AS_STR)?; type_field.ty.format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", comma_token.span().as_str())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } if let Some(final_value) = &fields.final_value_opt { - // TODO: Handle annotation - let final_value = &final_value.value; - writeln!( - formatted_code, - "{}{}", - final_value.span().as_str(), - PunctKind::Comma.as_char(), - )?; + final_value.format(formatted_code, formatter)?; + writeln!(formatted_code)?; } } FieldAlignment::Off => fields.format(formatted_code, formatter)?, @@ -164,6 +154,7 @@ impl CurlyBrace for ItemEnum { Ok(()) } } + impl LeafSpans for ItemEnum { fn leaf_spans(&self) -> Vec { let mut collected_spans = Vec::new(); diff --git a/swayfmt/src/items/item_fn/mod.rs b/swayfmt/src/items/item_fn/mod.rs index 596f37efad2..235fc5a2179 100644 --- a/swayfmt/src/items/item_fn/mod.rs +++ b/swayfmt/src/items/item_fn/mod.rs @@ -11,8 +11,10 @@ use crate::{ }; use std::fmt::Write; use sway_ast::{ - keywords::{MutToken, RefToken, SelfToken, Token}, - FnArg, FnArgs, FnSignature, ItemFn, + keywords::{ + ColonToken, FnToken, Keyword, MutToken, RefToken, RightArrowToken, SelfToken, Token, + }, + CommaToken, FnArg, FnArgs, FnSignature, ItemFn, PubToken, }; use sway_types::{ast::Delimiter, Spanned}; @@ -152,11 +154,11 @@ fn format_fn_sig( formatter: &mut Formatter, ) -> Result<(), FormatterError> { // `pub ` - if let Some(visibility_token) = &fn_sig.visibility { - write!(formatted_code, "{} ", visibility_token.span().as_str())?; + if fn_sig.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // `fn ` + name - write!(formatted_code, "{} ", fn_sig.fn_token.span().as_str())?; + write!(formatted_code, "{} ", FnToken::AS_STR)?; fn_sig.name.format(formatted_code, formatter)?; // `` if let Some(generics) = &fn_sig.generics { @@ -169,12 +171,8 @@ fn format_fn_sig( // `)` FnSignature::close_parenthesis(formatted_code, formatter)?; // `return_type_opt` - if let Some((right_arrow, ty)) = &fn_sig.return_type_opt { - write!( - formatted_code, - " {} ", - right_arrow.ident().as_str() // `->` - )?; + if let Some((_right_arrow, ty)) = &fn_sig.return_type_opt { + write!(formatted_code, " {} ", RightArrowToken::AS_STR)?; ty.format(formatted_code, formatter)?; // `Ty` } // `WhereClause` @@ -196,7 +194,7 @@ fn format_fn_args( FnArgs::Static(args) => match formatter.shape.code_line.line_style { LineStyle::Multiline => { formatter.shape.code_line.update_expr_new_line(true); - if !args.value_separator_pairs.is_empty() || args.final_value_opt.is_some() { + if !args.is_empty() { formatter.indent(); args.format(formatted_code, formatter)?; formatter.unindent(); @@ -218,9 +216,9 @@ fn format_fn_args( write!(formatted_code, "\n{}", formatter.indent_to_str()?)?; format_self(self_token, ref_self, mutable_self, formatted_code)?; // `args_opt` - if let Some((comma, args)) = args_opt { + if let Some((_comma, args)) = args_opt { // `, ` - write!(formatted_code, "{}", comma.ident().as_str())?; + write!(formatted_code, "{}", CommaToken::AS_STR)?; // `Punctuated` args.format(formatted_code, formatter)?; } @@ -228,9 +226,9 @@ fn format_fn_args( _ => { format_self(self_token, ref_self, mutable_self, formatted_code)?; // `args_opt` - if let Some((comma, args)) = args_opt { + if let Some((_comma, args)) = args_opt { // `, ` - write!(formatted_code, "{} ", comma.ident().as_str())?; + write!(formatted_code, "{} ", CommaToken::AS_STR)?; // `Punctuated` args.format(formatted_code, formatter)?; } @@ -243,21 +241,21 @@ fn format_fn_args( } fn format_self( - self_token: &SelfToken, + _self_token: &SelfToken, ref_self: &Option, mutable_self: &Option, formatted_code: &mut FormattedCode, ) -> Result<(), FormatterError> { // `ref ` - if let Some(ref_token) = ref_self { - write!(formatted_code, "{} ", ref_token.span().as_str())?; + if ref_self.is_some() { + write!(formatted_code, "{} ", RefToken::AS_STR)?; } // `mut ` - if let Some(mut_token) = mutable_self { - write!(formatted_code, "{} ", mut_token.span().as_str())?; + if mutable_self.is_some() { + write!(formatted_code, "{} ", MutToken::AS_STR)?; } // `self` - write!(formatted_code, "{}", self_token.span().as_str())?; + write!(formatted_code, "{}", SelfToken::AS_STR)?; Ok(()) } @@ -289,7 +287,7 @@ impl Format for FnArg { ) -> Result<(), FormatterError> { self.pattern.format(formatted_code, formatter)?; // `: ` - write!(formatted_code, "{} ", self.colon_token.span().as_str())?; + write!(formatted_code, "{} ", ColonToken::AS_STR)?; write_comments( formatted_code, diff --git a/swayfmt/src/items/item_impl/mod.rs b/swayfmt/src/items/item_impl/mod.rs index 164f157ba2c..fcadf3b040c 100644 --- a/swayfmt/src/items/item_impl/mod.rs +++ b/swayfmt/src/items/item_impl/mod.rs @@ -8,7 +8,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{ItemImpl, ItemImplItem}; +use sway_ast::{ + keywords::{ForToken, ImplToken, Keyword}, + ItemImpl, ItemImplItem, +}; use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] @@ -23,14 +26,14 @@ impl Format for ItemImpl { // Required for comment formatting let start_len = formatted_code.len(); - write!(formatted_code, "{}", self.impl_token.span().as_str())?; + write!(formatted_code, "{}", ImplToken::AS_STR)?; if let Some(generic_params) = &self.generic_params_opt { generic_params.format(formatted_code, formatter)?; } write!(formatted_code, " ")?; - if let Some((path_type, for_token)) = &self.trait_opt { + if let Some((path_type, _for_token)) = &self.trait_opt { path_type.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", for_token.span().as_str())?; + write!(formatted_code, " {} ", ForToken::AS_STR)?; } self.ty.format(formatted_code, formatter)?; if let Some(where_clause) = &self.where_clause_opt { diff --git a/swayfmt/src/items/item_storage/mod.rs b/swayfmt/src/items/item_storage/mod.rs index c6fa0fdf189..acbcf5937c3 100644 --- a/swayfmt/src/items/item_storage/mod.rs +++ b/swayfmt/src/items/item_storage/mod.rs @@ -11,7 +11,10 @@ use crate::{ }, }; use std::{collections::HashMap, fmt::Write}; -use sway_ast::{keywords::Token, ItemStorage, StorageEntry, StorageField}; +use sway_ast::{ + keywords::{ColonToken, EqToken, Keyword, StorageToken, Token}, + CommaToken, ItemStorage, StorageEntry, StorageField, +}; use sway_types::{ast::Delimiter, IdentUnique, Spanned}; #[cfg(test)] @@ -32,7 +35,7 @@ impl Format for ItemStorage { let start_len = formatted_code.len(); // Add storage token - write!(formatted_code, "{}", self.storage_token.span().as_str())?; + write!(formatted_code, "{}", StorageToken::AS_STR)?; let entries = self.entries.get(); // Handle opening brace @@ -47,7 +50,8 @@ impl Format for ItemStorage { let value_pairs = &entries .value_separator_pairs .iter() - // TODO: Handle annotations instead of stripping them + // TODO: Handle annotations instead of stripping them. + // See: https://github.com/FuelLabs/sway/issues/6802 .map(|(storage_field, comma_token)| (&storage_field.value, comma_token)) .collect::>(); // In first iteration we are going to be collecting the lengths of the @@ -114,7 +118,7 @@ impl Format for ItemStorage { ItemStorage::open_curly_brace(formatted_code, formatter)?; writeln!(formatted_code)?; - for (e, comma_token) in + for (e, _comma_token) in namespace.clone().into_inner().value_separator_pairs { format_entry( @@ -124,7 +128,7 @@ impl Format for ItemStorage { field_lengths, max_valid_field_length, )?; - writeln!(formatted_code, "{}", comma_token.ident().as_str())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } if let Some(final_value) = &namespace.clone().into_inner().final_value_opt @@ -159,17 +163,9 @@ impl Format for ItemStorage { } } // Add `:`, `ty` & `CommaToken` - write!( - formatted_code, - " {} ", - storage_field.colon_token.ident().as_str(), - )?; + write!(formatted_code, " {} ", ColonToken::AS_STR)?; storage_field.ty.format(formatted_code, formatter)?; - write!( - formatted_code, - " {} ", - storage_field.eq_token.ident().as_str() - )?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; storage_field .initializer .format(formatted_code, formatter)?; @@ -177,7 +173,7 @@ impl Format for ItemStorage { Ok(()) } - for (storage_entry, comma_token) in value_pairs.iter().clone() { + for (storage_entry, _comma_token) in value_pairs.iter().clone() { format_entry( formatted_code, formatter, @@ -185,7 +181,7 @@ impl Format for ItemStorage { &field_lengths, max_valid_field_length, )?; - writeln!(formatted_code, "{}", comma_token.ident().as_str())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } if let Some(final_value) = &entries.final_value_opt { format_entry( diff --git a/swayfmt/src/items/item_struct/mod.rs b/swayfmt/src/items/item_struct/mod.rs index 8ebefab2898..40946639ebb 100644 --- a/swayfmt/src/items/item_struct/mod.rs +++ b/swayfmt/src/items/item_struct/mod.rs @@ -11,7 +11,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::ItemStruct; +use sway_ast::{ + keywords::{ColonToken, Keyword, StructToken, Token}, + CommaToken, ItemStruct, PubToken, +}; use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] @@ -31,11 +34,11 @@ impl Format for ItemStruct { // Required for comment formatting let start_len = formatted_code.len(); // If there is a visibility token add it to the formatted_code with a ` ` after it. - if let Some(visibility) = &self.visibility { - write!(formatted_code, "{} ", visibility.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // Add struct token and name - write!(formatted_code, "{} ", self.struct_token.span().as_str())?; + write!(formatted_code, "{} ", StructToken::AS_STR)?; self.name.format(formatted_code, formatter)?; // Format `GenericParams`, if any if let Some(generics) = &self.generics { @@ -52,7 +55,7 @@ impl Format for ItemStruct { // Handle opening brace Self::open_curly_brace(formatted_code, formatter)?; - if fields.final_value_opt.is_none() && fields.value_separator_pairs.is_empty() { + if fields.is_empty() { write_comments(formatted_code, self.span().into(), formatter)?; } @@ -60,74 +63,67 @@ impl Format for ItemStruct { // Determine alignment tactic match formatter.config.structures.field_alignment { - FieldAlignment::AlignFields(enum_variant_align_threshold) => { + FieldAlignment::AlignFields(struct_field_align_threshold) => { writeln!(formatted_code)?; - let value_pairs = &fields + let type_fields = &fields .value_separator_pairs .iter() - // TODO: Handle annotations instead of stripping them - .map(|(type_field, comma_token)| (&type_field.value, comma_token)) + // TODO: Handle annotations instead of stripping them. + // See: https://github.com/FuelLabs/sway/issues/6802 + .map(|(type_field, _comma_token)| &type_field.value) .collect::>(); - // In first iteration we are going to be collecting the lengths of the struct variants. + // In first iteration we are going to be collecting the lengths of the struct fields. // We need to include the `pub` keyword in the length, if the field is public, // together with one space character between the `pub` and the name. - let variant_length: Vec = value_pairs + let fields_lengths: Vec = type_fields .iter() - .map(|(type_field, _)| { + .map(|type_field| { type_field .visibility .as_ref() - // We don't want to hard code the token here to `pub` or just hardcode 4. - // This is in case we introduce e.g. `pub(crate)` one day. - .map_or(0, |token| token.span().as_str().len() + 1) + .map_or(0, |_pub_token| PubToken::AS_STR.len() + 1) + type_field.name.as_str().len() }) .collect(); - // Find the maximum length in the variant_length vector that is still smaller than struct_field_align_threshold. - let mut max_valid_variant_length = 0; - variant_length.iter().for_each(|length| { - if *length > max_valid_variant_length - && *length < enum_variant_align_threshold + // Find the maximum length that is still smaller than the align threshold. + let mut max_valid_field_length = 0; + fields_lengths.iter().for_each(|length| { + if *length > max_valid_field_length + && *length < struct_field_align_threshold { - max_valid_variant_length = *length; + max_valid_field_length = *length; } }); - let value_pairs_iter = value_pairs.iter().enumerate(); - for (var_index, (type_field, comma_token)) in value_pairs_iter.clone() { + for (var_index, type_field) in type_fields.iter().enumerate() { write!(formatted_code, "{}", formatter.indent_to_str()?)?; // If there is a visibility token add it to the formatted_code with a ` ` after it. - if let Some(visibility) = &type_field.visibility { - write!(formatted_code, "{} ", visibility.span().as_str())?; + if type_field.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // Add name type_field.name.format(formatted_code, formatter)?; - let current_variant_length = variant_length[var_index]; - if current_variant_length < max_valid_variant_length { + let current_field_length = fields_lengths[var_index]; + if current_field_length < max_valid_field_length { // We need to add alignment between : and ty // max_valid_variant_length: the length of the variant that we are taking as a reference to align // current_variant_length: the length of the current variant that we are trying to format let mut required_alignment = - max_valid_variant_length - current_variant_length; + max_valid_field_length - current_field_length; while required_alignment != 0 { write!(formatted_code, " ")?; required_alignment -= 1; } } // Add `:`, ty & `CommaToken` - write!( - formatted_code, - " {} ", - type_field.colon_token.span().as_str(), - )?; + write!(formatted_code, " {} ", ColonToken::AS_STR)?; type_field.ty.format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", comma_token.span().as_str())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } if let Some(final_value) = &fields.final_value_opt { - // TODO: Handle annotation - let final_value = &final_value.value; - write!(formatted_code, "{}", final_value.span().as_str())?; + final_value.format(formatted_code, formatter)?; + writeln!(formatted_code)?; } } FieldAlignment::Off => { diff --git a/swayfmt/src/items/item_trait/mod.rs b/swayfmt/src/items/item_trait/mod.rs index 10f94eee8b4..32caff67128 100644 --- a/swayfmt/src/items/item_trait/mod.rs +++ b/swayfmt/src/items/item_trait/mod.rs @@ -8,7 +8,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{keywords::Token, ItemTrait, ItemTraitItem, Traits}; +use sway_ast::{ + keywords::{AddToken, ColonToken, Keyword, Token, TraitToken}, + ItemTrait, ItemTraitItem, PubToken, Traits, +}; use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] @@ -23,23 +26,23 @@ impl Format for ItemTrait { // Required for comment formatting let start_len = formatted_code.len(); // `pub ` - if let Some(pub_token) = &self.visibility { - write!(formatted_code, "{} ", pub_token.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // `trait name` write!( formatted_code, "{} {}", - self.trait_token.span().as_str(), - self.name.span().as_str() + TraitToken::AS_STR, + self.name.as_str(), )?; // `` if let Some(generics) = &self.generics { generics.format(formatted_code, formatter)?; } // `: super_trait + super_trait` - if let Some((colon_token, traits)) = &self.super_traits { - write!(formatted_code, "{} ", colon_token.ident().as_str())?; + if let Some((_colon_token, traits)) = &self.super_traits { + write!(formatted_code, "{} ", ColonToken::AS_STR)?; traits.format(formatted_code, formatter)?; } // `where` @@ -145,8 +148,8 @@ impl Format for Traits { // additional `PathType`s // // ` + PathType` - for (add_token, path_type) in self.suffixes.iter() { - write!(formatted_code, " {} ", add_token.span().as_str())?; + for (_add_token, path_type) in self.suffixes.iter() { + write!(formatted_code, " {} ", AddToken::AS_STR)?; path_type.format(formatted_code, formatter)?; } diff --git a/swayfmt/src/items/item_trait_type.rs b/swayfmt/src/items/item_trait_type.rs index f3af2251b2f..eb363c1ef7b 100644 --- a/swayfmt/src/items/item_trait_type.rs +++ b/swayfmt/src/items/item_trait_type.rs @@ -4,7 +4,10 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::{keywords::Token, TraitType}; +use sway_ast::{ + keywords::{EqToken, Keyword, SemicolonToken, Token, TypeToken}, + TraitType, +}; use sway_types::Spanned; impl Format for TraitType { @@ -16,15 +19,15 @@ impl Format for TraitType { // Required for comment formatting let start_len = formatted_code.len(); - // Add the const token - write!(formatted_code, "{} ", self.type_token.span().as_str())?; + // Add the type token + write!(formatted_code, "{} ", TypeToken::AS_STR)?; - // Add name of the const + // Add name of the type self.name.format(formatted_code, formatter)?; // Check if ` = ` exists - if let Some(eq_token) = &self.eq_token_opt { - write!(formatted_code, " {} ", eq_token.ident().as_str())?; + if self.eq_token_opt.is_some() { + write!(formatted_code, " {} ", EqToken::AS_STR)?; } // Check if ty exists @@ -32,7 +35,7 @@ impl Format for TraitType { ty.format(formatted_code, formatter)?; } - write!(formatted_code, "{}", self.semicolon_token.ident().as_str())?; + write!(formatted_code, "{}", SemicolonToken::AS_STR)?; rewrite_with_comments::( formatter, diff --git a/swayfmt/src/items/item_type_alias.rs b/swayfmt/src/items/item_type_alias.rs index 4870baeb031..86221a70f5b 100644 --- a/swayfmt/src/items/item_type_alias.rs +++ b/swayfmt/src/items/item_type_alias.rs @@ -4,7 +4,10 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::{keywords::Token, ItemTypeAlias}; +use sway_ast::{ + keywords::{EqToken, Keyword, SemicolonToken, Token, TypeToken}, + ItemTypeAlias, PubToken, +}; use sway_types::Spanned; impl Format for ItemTypeAlias { @@ -17,24 +20,24 @@ impl Format for ItemTypeAlias { let start_len = formatted_code.len(); // Check if visibility token exists if so add it. - if let Some(visibility_token) = &self.visibility { - write!(formatted_code, "{} ", visibility_token.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // Add the `type` token - write!(formatted_code, "{} ", self.type_token.span().as_str())?; + write!(formatted_code, "{} ", TypeToken::AS_STR)?; // Add name of the type alias self.name.format(formatted_code, formatter)?; // Add the `=` token - write!(formatted_code, " {} ", self.eq_token.ident().as_str())?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; // Format and add `ty` self.ty.format(formatted_code, formatter)?; // Add the `;` token - write!(formatted_code, "{}", self.semicolon_token.ident().as_str())?; + write!(formatted_code, "{}", SemicolonToken::AS_STR)?; rewrite_with_comments::( formatter, diff --git a/swayfmt/src/items/item_use/mod.rs b/swayfmt/src/items/item_use/mod.rs index ce304183495..838248fb1c7 100644 --- a/swayfmt/src/items/item_use/mod.rs +++ b/swayfmt/src/items/item_use/mod.rs @@ -9,11 +9,11 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{CommaToken, ItemUse, UseTree}; -use sway_types::{ - ast::{Delimiter, PunctKind}, - Spanned, +use sway_ast::{ + keywords::{AsToken, Keyword, SemicolonToken, StarToken, Token, UseToken}, + CommaToken, DoubleColonToken, ItemUse, PubToken, UseTree, }; +use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] mod tests; @@ -64,23 +64,40 @@ impl Format for UseTree { match self { Self::Group { imports } => { // check for only one import - if imports.inner.value_separator_pairs.is_empty() { + if imports.inner.value_separator_pairs.is_empty() + && !formatter.shape.code_line.line_style.is_multiline() + { + // we can have: path::{single_import} if let Some(single_import) = &imports.inner.final_value_opt { single_import.format(formatted_code, formatter)?; } + } else if imports.inner.value_separator_pairs.len() == 1 + && imports.inner.has_trailing_punctuation() + && !formatter.shape.code_line.line_style.is_multiline() + { + // but we can also have: path::{single_import,} + // note that in the case of multiline we want to keep the trailing comma + let single_import = &imports + .inner + .value_separator_pairs + .first() + .expect("the `if` condition ensures the existence of the first element") + .0; + single_import.format(formatted_code, formatter)?; } else { Self::open_curly_brace(formatted_code, formatter)?; // sort group imports let imports = imports.get(); let value_pairs = &imports.value_separator_pairs; - let mut commas: Vec<&CommaToken> = Vec::new(); + // track how many commas we have, to simplify checking for trailing element or trailing comma + let mut commas: Vec<()> = Vec::new(); let mut ord_vec: Vec = value_pairs .iter() .map( - |(use_tree, comma_token)| -> Result { + |(use_tree, _comma_token)| -> Result { let mut buf = FormattedCode::new(); use_tree.format(&mut buf, formatter)?; - commas.push(comma_token); + commas.push(()); // we have a comma token Ok(buf) }, ) @@ -102,15 +119,16 @@ impl Format for UseTree { a.to_lowercase().cmp(&b.to_lowercase()) } }); - for (use_tree, comma) in ord_vec.iter_mut().zip(commas.iter()) { - write!(use_tree, "{}", comma.span().as_str())?; + // zip will take only the parts of `ord_vec` before the last comma + for (use_tree, _) in ord_vec.iter_mut().zip(commas.iter()) { + write!(use_tree, "{}", CommaToken::AS_STR)?; } match formatter.shape.code_line.line_style { LineStyle::Multiline => { if imports.final_value_opt.is_some() { if let Some(last) = ord_vec.iter_mut().last() { - write!(last, "{}", PunctKind::Comma.as_char())?; + write!(last, "{}", CommaToken::AS_STR)?; } } @@ -122,39 +140,48 @@ impl Format for UseTree { )?; } _ => { - write!(formatted_code, "{}", ord_vec.join(" "))?; + if imports.has_trailing_punctuation() { + // remove the trailing punctuation + write!( + formatted_code, + "{}", + ord_vec.join(" ").trim_end_matches(',') + )?; + } else { + write!(formatted_code, "{}", ord_vec.join(" "))?; + } } } Self::close_curly_brace(formatted_code, formatter)?; } } - Self::Name { name } => write!(formatted_code, "{}", name.span().as_str())?, + Self::Name { name } => write!(formatted_code, "{}", name.as_str())?, Self::Rename { name, - as_token, + as_token: _, alias, } => { write!( formatted_code, "{} {} {}", - name.span().as_str(), - as_token.span().as_str(), - alias.span().as_str() + name.as_str(), + AsToken::AS_STR, + alias.as_str(), )?; } - Self::Glob { star_token } => { - write!(formatted_code, "{}", star_token.span().as_str())?; + Self::Glob { star_token: _ } => { + write!(formatted_code, "{}", StarToken::AS_STR)?; } Self::Path { prefix, - double_colon_token, + double_colon_token: _, suffix, } => { write!( formatted_code, "{}{}", - prefix.span().as_str(), - double_colon_token.span().as_str() + prefix.as_str(), + DoubleColonToken::AS_STR, )?; suffix.format(formatted_code, formatter)?; } @@ -208,19 +235,15 @@ fn format_use_stmt( formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - if let Some(pub_token) = &item_use.visibility { - write!(formatted_code, "{} ", pub_token.span().as_str())?; + if item_use.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } - write!(formatted_code, "{} ", item_use.use_token.span().as_str())?; - if let Some(root_import) = &item_use.root_import { - write!(formatted_code, "{}", root_import.span().as_str())?; + write!(formatted_code, "{} ", UseToken::AS_STR)?; + if item_use.root_import.is_some() { + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; } item_use.tree.format(formatted_code, formatter)?; - write!( - formatted_code, - "{}", - item_use.semicolon_token.span().as_str() - )?; + write!(formatted_code, "{}", SemicolonToken::AS_STR)?; Ok(()) } diff --git a/swayfmt/src/items/item_use/tests.rs b/swayfmt/src/items/item_use/tests.rs index 0b0a207bc37..64794080d65 100644 --- a/swayfmt/src/items/item_use/tests.rs +++ b/swayfmt/src/items/item_use/tests.rs @@ -10,6 +10,15 @@ fmt_test_item!(multiline "use foo::{ };", out_of_order "use foo::{yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, quux, xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx};" ); + +fmt_test_item!(multiline_with_trailing_comma "use foo::{ + quux, + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, + yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, +};", + out_of_order "use foo::{yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, quux, xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,};" +); + fmt_test_item!(multiline_nested "use foo::{ Quux::{ a, @@ -22,10 +31,42 @@ fmt_test_item!(multiline_nested "use foo::{ out_of_order "use foo::{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, Quux::{b, a, C}, yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx};" ); +fmt_test_item!(multiline_nested_with_trailing_comma "use foo::{ + Quux::{ + a, + b, + C, + }, + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, + yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, +};", + out_of_order "use foo::{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, Quux::{b, a, C,}, yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,};" +); + fmt_test_item!(single_line_sort "use foo::{bar, baz, Quux::{a, b, C}};", out_of_order "use foo::{baz, Quux::{b, a, C}, bar};" ); +fmt_test_item!(single_line_sort_with_trailing_comma "use foo::{bar, baz, Quux::{a, b, C}};", + out_of_order "use foo::{baz, Quux::{b, a, C,}, bar,};" +); + fmt_test_item!(single_import_without_braces "use std::tx::tx_id;", braced_single_import "use std::tx::{tx_id};" ); + +fmt_test_item!(single_import_without_braces_with_trailing_comma "use std::tx::tx_id;", + braced_single_import "use std::tx::{tx_id,};" +); + +fmt_test_item!(single_import_multiline_with_braces "use std::tx::{ + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, +};", + braced_single_import "use std::tx::{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx};" +); + +fmt_test_item!(single_import_multiline_with_braces_with_trailing_comma "use std::tx::{ + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, +};", + braced_single_import "use std::tx::{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,};" +); diff --git a/swayfmt/src/module/mod.rs b/swayfmt/src/module/mod.rs index db49d4f806c..de95433281c 100644 --- a/swayfmt/src/module/mod.rs +++ b/swayfmt/src/module/mod.rs @@ -4,7 +4,12 @@ use crate::{ utils::map::byte_span::{self, ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::{Item, ItemKind, Module, ModuleKind}; +use sway_ast::{ + keywords::{ + ContractToken, Keyword, LibraryToken, PredicateToken, ScriptToken, SemicolonToken, Token, + }, + Item, ItemKind, Module, ModuleKind, +}; use sway_types::Spanned; pub(crate) mod item; @@ -18,7 +23,7 @@ impl Format for Module { ) -> Result<(), FormatterError> { write_comments(formatted_code, 0..self.span().start(), formatter)?; self.kind.format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", self.semicolon_token.span().as_str())?; + writeln!(formatted_code, "{}", SemicolonToken::AS_STR)?; // Format comments between module kind declaration and rest of items if !self.items.is_empty() { @@ -69,17 +74,17 @@ impl Format for ModuleKind { _formatter: &mut Formatter, ) -> Result<(), FormatterError> { match self { - ModuleKind::Script { script_token } => { - write!(formatted_code, "{}", script_token.span().as_str())? + ModuleKind::Script { script_token: _ } => { + write!(formatted_code, "{}", ScriptToken::AS_STR)? } - ModuleKind::Contract { contract_token } => { - write!(formatted_code, "{}", contract_token.span().as_str())? + ModuleKind::Contract { contract_token: _ } => { + write!(formatted_code, "{}", ContractToken::AS_STR)? } - ModuleKind::Predicate { predicate_token } => { - write!(formatted_code, "{}", predicate_token.span().as_str())? + ModuleKind::Predicate { predicate_token: _ } => { + write!(formatted_code, "{}", PredicateToken::AS_STR)? } - ModuleKind::Library { library_token } => { - write!(formatted_code, "{}", library_token.span().as_str())?; + ModuleKind::Library { library_token: _ } => { + write!(formatted_code, "{}", LibraryToken::AS_STR)?; } }; diff --git a/swayfmt/src/module/submodule.rs b/swayfmt/src/module/submodule.rs index 0c2a6c4d31b..6edb91ab574 100644 --- a/swayfmt/src/module/submodule.rs +++ b/swayfmt/src/module/submodule.rs @@ -3,7 +3,11 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::submodule::Submodule; +use sway_ast::{ + keywords::{Keyword, ModToken, SemicolonToken, Token}, + submodule::Submodule, + PubToken, +}; use sway_types::Spanned; impl Format for Submodule { @@ -12,12 +16,12 @@ impl Format for Submodule { formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - if let Some(pub_token) = &self.visibility { - write!(formatted_code, "{} ", pub_token.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } - write!(formatted_code, "{} ", self.mod_token.span().as_str())?; + write!(formatted_code, "{} ", ModToken::AS_STR)?; self.name.format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", self.semicolon_token.span().as_str())?; + writeln!(formatted_code, "{}", SemicolonToken::AS_STR)?; Ok(()) } } diff --git a/swayfmt/src/parse.rs b/swayfmt/src/parse.rs index 9d4ccadbbfb..17befe22cc3 100644 --- a/swayfmt/src/parse.rs +++ b/swayfmt/src/parse.rs @@ -1,9 +1,7 @@ use crate::{error::ParseFileError, Formatter, FormatterError}; -use std::path::PathBuf; use std::sync::Arc; use sway_ast::{attribute::Annotated, token::CommentedTokenStream, Module}; use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::SourceEngine; fn with_handler( run: impl FnOnce(&Handler) -> Result, @@ -16,13 +14,8 @@ fn with_handler( .ok_or(ParseFileError(errors)) } -pub fn parse_file( - source_engine: &SourceEngine, - src: Arc, - path: Option>, -) -> Result, ParseFileError> { - let source_id = path.map(|p| source_engine.get_source_id(p.as_ref())); - with_handler(|h| sway_parse::parse_file(h, src, source_id)) +pub fn parse_file(src: Arc) -> Result, ParseFileError> { + with_handler(|h| sway_parse::parse_file(h, src, None)) } pub fn lex(input: &Arc) -> Result { diff --git a/swayfmt/src/utils/language/attribute.rs b/swayfmt/src/utils/language/attribute.rs index daa6b7e5611..b9662bf8d56 100644 --- a/swayfmt/src/utils/language/attribute.rs +++ b/swayfmt/src/utils/language/attribute.rs @@ -8,12 +8,12 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::attribute::{Annotated, Attribute, AttributeArg, AttributeDecl, AttributeHashKind}; -use sway_types::{ - ast::{Delimiter, PunctKind}, - constants::DOC_COMMENT_ATTRIBUTE_NAME, - Spanned, +use sway_ast::{ + attribute::{Annotated, Attribute, AttributeArg, AttributeDecl, AttributeHashKind}, + keywords::{HashToken, Token}, + CommaToken, }; +use sway_types::{ast::Delimiter, constants::DOC_COMMENT_ATTRIBUTE_NAME, Spanned}; impl Format for Annotated { fn format( @@ -56,11 +56,12 @@ impl Format for AttributeArg { fn format( &self, formatted_code: &mut FormattedCode, - _formatter: &mut Formatter, + formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, "{}", self.name.span().as_str())?; + write!(formatted_code, "{}", self.name.as_str())?; if let Some(value) = &self.value { - write!(formatted_code, " = {}", value.span().as_str())?; + write!(formatted_code, " = ")?; + value.format(formatted_code, formatter)?; } Ok(()) @@ -114,11 +115,12 @@ impl Format for AttributeDecl { // invariant: attribute lists cannot be empty // `#` - let hash_type_token_span = match &self.hash_kind { - AttributeHashKind::Inner(_) => Err(FormatterError::HashBangAttributeError), - AttributeHashKind::Outer(hash_token) => Ok(hash_token.span()), + match &self.hash_kind { + AttributeHashKind::Inner(_) => return Err(FormatterError::HashBangAttributeError), + AttributeHashKind::Outer(_hash_token) => { + write!(formatted_code, "{}", HashToken::AS_STR)?; + } }; - write!(formatted_code, "{}", hash_type_token_span?.as_str())?; // `[` Self::open_square_bracket(formatted_code, formatter)?; let mut regular_attrs = regular_attrs.iter().peekable(); @@ -127,7 +129,7 @@ impl Format for AttributeDecl { formatter.shape.with_default_code_line(), |formatter| -> Result<(), FormatterError> { // name e.g. `storage` - write!(formatted_code, "{}", attr.name.span().as_str())?; + write!(formatted_code, "{}", attr.name.as_str())?; if let Some(args) = &attr.args { // `(` Self::open_parenthesis(formatted_code, formatter)?; @@ -141,7 +143,7 @@ impl Format for AttributeDecl { )?; // do not put a separator after the last attribute if regular_attrs.peek().is_some() { - write!(formatted_code, "{} ", PunctKind::Comma.as_char())?; + write!(formatted_code, "{} ", CommaToken::AS_STR)?; } } // `]\n` diff --git a/swayfmt/src/utils/language/expr/abi_cast.rs b/swayfmt/src/utils/language/expr/abi_cast.rs index 14493f3f4d3..5c6545891ab 100644 --- a/swayfmt/src/utils/language/expr/abi_cast.rs +++ b/swayfmt/src/utils/language/expr/abi_cast.rs @@ -6,7 +6,7 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::AbiCastArgs; +use sway_ast::{keywords::Token, AbiCastArgs, CommaToken}; use sway_types::{ast::Delimiter, Spanned}; impl Format for AbiCastArgs { @@ -17,7 +17,7 @@ impl Format for AbiCastArgs { ) -> Result<(), FormatterError> { Self::open_parenthesis(formatted_code, formatter)?; self.name.format(formatted_code, formatter)?; - write!(formatted_code, "{} ", self.comma_token.span().as_str())?; + write!(formatted_code, "{} ", CommaToken::AS_STR)?; self.address.format(formatted_code, formatter)?; Self::close_parenthesis(formatted_code, formatter)?; diff --git a/swayfmt/src/utils/language/expr/asm_block.rs b/swayfmt/src/utils/language/expr/asm_block.rs index 19f92f5ea68..458bfec669f 100644 --- a/swayfmt/src/utils/language/expr/asm_block.rs +++ b/swayfmt/src/utils/language/expr/asm_block.rs @@ -9,6 +9,7 @@ use crate::{ use std::fmt::Write; use sway_ast::{ expr::asm::{AsmBlock, AsmBlockContents, AsmFinalExpr, AsmRegisterDeclaration}, + keywords::{AsmToken, ColonToken, Keyword, SemicolonToken, Token}, Instruction, }; use sway_types::{ast::Delimiter, Spanned}; @@ -56,7 +57,7 @@ fn format_asm_block( formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, "{}", asm_block.asm_token.span().as_str())?; + write!(formatted_code, "{}", AsmToken::AS_STR)?; formatter.with_shape( formatter.shape.with_default_code_line(), @@ -174,8 +175,8 @@ impl Format for AsmRegisterDeclaration { formatter: &mut Formatter, ) -> Result<(), FormatterError> { self.register.format(formatted_code, formatter)?; - if let Some((colon_token, expr)) = &self.value_opt { - write!(formatted_code, "{} ", colon_token.span().as_str())?; + if let Some((_colon_token, expr)) = &self.value_opt { + write!(formatted_code, "{} ", ColonToken::AS_STR)?; expr.format(formatted_code, formatter)?; } @@ -189,7 +190,7 @@ impl Format for Instruction { formatted_code: &mut FormattedCode, _formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, "{}", &self.op_code_ident().as_str())?; + write!(formatted_code, "{}", self.op_code_as_str())?; for arg in self.register_arg_idents() { write!(formatted_code, " {}", arg.as_str())? } @@ -206,10 +207,10 @@ impl Format for AsmBlockContents { formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - for (instruction, semicolon_token) in self.instructions.iter() { + for (instruction, _semicolon_token) in self.instructions.iter() { write!(formatted_code, "{}", formatter.indent_to_str()?)?; instruction.format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", semicolon_token.span().as_str())? + writeln!(formatted_code, "{}", SemicolonToken::AS_STR)? } if let Some(final_expr) = &self.final_expr_opt { if formatter.shape.code_line.line_style == LineStyle::Multiline { @@ -232,8 +233,8 @@ impl Format for AsmFinalExpr { formatter: &mut Formatter, ) -> Result<(), FormatterError> { self.register.format(formatted_code, formatter)?; - if let Some((colon_token, ty)) = &self.ty_opt { - write!(formatted_code, "{} ", colon_token.span().as_str())?; + if let Some((_colon_token, ty)) = &self.ty_opt { + write!(formatted_code, "{} ", ColonToken::AS_STR)?; ty.format(formatted_code, formatter)?; } diff --git a/swayfmt/src/utils/language/expr/assignable.rs b/swayfmt/src/utils/language/expr/assignable.rs index b5e278464dd..1df99ad70cf 100644 --- a/swayfmt/src/utils/language/expr/assignable.rs +++ b/swayfmt/src/utils/language/expr/assignable.rs @@ -6,7 +6,12 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{assignable::ElementAccess, expr::ReassignmentOp, Assignable, Expr}; +use sway_ast::{ + assignable::ElementAccess, + expr::ReassignmentOp, + keywords::{DotToken, StarToken, Token}, + Assignable, Expr, +}; use sway_types::Spanned; impl Format for ElementAccess { @@ -27,26 +32,21 @@ impl Format for ElementAccess { } ElementAccess::FieldProjection { target, - dot_token, + dot_token: _, name, } => { target.format(formatted_code, formatter)?; - write!(formatted_code, "{}", dot_token.span().as_str())?; + write!(formatted_code, "{}", DotToken::AS_STR)?; name.format(formatted_code, formatter)?; } ElementAccess::TupleFieldProjection { target, - dot_token, - field: _, - field_span, + dot_token: _, + field, + field_span: _, } => { target.format(formatted_code, formatter)?; - write!( - formatted_code, - "{}{}", - dot_token.span().as_str(), - field_span.as_str() - )?; + write!(formatted_code, "{}{}", DotToken::AS_STR, field)?; } } Ok(()) @@ -63,8 +63,11 @@ impl Format for Assignable { Assignable::ElementAccess(element_access) => { element_access.format(formatted_code, formatter)? } - Assignable::Deref { star_token, expr } => { - write!(formatted_code, "{}", star_token.span().as_str())?; + Assignable::Deref { + star_token: _, + expr, + } => { + write!(formatted_code, "{}", StarToken::AS_STR)?; expr.format(formatted_code, formatter)?; } } @@ -78,7 +81,7 @@ impl Format for ReassignmentOp { formatted_code: &mut FormattedCode, _formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, " {} ", self.span.as_str())?; + write!(formatted_code, " {} ", self.variant.as_str())?; Ok(()) } } diff --git a/swayfmt/src/utils/language/expr/collections.rs b/swayfmt/src/utils/language/expr/collections.rs index f175329bbd9..af34214f21c 100644 --- a/swayfmt/src/utils/language/expr/collections.rs +++ b/swayfmt/src/utils/language/expr/collections.rs @@ -6,7 +6,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{ExprArrayDescriptor, ExprTupleDescriptor}; +use sway_ast::{ + keywords::{SemicolonToken, Token}, + CommaToken, ExprArrayDescriptor, ExprTupleDescriptor, +}; use sway_types::{ast::Delimiter, Spanned}; impl Format for ExprTupleDescriptor { @@ -20,18 +23,18 @@ impl Format for ExprTupleDescriptor { Self::Nil => {} Self::Cons { head, - comma_token, + comma_token: _, tail, } => match formatter.shape.code_line.line_style { LineStyle::Multiline => { write!(formatted_code, "{}", formatter.indent_to_str()?)?; head.format(formatted_code, formatter)?; - write!(formatted_code, "{}", comma_token.span().as_str())?; + write!(formatted_code, "{}", CommaToken::AS_STR)?; tail.format(formatted_code, formatter)?; } _ => { head.format(formatted_code, formatter)?; - write!(formatted_code, "{} ", comma_token.span().as_str())?; + write!(formatted_code, "{} ", CommaToken::AS_STR)?; tail.format(formatted_code, formatter)?; } }, @@ -91,11 +94,11 @@ impl Format for ExprArrayDescriptor { } Self::Repeat { value, - semicolon_token, + semicolon_token: _, length, } => { value.format(formatted_code, formatter)?; - write!(formatted_code, "{} ", semicolon_token.span().as_str())?; + write!(formatted_code, "{} ", SemicolonToken::AS_STR)?; length.format(formatted_code, formatter)?; } } diff --git a/swayfmt/src/utils/language/expr/conditional.rs b/swayfmt/src/utils/language/expr/conditional.rs index f21e71c133d..b97d5896c47 100644 --- a/swayfmt/src/utils/language/expr/conditional.rs +++ b/swayfmt/src/utils/language/expr/conditional.rs @@ -10,7 +10,11 @@ use crate::{ }, }; use std::{fmt::Write, ops::Range}; -use sway_ast::{expr::LoopControlFlow, IfCondition, IfExpr, MatchBranch, MatchBranchKind}; +use sway_ast::{ + expr::LoopControlFlow, + keywords::{ElseToken, EqToken, FatRightArrowToken, IfToken, Keyword, LetToken, Token}, + CommaToken, IfCondition, IfExpr, MatchBranch, MatchBranchKind, +}; use sway_types::{ast::Delimiter, Spanned}; impl Format for IfExpr { @@ -125,7 +129,7 @@ fn format_if_condition( formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, "{} ", if_expr.if_token.span().as_str())?; + write!(formatted_code, "{} ", IfToken::AS_STR)?; if formatter.shape.code_line.line_style == LineStyle::Multiline { formatter.indent(); if_expr.condition.format(formatted_code, formatter)?; @@ -181,11 +185,11 @@ fn format_else_opt( )?; if comments_written { - write!(else_if_str, "{}", formatter.indent_to_str()?,)?; + write!(else_if_str, "{}", formatter.indent_to_str()?)?; } else { write!(else_if_str, " ")?; } - write!(else_if_str, "{}", else_token.span().as_str())?; + write!(else_if_str, "{}", ElseToken::AS_STR)?; match &control_flow { LoopControlFlow::Continue(if_expr) => { write!(else_if_str, " ")?; @@ -263,14 +267,14 @@ impl Format for IfCondition { expr.format(formatted_code, formatter)?; } Self::Let { - let_token, + let_token: _, lhs, - eq_token, + eq_token: _, rhs, } => { - write!(formatted_code, "{} ", let_token.span().as_str())?; + write!(formatted_code, "{} ", LetToken::AS_STR)?; lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", eq_token.span().as_str())?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } } @@ -286,11 +290,7 @@ impl Format for MatchBranch { formatter: &mut Formatter, ) -> Result<(), FormatterError> { self.pattern.format(formatted_code, formatter)?; - write!( - formatted_code, - " {} ", - self.fat_right_arrow_token.span().as_str() - )?; + write!(formatted_code, " {} ", FatRightArrowToken::AS_STR)?; self.kind.format(formatted_code, formatter)?; Ok(()) @@ -348,13 +348,16 @@ impl Format for MatchBranchKind { write!(formatted_code, "{}", formatter.indent_to_str()?)?; } Self::close_curly_brace(formatted_code, formatter)?; - if let Some(comma_token) = comma_token_opt { - write!(formatted_code, "{}", comma_token.span().as_str())?; + if comma_token_opt.is_some() { + write!(formatted_code, "{}", CommaToken::AS_STR)?; } } - Self::Expr { expr, comma_token } => { + Self::Expr { + expr, + comma_token: _, + } => { expr.format(formatted_code, formatter)?; - write!(formatted_code, "{}", comma_token.span().as_str())?; + write!(formatted_code, "{}", CommaToken::AS_STR)?; } } diff --git a/swayfmt/src/utils/language/expr/mod.rs b/swayfmt/src/utils/language/expr/mod.rs index a65eb3bc527..9fd5005a24a 100644 --- a/swayfmt/src/utils/language/expr/mod.rs +++ b/swayfmt/src/utils/language/expr/mod.rs @@ -10,11 +10,8 @@ use crate::{ }; use std::fmt::Write; use sway_ast::{ - brackets::Parens, - keywords::{CommaToken, DotToken}, - punctuated::Punctuated, - Braces, CodeBlockContents, Expr, ExprStructField, IfExpr, MatchBranch, PathExpr, - PathExprSegment, + brackets::Parens, keywords::*, punctuated::Punctuated, Braces, CodeBlockContents, Expr, + ExprStructField, IfExpr, MatchBranch, PathExpr, PathExprSegment, }; use sway_types::{ast::Delimiter, Spanned}; @@ -79,7 +76,7 @@ fn two_parts_expr( )?; } _ => { - write!(formatted_code, " {} ", operator,)?; + write!(formatted_code, " {} ", operator)?; } } write!(formatted_code, "{}", rhs_code)?; @@ -99,8 +96,8 @@ impl Format for Expr { } Self::Path(path) => path.format(formatted_code, formatter)?, Self::Literal(lit) => lit.format(formatted_code, formatter)?, - Self::AbiCast { abi_token, args } => { - write!(formatted_code, "{}", abi_token.span().as_str())?; + Self::AbiCast { abi_token: _, args } => { + write!(formatted_code, "{}", AbiToken::AS_STR)?; args.get().format(formatted_code, formatter)?; } Self::Struct { path, fields } => { @@ -205,7 +202,7 @@ impl Format for Expr { .get_line_style(None, Some(body_width), &formatter.config); if formatter.shape.code_line.line_style == LineStyle::Multiline { - // Expr needs to be splitten into multiple lines + // Expr needs to be split into multiple lines array_descriptor.format(formatted_code, formatter)?; } else { // Expr fits in a single line @@ -218,10 +215,10 @@ impl Format for Expr { } Self::Asm(asm_block) => asm_block.format(formatted_code, formatter)?, Self::Return { - return_token, + return_token: _, expr_opt, } => { - write!(formatted_code, "{}", return_token.span().as_str())?; + write!(formatted_code, "{}", ReturnToken::AS_STR)?; if let Some(expr) = &expr_opt { write!(formatted_code, " ")?; expr.format(formatted_code, formatter)?; @@ -229,11 +226,11 @@ impl Format for Expr { } Self::If(if_expr) => if_expr.format(formatted_code, formatter)?, Self::Match { - match_token, + match_token: _, value, branches, } => { - write!(formatted_code, "{} ", match_token.span().as_str())?; + write!(formatted_code, "{} ", MatchToken::AS_STR)?; value.format(formatted_code, formatter)?; write!(formatted_code, " ")?; if !branches.get().is_empty() { @@ -250,7 +247,7 @@ impl Format for Expr { } } Self::While { - while_token, + while_token: _, condition, block, } => { @@ -259,7 +256,7 @@ impl Format for Expr { .shape .with_code_line_from(LineStyle::Normal, ExprKind::Function), |formatter| -> Result<(), FormatterError> { - write!(formatted_code, "{} ", while_token.span().as_str())?; + write!(formatted_code, "{} ", WhileToken::AS_STR)?; condition.format(formatted_code, formatter)?; IfExpr::open_curly_brace(formatted_code, formatter)?; block.get().format(formatted_code, formatter)?; @@ -269,8 +266,8 @@ impl Format for Expr { )?; } Self::For { - for_token, - in_token, + for_token: _, + in_token: _, value_pattern, iterator, block, @@ -280,9 +277,9 @@ impl Format for Expr { .shape .with_code_line_from(LineStyle::Normal, ExprKind::Function), |formatter| -> Result<(), FormatterError> { - write!(formatted_code, "{} ", for_token.span().as_str())?; + write!(formatted_code, "{} ", ForToken::AS_STR)?; value_pattern.format(formatted_code, formatter)?; - write!(formatted_code, "{} ", in_token.span().as_str())?; + write!(formatted_code, "{} ", InToken::AS_STR)?; iterator.format(formatted_code, formatter)?; IfExpr::open_curly_brace(formatted_code, formatter)?; block.get().format(formatted_code, formatter)?; @@ -305,7 +302,7 @@ impl Format for Expr { Self::open_parenthesis(formatted_code, formatter)?; let (_, args_str) = write_function_call_arguments(args.get(), formatter)?; - write!(formatted_code, "{}", args_str,)?; + write!(formatted_code, "{}", args_str)?; Self::close_parenthesis(formatted_code, formatter)?; Ok(()) @@ -381,7 +378,7 @@ impl Format for Expr { } Self::FieldProjection { target, - dot_token, + dot_token: _, name, } => { let prev_length = formatted_code.len(); @@ -398,124 +395,124 @@ impl Format for Expr { formatted_code, "\n{}{}", formatter.indent_to_str()?, - dot_token.span().as_str() + DotToken::AS_STR, )?; name.format(formatted_code, formatter)?; formatter.unindent(); } else { - write!(formatted_code, "{}", dot_token.span().as_str())?; + write!(formatted_code, "{}", DotToken::AS_STR)?; name.format(formatted_code, formatter)?; } } Self::TupleFieldProjection { target, - dot_token, - field: _, - field_span, + dot_token: _, + field, + field_span: _, } => { target.format(formatted_code, formatter)?; - write!( - formatted_code, - "{}{}", - dot_token.span().as_str(), - field_span.as_str(), - )?; + write!(formatted_code, "{}{}", DotToken::AS_STR, field)?; } Self::Ref { - ampersand_token, + ampersand_token: _, mut_token, expr, } => { - // TODO-IG: Add unit tests. - write!(formatted_code, "{}", ampersand_token.span().as_str())?; - if let Some(mut_token) = mut_token { - write!(formatted_code, "{} ", mut_token.span().as_str())?; + write!(formatted_code, "{}", AmpersandToken::AS_STR)?; + if mut_token.is_some() { + write!(formatted_code, "{} ", MutToken::AS_STR)?; } expr.format(formatted_code, formatter)?; } - Self::Deref { star_token, expr } => { - write!(formatted_code, "{}", star_token.span().as_str())?; + Self::Deref { + star_token: _, + expr, + } => { + write!(formatted_code, "{}", StarToken::AS_STR)?; expr.format(formatted_code, formatter)?; } - Self::Not { bang_token, expr } => { - write!(formatted_code, "{}", bang_token.span().as_str())?; + Self::Not { + bang_token: _, + expr, + } => { + write!(formatted_code, "{}", BangToken::AS_STR)?; expr.format(formatted_code, formatter)?; } Self::Pow { lhs, - double_star_token, + double_star_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", double_star_token.span().as_str())?; + write!(formatted_code, " {} ", DoubleStarToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Mul { lhs, - star_token, + star_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", star_token.span().as_str())?; + write!(formatted_code, " {} ", StarToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Div { lhs, - forward_slash_token, + forward_slash_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", forward_slash_token.span().as_str())?; + write!(formatted_code, " {} ", ForwardSlashToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Modulo { lhs, - percent_token, + percent_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", percent_token.span().as_str())?; + write!(formatted_code, " {} ", PercentToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Add { lhs, - add_token, + add_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", add_token.span().as_str())?; + write!(formatted_code, " {} ", AddToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Sub { lhs, - sub_token, + sub_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", sub_token.span().as_str())?; + write!(formatted_code, " {} ", SubToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Shl { lhs, - shl_token, + shl_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", shl_token.span().as_str())?; + write!(formatted_code, " {} ", ShlToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Shr { lhs, - shr_token, + shr_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", shr_token.span().as_str())?; + write!(formatted_code, " {} ", ShrToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::BitAnd { lhs, - ampersand_token, + ampersand_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; @@ -525,18 +522,18 @@ impl Format for Expr { formatted_code, "\n{}{} ", formatter.indent_to_str()?, - ampersand_token.span().as_str() + AmpersandToken::AS_STR, )?; } _ => { - write!(formatted_code, " {} ", ampersand_token.span().as_str())?; + write!(formatted_code, " {} ", AmpersandToken::AS_STR)?; } } rhs.format(formatted_code, formatter)?; } Self::BitXor { lhs, - caret_token, + caret_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; @@ -546,18 +543,18 @@ impl Format for Expr { formatted_code, "\n{}{} ", formatter.indent_to_str()?, - caret_token.span().as_str() + CaretToken::AS_STR, )?; } _ => { - write!(formatted_code, " {} ", caret_token.span().as_str())?; + write!(formatted_code, " {} ", CaretToken::AS_STR)?; } } rhs.format(formatted_code, formatter)?; } Self::BitOr { lhs, - pipe_token, + pipe_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; @@ -567,81 +564,77 @@ impl Format for Expr { formatted_code, "\n{}{} ", formatter.indent_to_str()?, - pipe_token.span().as_str() + PipeToken::AS_STR, )?; } _ => { - write!(formatted_code, " {} ", pipe_token.span().as_str())?; + write!(formatted_code, " {} ", PipeToken::AS_STR)?; } } rhs.format(formatted_code, formatter)?; } Self::Equal { lhs, - double_eq_token, + double_eq_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", double_eq_token.span().as_str())?; + write!(formatted_code, " {} ", DoubleEqToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::NotEqual { lhs, - bang_eq_token, + bang_eq_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", bang_eq_token.span().as_str())?; + write!(formatted_code, " {} ", BangEqToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::LessThan { lhs, - less_than_token, + less_than_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", less_than_token.span().as_str())?; + write!(formatted_code, " {} ", LessThanToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::GreaterThan { lhs, - greater_than_token, + greater_than_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", greater_than_token.span().as_str())?; + write!(formatted_code, " {} ", GreaterThanToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::LessThanEq { lhs, - less_than_eq_token, + less_than_eq_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", less_than_eq_token.span().as_str())?; + write!(formatted_code, " {} ", LessThanEqToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::GreaterThanEq { lhs, - greater_than_eq_token, + greater_than_eq_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!( - formatted_code, - " {} ", - greater_than_eq_token.span().as_str() - )?; + write!(formatted_code, " {} ", GreaterThanEqToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::LogicalAnd { lhs, - double_ampersand_token, + double_ampersand_token: _, rhs, } => { two_parts_expr( lhs, - double_ampersand_token.span().as_str(), + DoubleAmpersandToken::AS_STR, rhs, formatted_code, formatter, @@ -649,16 +642,10 @@ impl Format for Expr { } Self::LogicalOr { lhs, - double_pipe_token, + double_pipe_token: _, rhs, } => { - two_parts_expr( - lhs, - double_pipe_token.span().as_str(), - rhs, - formatted_code, - formatter, - )?; + two_parts_expr(lhs, DoublePipeToken::AS_STR, rhs, formatted_code, formatter)?; } Self::Reassignment { assignable, @@ -669,11 +656,11 @@ impl Format for Expr { reassignment_op.format(formatted_code, formatter)?; expr.format(formatted_code, formatter)?; } - Self::Break { break_token } => { - write!(formatted_code, "{}", break_token.span().as_str())?; + Self::Break { break_token: _ } => { + write!(formatted_code, "{}", BreakToken::AS_STR)?; } - Self::Continue { continue_token } => { - write!(formatted_code, "{}", continue_token.span().as_str())?; + Self::Continue { continue_token: _ } => { + write!(formatted_code, "{}", ContinueToken::AS_STR)?; } } @@ -888,7 +875,7 @@ where fn format_method_call( target: &Expr, - dot_token: &DotToken, + _dot_token: &DotToken, path_seg: &PathExprSegment, contract_args_opt: &Option>>, args: &Parens>, @@ -906,7 +893,7 @@ fn format_method_call( write!(formatted_code, "\n{}", formatter.indent_to_str()?)?; } - write!(formatted_code, "{}", dot_token.span().as_str())?; + write!(formatted_code, "{}", DotToken::AS_STR)?; path_seg.format(formatted_code, formatter)?; if let Some(contract_args) = &contract_args_opt { @@ -927,7 +914,7 @@ fn format_method_call( Expr::open_parenthesis(formatted_code, formatter)?; let (args_inline, args_str) = write_function_call_arguments(args.get(), formatter)?; - write!(formatted_code, "{}", args_str,)?; + write!(formatted_code, "{}", args_str)?; Expr::close_parenthesis(formatted_code, formatter)?; if formatter.shape.code_line.expr_new_line { @@ -942,15 +929,15 @@ fn get_field_width( ) -> Result<(usize, usize), FormatterError> { let mut largest_field: usize = 0; let mut body_width: usize = 3; // this is taking into account the opening brace, the following space and the ending brace. - for (field, comma_token) in &fields.value_separator_pairs { + for (field, _comma_token) in &fields.value_separator_pairs { let mut field_length = field.field_name.as_str().chars().count(); - if let Some((colon_token, expr)) = &field.expr_opt { + if let Some((_colon_token, expr)) = &field.expr_opt { let mut buf = String::new(); - write!(buf, "{} ", colon_token.span().as_str())?; + write!(buf, "{} ", ColonToken::AS_STR)?; expr.format(&mut buf, formatter)?; field_length += buf.chars().count(); } - field_length += comma_token.span().as_str().chars().count(); + field_length += CommaToken::AS_STR.chars().count(); body_width += &field_length + 1; // accounting for the following space if field_length > largest_field { @@ -959,9 +946,9 @@ fn get_field_width( } if let Some(final_value) = &fields.final_value_opt { let mut field_length = final_value.field_name.as_str().chars().count(); - if let Some((colon_token, expr)) = &final_value.expr_opt { + if let Some((_colon_token, expr)) = &final_value.expr_opt { let mut buf = String::new(); - write!(buf, "{} ", colon_token.span().as_str())?; + write!(buf, "{} ", ColonToken::AS_STR)?; expr.format(&mut buf, formatter)?; field_length += buf.chars().count(); } diff --git a/swayfmt/src/utils/language/expr/struct_field.rs b/swayfmt/src/utils/language/expr/struct_field.rs index 0a51864cc6c..99764c34226 100644 --- a/swayfmt/src/utils/language/expr/struct_field.rs +++ b/swayfmt/src/utils/language/expr/struct_field.rs @@ -10,7 +10,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::ExprStructField; +use sway_ast::{ + keywords::{ColonToken, Token}, + ExprStructField, +}; use sway_types::{ast::Delimiter, Spanned}; impl Format for ExprStructField { @@ -19,8 +22,8 @@ impl Format for ExprStructField { formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, "{}", self.field_name.span().as_str())?; - if let Some((colon_token, expr)) = &self.expr_opt { + write!(formatted_code, "{}", self.field_name.as_str())?; + if let Some((_colon_token, expr)) = &self.expr_opt { formatter.with_shape( formatter .shape @@ -37,12 +40,7 @@ impl Format for ExprStructField { } else { expr_str }; - write!( - formatted_code, - "{} {}", - colon_token.span().as_str(), - expr_str - )?; + write!(formatted_code, "{} {}", ColonToken::AS_STR, expr_str)?; Ok(()) }, )?; diff --git a/swayfmt/src/utils/language/literal.rs b/swayfmt/src/utils/language/literal.rs index 3918f4de7f6..8fecedae9eb 100644 --- a/swayfmt/src/utils/language/literal.rs +++ b/swayfmt/src/utils/language/literal.rs @@ -3,7 +3,7 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::Literal; +use sway_ast::{literal::LitBoolType, LitIntType, Literal}; impl Format for Literal { fn format( @@ -12,16 +12,56 @@ impl Format for Literal { _formatter: &mut Formatter, ) -> Result<(), FormatterError> { match self { - // TODO: do more digging into `Literal` and see if there is more formatting to do. - Self::String(lit_string) => write!(formatted_code, "{}", lit_string.span.as_str())?, - Self::Char(lit_char) => write!(formatted_code, "{}", lit_char.span.as_str())?, + Self::String(lit_string) => write!(formatted_code, "\"{}\"", lit_string.parsed)?, + Self::Char(lit_char) => write!(formatted_code, "\'{}\'", lit_char.parsed)?, Self::Int(lit_int) => { - write!(formatted_code, "{}", lit_int.span.as_str())?; - if let Some((_, ty_span)) = &lit_int.ty_opt { - write!(formatted_code, "{}", ty_span.as_str())?; + // It is tricky to support formatting of `LitInt` for an arbitrary `LitInt` + // that is potentially not backed by source code, but constructed in-memory. + // + // E.g., a constructed `LitInt` representing 1000 can have only the numeric value + // (LitInt::parsed) specified, in which case we can simply output the value. + // If it has the type specified (LitInt::ty_opt), we can output the type next to the + // value, e.g., 1000u16. + // But a `LitInt` backed by code can have an arbitrary representation that includes + // underscores. E.g., 1_00_00__u16. In that case we need to preserve the original + // representation. + // + // The taken approach is the following. If the length of the `LitInt::span` is zero, + // we assume that it is not backed by source code and render the canonical representation, + // 1000u16 in the above example. Otherwise, we assume that it is backed by source code + // and use the actual spans to obtain the strings. + + if lit_int.span.is_empty() { + write!(formatted_code, "{}", lit_int.parsed)?; + if let Some((int_type, _)) = &lit_int.ty_opt { + let int_type = match int_type { + LitIntType::U8 => "u8", + LitIntType::U16 => "u16", + LitIntType::U32 => "u32", + LitIntType::U64 => "u64", + LitIntType::U256 => "u256", + LitIntType::I8 => "i8", + LitIntType::I16 => "i16", + LitIntType::I32 => "i32", + LitIntType::I64 => "i64", + }; + write!(formatted_code, "{}", int_type)?; + } + } else { + write!(formatted_code, "{}", lit_int.span.as_str())?; + if let Some((_, ty_span)) = &lit_int.ty_opt { + write!(formatted_code, "{}", ty_span.as_str())?; + } } } - Self::Bool(lit_bool) => write!(formatted_code, "{}", lit_bool.span.as_str())?, + Self::Bool(lit_bool) => write!( + formatted_code, + "{}", + match lit_bool.kind { + LitBoolType::True => "true", + LitBoolType::False => "false", + } + )?, } Ok(()) } diff --git a/swayfmt/src/utils/language/path.rs b/swayfmt/src/utils/language/path.rs index f8575f185b0..6d5a84ded1d 100644 --- a/swayfmt/src/utils/language/path.rs +++ b/swayfmt/src/utils/language/path.rs @@ -7,7 +7,8 @@ use crate::{ }; use std::{fmt::Write, vec}; use sway_ast::{ - keywords::Token, PathExpr, PathExprSegment, PathType, PathTypeSegment, QualifiedPathRoot, + keywords::{AsToken, Keyword, Token}, + DoubleColonToken, PathExpr, PathExprSegment, PathType, PathTypeSegment, QualifiedPathRoot, }; use sway_types::Spanned; @@ -17,7 +18,7 @@ impl Format for PathExpr { formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - if let Some((qualified_path_root, double_colon_token)) = &self.root_opt { + if let Some((qualified_path_root, _double_colon_token)) = &self.root_opt { if let Some(root) = &qualified_path_root { open_angle_bracket(formatted_code)?; root.clone() @@ -25,11 +26,11 @@ impl Format for PathExpr { .format(formatted_code, formatter)?; close_angle_bracket(formatted_code)?; } - write!(formatted_code, "{}", double_colon_token.ident().as_str())?; + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; } self.prefix.format(formatted_code, formatter)?; - for (double_colon_token, path_expr_segment) in self.suffix.iter() { - write!(formatted_code, "{}", double_colon_token.span().as_str())?; + for (_double_colon_token, path_expr_segment) in self.suffix.iter() { + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; path_expr_segment.format(formatted_code, formatter)?; } @@ -46,8 +47,8 @@ impl Format for PathExprSegment { // name self.name.format(formatted_code, formatter)?; // generics `::` - if let Some((double_colon_token, generic_args)) = &self.generics_opt { - write!(formatted_code, "{}", double_colon_token.span().as_str())?; + if let Some((_double_colon_token, generic_args)) = &self.generics_opt { + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; generic_args.format(formatted_code, formatter)?; } @@ -62,8 +63,8 @@ impl Format for QualifiedPathRoot { formatter: &mut Formatter, ) -> Result<(), FormatterError> { self.ty.format(formatted_code, formatter)?; - let (as_token, path_type) = &self.as_trait; - write!(formatted_code, " {} ", as_token.span().as_str())?; + let (_as_token, path_type) = &self.as_trait; + write!(formatted_code, " {} ", AsToken::AS_STR)?; path_type.format(formatted_code, formatter)?; Ok(()) @@ -76,7 +77,7 @@ impl Format for PathType { formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - if let Some((root_opt, double_colon_token)) = &self.root_opt { + if let Some((root_opt, _double_colon_token)) = &self.root_opt { if let Some(qualified_path_root) = &root_opt { open_angle_bracket(formatted_code)?; qualified_path_root @@ -85,11 +86,11 @@ impl Format for PathType { .format(formatted_code, formatter)?; close_angle_bracket(formatted_code)?; } - write!(formatted_code, "{}", double_colon_token.span().as_str())?; + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; } self.prefix.format(formatted_code, formatter)?; - for (double_colon_token, path_type_segment) in self.suffix.iter() { - write!(formatted_code, "{}", double_colon_token.span().as_str())?; + for (_double_colon_token, path_type_segment) in self.suffix.iter() { + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; path_type_segment.format(formatted_code, formatter)?; } @@ -104,11 +105,11 @@ impl Format for PathTypeSegment { formatter: &mut Formatter, ) -> Result<(), FormatterError> { // name - write!(formatted_code, "{}", self.name.span().as_str())?; + write!(formatted_code, "{}", self.name.as_str())?; // generics `::` if let Some((double_colon_opt, generic_args)) = &self.generics_opt { - if let Some(double_colon_token) = &double_colon_opt { - write!(formatted_code, "{}", double_colon_token.span().as_str())?; + if double_colon_opt.is_some() { + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; } generic_args.format(formatted_code, formatter)?; } diff --git a/swayfmt/src/utils/language/pattern.rs b/swayfmt/src/utils/language/pattern.rs index 5c95b2e0ba3..655db700939 100644 --- a/swayfmt/src/utils/language/pattern.rs +++ b/swayfmt/src/utils/language/pattern.rs @@ -10,6 +10,7 @@ use crate::{ }; use std::fmt::Write; use sway_ast::{ + keywords::{ColonToken, DoubleDotToken, Keyword, MutToken, RefToken, Token, UnderscoreToken}, Braces, CommaToken, ExprTupleDescriptor, PathExpr, Pattern, PatternStructField, Punctuated, }; use sway_types::{ast::Delimiter, Spanned}; @@ -30,19 +31,19 @@ impl Format for Pattern { formatted_code.push_str(" | "); rhs.format(formatted_code, formatter)?; } - Self::Wildcard { underscore_token } => { - formatted_code.push_str(underscore_token.span().as_str()) - } + Self::Wildcard { + underscore_token: _, + } => formatted_code.push_str(UnderscoreToken::AS_STR), Self::Var { reference, mutable, name, } => { - if let Some(ref_token) = reference { - write!(formatted_code, "{} ", ref_token.span().as_str())?; + if reference.is_some() { + write!(formatted_code, "{} ", RefToken::AS_STR)?; } - if let Some(mut_token) = mutable { - write!(formatted_code, "{} ", mut_token.span().as_str())?; + if mutable.is_some() { + write!(formatted_code, "{} ", MutToken::AS_STR)?; } name.format(formatted_code, formatter)?; } @@ -188,16 +189,16 @@ impl Format for PatternStructField { formatter: &mut Formatter, ) -> Result<(), FormatterError> { match self { - Self::Rest { token } => { - write!(formatted_code, "{}", token.span().as_str())?; + Self::Rest { token: _ } => { + write!(formatted_code, "{}", DoubleDotToken::AS_STR)?; } Self::Field { field_name, pattern_opt, } => { - write!(formatted_code, "{}", field_name.span().as_str())?; - if let Some((colon_token, pattern)) = pattern_opt { - write!(formatted_code, "{} ", colon_token.span().as_str())?; + write!(formatted_code, "{}", field_name.as_str())?; + if let Some((_colon_token, pattern)) = pattern_opt { + write!(formatted_code, "{} ", ColonToken::AS_STR)?; pattern.format(formatted_code, formatter)?; } } @@ -213,12 +214,12 @@ fn get_field_width( ) -> Result<(usize, usize), FormatterError> { let mut largest_field: usize = 0; let mut body_width: usize = 3; // this is taking into account the opening brace, the following space and the ending brace. - for (field, comma_token) in &fields.value_separator_pairs { + for (field, _comma_token) in &fields.value_separator_pairs { let mut field_str = FormattedCode::new(); field.format(&mut field_str, formatter)?; let mut field_length = field_str.chars().count(); - field_length += comma_token.span().as_str().chars().count(); + field_length += CommaToken::AS_STR.chars().count(); body_width += &field_length + 1; // accounting for the following space if field_length > largest_field { diff --git a/swayfmt/src/utils/language/punctuated.rs b/swayfmt/src/utils/language/punctuated.rs index a06a6c68e55..ff488a60864 100644 --- a/swayfmt/src/utils/language/punctuated.rs +++ b/swayfmt/src/utils/language/punctuated.rs @@ -8,8 +8,9 @@ use crate::{ }; use std::fmt::Write; use sway_ast::{ - keywords::CommaToken, punctuated::Punctuated, ConfigurableField, ItemStorage, StorageEntry, - StorageField, TypeField, + keywords::{ColonToken, CommaToken, EqToken, InToken, Keyword, Token}, + punctuated::Punctuated, + ConfigurableField, ItemStorage, PubToken, StorageEntry, StorageField, TypeField, }; use sway_types::{ast::PunctKind, Ident, Spanned}; @@ -27,7 +28,7 @@ where formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - if !self.value_separator_pairs.is_empty() || self.final_value_opt.is_some() { + if !self.is_empty() { match formatter.shape.code_line.line_style { LineStyle::Normal => { write!( @@ -55,7 +56,7 @@ where if !formatted_code.ends_with('\n') { writeln!(formatted_code)?; } - if !self.value_separator_pairs.is_empty() || self.final_value_opt.is_some() { + if !self.is_empty() { formatter.write_indent_into_buffer(formatted_code)?; } @@ -191,8 +192,8 @@ impl Format for Ident { _formatter: &mut Formatter, ) -> Result<(), FormatterError> { match self.is_raw_ident() { - true => write!(formatted_code, "{}{}", RAW_MODIFIER, self.span().as_str())?, - false => write!(formatted_code, "{}", self.span().as_str())?, + true => write!(formatted_code, "{}{}", RAW_MODIFIER, self.as_str())?, + false => write!(formatted_code, "{}", self.as_str())?, } Ok(()) @@ -206,14 +207,14 @@ impl Format for TypeField { formatter: &mut Formatter, ) -> Result<(), FormatterError> { // If there is a visibility token add it to the formatted_code with a ` ` after it. - if let Some(visibility) = &self.visibility { - write!(formatted_code, "{} ", visibility.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } write!( formatted_code, "{}{} ", - self.name.span().as_str(), - self.colon_token.span().as_str(), + self.name.as_str(), + ColonToken::AS_STR, )?; self.ty.format(formatted_code, formatter)?; @@ -233,11 +234,11 @@ impl Format for ConfigurableField { write!( formatted_code, "{}{} ", - self.name.span().as_str(), - self.colon_token.span().as_str(), + self.name.as_str(), + ColonToken::AS_STR, )?; self.ty.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", self.eq_token.span().as_str())?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; Ok(()) }, @@ -258,17 +259,17 @@ impl Format for StorageField { formatter.with_shape( formatter.shape.with_default_code_line(), |formatter| -> Result<(), FormatterError> { - write!(formatted_code, "{}", self.name.span().as_str())?; - if let Some(in_token) = &self.in_token { - write!(formatted_code, " {}", in_token.span().as_str())?; + write!(formatted_code, "{}", self.name.as_str())?; + if self.in_token.is_some() { + write!(formatted_code, " {} ", InToken::AS_STR)?; } if let Some(key_expr) = &self.key_expr { - write!(formatted_code, " {}", key_expr.span().as_str())?; + key_expr.format(formatted_code, formatter)?; } - write!(formatted_code, "{} ", self.colon_token.span().as_str())?; + write!(formatted_code, "{} ", ColonToken::AS_STR)?; self.ty.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", self.eq_token.span().as_str())?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; Ok(()) }, @@ -328,7 +329,7 @@ impl Format for CommaToken { formatted_code: &mut FormattedCode, _formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, "{}", self.span().as_str())?; + write!(formatted_code, "{}", CommaToken::AS_STR)?; Ok(()) } diff --git a/swayfmt/src/utils/language/statement.rs b/swayfmt/src/utils/language/statement.rs index ffbcd443f66..1359161bf2c 100644 --- a/swayfmt/src/utils/language/statement.rs +++ b/swayfmt/src/utils/language/statement.rs @@ -3,7 +3,10 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::{Expr, Parens, Punctuated, Statement, StatementLet}; +use sway_ast::{ + keywords::{ColonToken, EqToken, Keyword, LetToken, SemicolonToken, Token}, + Expr, Parens, Punctuated, Statement, StatementLet, +}; use sway_types::{Span, Spanned}; impl Format for Statement { @@ -20,7 +23,7 @@ impl Format for Statement { } /// Remove arguments from the expression if the expression is a method call if -/// the method is a simple two path call (foo.bar()). This needed because in +/// the method is a simple two path call (foo.bar()). This is needed because in /// method calls of two parts they are never broke into multiple lines. /// Arguments however can be broken into multiple lines, and that is handled /// by `write_function_call_arguments` @@ -117,11 +120,11 @@ fn format_statement( } else { expr.format(formatted_code, formatter)?; } - if let Some(semicolon) = semicolon_token_opt { + if semicolon_token_opt.is_some() { if formatter.shape.code_line.line_style == LineStyle::Inline { - write!(formatted_code, "{}", semicolon.span().as_str())?; + write!(formatted_code, "{}", SemicolonToken::AS_STR)?; } else { - writeln!(formatted_code, "{}", semicolon.span().as_str())?; + writeln!(formatted_code, "{}", SemicolonToken::AS_STR)?; } } } @@ -140,24 +143,24 @@ impl Format for StatementLet { formatter: &mut Formatter, ) -> Result<(), FormatterError> { // `let ` - write!(formatted_code, "{} ", self.let_token.span().as_str())?; + write!(formatted_code, "{} ", LetToken::AS_STR)?; // pattern self.pattern.format(formatted_code, formatter)?; // `: Ty` - if let Some(ty) = &self.ty_opt { - write!(formatted_code, "{} ", ty.0.span().as_str())?; - ty.1.format(formatted_code, formatter)?; + if let Some((_colon_token, ty)) = &self.ty_opt { + write!(formatted_code, "{} ", ColonToken::AS_STR)?; + ty.format(formatted_code, formatter)?; } // ` = ` - write!(formatted_code, " {} ", self.eq_token.span().as_str())?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; // expr self.expr.format(formatted_code, formatter)?; if formatter.shape.code_line.line_style == LineStyle::Inline { // `;` - write!(formatted_code, "{}", self.semicolon_token.span().as_str())?; + write!(formatted_code, "{}", SemicolonToken::AS_STR)?; } else { // `;\n` - writeln!(formatted_code, "{}", self.semicolon_token.span().as_str())?; + writeln!(formatted_code, "{}", SemicolonToken::AS_STR)?; } Ok(()) diff --git a/swayfmt/src/utils/language/ty.rs b/swayfmt/src/utils/language/ty.rs index a509cca1567..327ed8165cc 100644 --- a/swayfmt/src/utils/language/ty.rs +++ b/swayfmt/src/utils/language/ty.rs @@ -6,8 +6,12 @@ use std::fmt::Write; use sway_ast::{ brackets::SquareBrackets, expr::Expr, - keywords::{AmpersandToken, MutToken, PtrToken, SliceToken, StrToken, Token, UnderscoreToken}, + keywords::{ + AmpersandToken, BangToken, Keyword, MutToken, PtrToken, SemicolonToken, SliceToken, + StrToken, Token, UnderscoreToken, + }, ty::{Ty, TyArrayDescriptor, TyTupleDescriptor}, + CommaToken, }; use sway_types::{ast::Delimiter, Spanned}; @@ -24,39 +28,35 @@ impl Format for Ty { write!(formatted_code, "{}", Delimiter::Bracket.as_close_char())?; Ok(()) } - Self::Infer { underscore_token } => format_infer(formatted_code, underscore_token), + Self::Infer { + underscore_token: _, + } => format_infer(formatted_code), Self::Path(path_ty) => path_ty.format(formatted_code, formatter), Self::StringSlice(_) => { - write!(formatted_code, "str")?; + write!(formatted_code, "{}", StrToken::AS_STR)?; Ok(()) } - Self::StringArray { str_token, length } => { - format_str(formatted_code, str_token.clone(), length.clone()) - } + Self::StringArray { + str_token: _, + length, + } => format_str(formatted_code, formatter, length.clone()), Self::Tuple(tup_descriptor) => { write!(formatted_code, "{}", Delimiter::Parenthesis.as_open_char())?; tup_descriptor.get().format(formatted_code, formatter)?; write!(formatted_code, "{}", Delimiter::Parenthesis.as_close_char())?; Ok(()) } - Self::Ptr { ptr_token, ty } => { - format_ptr(formatted_code, ptr_token.clone(), ty.clone()) - } + Self::Ptr { ptr_token: _, ty } => format_ptr(formatted_code, formatter, ty.clone()), Self::Slice { slice_token, ty } => { - format_slice(formatted_code, slice_token.clone(), ty.clone()) + format_slice(formatted_code, formatter, slice_token, ty.clone()) } Self::Ref { - ampersand_token, + ampersand_token: _, mut_token, ty, - } => format_ref( - formatted_code, - ampersand_token.clone(), - mut_token.clone(), - ty.clone(), - ), - Self::Never { bang_token } => { - write!(formatted_code, "{}", bang_token.span().as_str(),)?; + } => format_ref(formatted_code, formatter, mut_token, ty), + Self::Never { bang_token: _ } => { + write!(formatted_code, "{}", BangToken::AS_STR)?; Ok(()) } } @@ -64,11 +64,9 @@ impl Format for Ty { } /// Simply inserts a `_` token to the `formatted_code`. -fn format_infer( - formatted_code: &mut FormattedCode, - underscore_token: &UnderscoreToken, -) -> Result<(), FormatterError> { - formatted_code.push_str(underscore_token.ident().as_str()); +fn format_infer(formatted_code: &mut FormattedCode) -> Result<(), FormatterError> { + formatted_code.push_str(UnderscoreToken::AS_STR); + Ok(()) } @@ -79,78 +77,73 @@ impl Format for TyArrayDescriptor { formatter: &mut Formatter, ) -> Result<(), FormatterError> { self.ty.format(formatted_code, formatter)?; - write!(formatted_code, "{} ", self.semicolon_token.span().as_str())?; + write!(formatted_code, "{} ", SemicolonToken::AS_STR)?; self.length.format(formatted_code, formatter)?; + Ok(()) } } fn format_str( formatted_code: &mut FormattedCode, - str_token: StrToken, + formatter: &mut Formatter, length: SquareBrackets>, ) -> Result<(), FormatterError> { - write!( - formatted_code, - "{}{}{}{}", - str_token.span().as_str(), - Delimiter::Bracket.as_open_char(), - length.into_inner().span().as_str(), - Delimiter::Bracket.as_close_char() - )?; + write!(formatted_code, "{}", StrToken::AS_STR)?; + write!(formatted_code, "{}", Delimiter::Bracket.as_open_char())?; + length.into_inner().format(formatted_code, formatter)?; + write!(formatted_code, "{}", Delimiter::Bracket.as_close_char())?; + Ok(()) } fn format_ptr( formatted_code: &mut FormattedCode, - ptr_token: PtrToken, + formatter: &mut Formatter, ty: SquareBrackets>, ) -> Result<(), FormatterError> { - write!( - formatted_code, - "{}[{}]", - ptr_token.span().as_str(), - ty.into_inner().span().as_str() - )?; + write!(formatted_code, "{}", PtrToken::AS_STR)?; + write!(formatted_code, "{}", Delimiter::Bracket.as_open_char())?; + ty.into_inner().format(formatted_code, formatter)?; + write!(formatted_code, "{}", Delimiter::Bracket.as_close_char())?; + Ok(()) } fn format_slice( formatted_code: &mut FormattedCode, - slice_token: Option, + formatter: &mut Formatter, + slice_token: &Option, ty: SquareBrackets>, ) -> Result<(), FormatterError> { - if let Some(slice_token) = slice_token { - write!( - formatted_code, - "{}[{}]", - slice_token.span().as_str(), - ty.into_inner().span().as_str() - )?; - } else { - write!(formatted_code, "[{}]", ty.into_inner().span().as_str())?; + if slice_token.is_some() { + write!(formatted_code, "{}", SliceToken::AS_STR)?; } + write!(formatted_code, "{}", Delimiter::Bracket.as_open_char())?; + ty.into_inner().format(formatted_code, formatter)?; + write!(formatted_code, "{}", Delimiter::Bracket.as_close_char())?; Ok(()) } fn format_ref( formatted_code: &mut FormattedCode, - ampersand_token: AmpersandToken, - mut_token: Option, - ty: Box, + formatter: &mut Formatter, + mut_token: &Option, + ty: &Ty, ) -> Result<(), FormatterError> { write!( formatted_code, - "{}{}{}", - ampersand_token.span().as_str(), - if let Some(mut_token) = mut_token { - format!("{} ", mut_token.span().as_str()) + "{}{}", + AmpersandToken::AS_STR, + if mut_token.is_some() { + format!("{} ", MutToken::AS_STR) } else { "".to_string() }, - ty.span().as_str() )?; + ty.format(formatted_code, formatter)?; + Ok(()) } @@ -162,7 +155,7 @@ impl Format for TyTupleDescriptor { ) -> Result<(), FormatterError> { if let TyTupleDescriptor::Cons { head, - comma_token, + comma_token: _, tail, } = self { @@ -170,7 +163,7 @@ impl Format for TyTupleDescriptor { formatter.shape.with_default_code_line(), |formatter| -> Result<(), FormatterError> { head.format(formatted_code, formatter)?; - write!(formatted_code, "{} ", comma_token.ident().as_str())?; + write!(formatted_code, "{} ", CommaToken::AS_STR)?; tail.format(formatted_code, formatter)?; Ok(()) diff --git a/swayfmt/src/utils/language/where_clause.rs b/swayfmt/src/utils/language/where_clause.rs index 6a365370572..805bac01b86 100644 --- a/swayfmt/src/utils/language/where_clause.rs +++ b/swayfmt/src/utils/language/where_clause.rs @@ -3,8 +3,11 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::{WhereBound, WhereClause}; -use sway_types::{ast::PunctKind, Spanned}; +use sway_ast::{ + keywords::{ColonToken, Keyword, Token, WhereToken}, + CommaToken, WhereBound, WhereClause, +}; +use sway_types::Spanned; impl Format for WhereClause { fn format( @@ -15,8 +18,8 @@ impl Format for WhereClause { writeln!( formatted_code, "{}{}", - &formatter.indent_to_str()?, - self.where_token.span().as_str(), + formatter.indent_to_str()?, + WhereToken::AS_STR, )?; formatter.indent(); // We should add a multiline field to `Shape` @@ -27,18 +30,19 @@ impl Format for WhereClause { // ``` // let value_pairs = self.bounds.value_separator_pairs.clone(); - for (bound, comma_token) in value_pairs.iter() { + for (bound, _comma_token) in value_pairs.iter() { // `WhereBound` bound.format(formatted_code, formatter)?; // `CommaToken` - writeln!(formatted_code, "{}", comma_token.span().as_str())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } if let Some(final_value) = &self.bounds.final_value_opt { final_value.format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", PunctKind::Comma.as_char())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } // reset indent formatter.unindent(); + Ok(()) } } @@ -52,11 +56,12 @@ impl Format for WhereBound { write!( formatted_code, "{}{}{} ", - &formatter.indent_to_str()?, // `Indent` - self.ty_name.span().as_str(), // `Ident` - self.colon_token.span().as_str(), // `ColonToken` + formatter.indent_to_str()?, + self.ty_name.as_str(), + ColonToken::AS_STR, )?; self.bounds.format(formatted_code, formatter)?; + Ok(()) } } diff --git a/swayfmt/src/utils/map/byte_span.rs b/swayfmt/src/utils/map/byte_span.rs index 36578739dcf..fec51afdc1c 100644 --- a/swayfmt/src/utils/map/byte_span.rs +++ b/swayfmt/src/utils/map/byte_span.rs @@ -49,8 +49,8 @@ impl ByteSpan { impl Ord for ByteSpan { fn cmp(&self, other: &Self) -> Ordering { - // If the starting position is the same encapsulatig span (i.e, wider one) should come - // first + // If the starting position is the same encapsulating span (i.e, wider one) should come + // first. match self.start.cmp(&other.start) { Ordering::Equal => other.end.cmp(&self.end), ord => ord, diff --git a/swayfmt/src/utils/map/newline.rs b/swayfmt/src/utils/map/newline.rs index 769b05e7ad3..9600248beee 100644 --- a/swayfmt/src/utils/map/newline.rs +++ b/swayfmt/src/utils/map/newline.rs @@ -1,8 +1,7 @@ use anyhow::Result; use ropey::{str_utils::byte_to_char_idx, Rope}; -use std::{collections::BTreeMap, fmt::Display, path::PathBuf, sync::Arc}; +use std::{collections::BTreeMap, fmt::Display, sync::Arc}; use sway_ast::Module; -use sway_types::SourceEngine; use crate::{ constants::NEW_LINE, @@ -106,11 +105,9 @@ fn newline_map_from_src(unformatted_input: &str) -> Result, unformatted_module: &Module, formatted_input: Arc, - path: Option>, formatted_code: &mut FormattedCode, formatter: &Formatter, ) -> Result<(), FormatterError> { @@ -123,7 +120,7 @@ pub fn handle_newlines( // formatting the code a second time will still produce the same result. let newline_map = newline_map_from_src(&unformatted_input)?; // After the formatting existing items should be the same (type of the item) but their spans will be changed since we applied formatting to them. - let formatted_module = parse_file(source_engine, formatted_input, path)?.value; + let formatted_module = parse_file(formatted_input)?.value; // Actually find & insert the newline sequences add_newlines( newline_map, diff --git a/swayfmt/tests/mod.rs b/swayfmt/tests/mod.rs index 890995ef338..c3369d150c3 100644 --- a/swayfmt/tests/mod.rs +++ b/swayfmt/tests/mod.rs @@ -6,11 +6,11 @@ use test_macros::assert_eq_pretty; /// Takes a configured formatter as input and formats a given input and checks the actual output against an /// expected output. There are two format passes to ensure that the received output does not change on a second pass. fn check_with_formatter(unformatted: &str, expected: &str, formatter: &mut Formatter) { - let first_formatted = Formatter::format(formatter, Arc::from(unformatted), None).unwrap(); + let first_formatted = Formatter::format(formatter, Arc::from(unformatted)).unwrap(); assert_eq_pretty!(first_formatted, expected); let second_formatted = - Formatter::format(formatter, Arc::from(first_formatted.clone()), None).unwrap(); + Formatter::format(formatter, Arc::from(first_formatted.clone())).unwrap(); assert_eq_pretty!(second_formatted, first_formatted); } @@ -74,7 +74,33 @@ fn struct_alignment() { contract; pub struct Foo { barbazfoo: u64, - baz : bool, + baz : bool, + } + "#}, + indoc! {r#" + contract; + pub struct Foo { + barbazfoo : u64, + baz : bool, + } + "#}, + &mut formatter, + ); +} + +#[test] +#[ignore = "Bug in `swayfmt`. Activate this test once https://github.com/FuelLabs/sway/issues/6805 is fixed."] +fn struct_alignment_without_trailing_comma() { + // The last struct field does not have trailing comma. + let mut formatter = Formatter::default(); + formatter.config.structures.field_alignment = FieldAlignment::AlignFields(40); + + check_with_formatter( + indoc! {r#" + contract; + pub struct Foo { + barbazfoo: u64, + baz : bool } "#}, indoc! {r#" @@ -98,7 +124,51 @@ fn struct_alignment_with_public_fields() { contract; pub struct Foo { barbazfoo: u64, - pub baz : bool, + pub baz : bool, + } + "#}, + indoc! {r#" + contract; + pub struct Foo { + barbazfoo : u64, + pub baz : bool, + } + "#}, + &mut formatter, + ); + + check_with_formatter( + indoc! {r#" + contract; + pub struct Foo { + pub barbazfoo: u64, + baz : bool, + } + "#}, + indoc! {r#" + contract; + pub struct Foo { + pub barbazfoo : u64, + baz : bool, + } + "#}, + &mut formatter, + ); +} + +#[test] +#[ignore = "Bug in `swayfmt`. Activate this test once https://github.com/FuelLabs/sway/issues/6805 is fixed."] +fn struct_alignment_with_public_fields_without_trailing_comma() { + // The last struct field does not have trailing comma. + let mut formatter = Formatter::default(); + formatter.config.structures.field_alignment = FieldAlignment::AlignFields(40); + + check_with_formatter( + indoc! {r#" + contract; + pub struct Foo { + barbazfoo: u64, + pub baz : bool } "#}, indoc! {r#" @@ -116,7 +186,7 @@ fn struct_alignment_with_public_fields() { contract; pub struct Foo { pub barbazfoo: u64, - baz : bool, + baz : bool } "#}, indoc! {r#" @@ -157,7 +227,34 @@ fn struct_public_fields() { } #[test] -fn struct_ending_comma() { +fn struct_public_fields_without_trailing_comma() { + // The last struct field does not have trailing comma. + let mut formatter = Formatter::default(); + formatter.config.structures.field_alignment = FieldAlignment::Off; + + check_with_formatter( + indoc! {r#" + contract; + pub struct Foo { + pub barbaz: T, + foo: u64, + pub baz : bool + } + "#}, + indoc! {r#" + contract; + pub struct Foo { + pub barbaz: T, + foo: u64, + pub baz: bool, + } + "#}, + &mut formatter, + ); +} + +#[test] +fn struct_add_ending_comma() { check( indoc! {r#" contract; @@ -183,10 +280,10 @@ fn enum_without_variant_alignment() { contract; enum Color { - Blue: (), Green: (), - Red: (), - Silver: (), - Grey: () } + Blue: (), Green: (), + Red: (), + Silver: () , + Grey: () , } "#}, indoc! {r#" contract; @@ -204,7 +301,6 @@ fn enum_without_variant_alignment() { #[test] fn enum_with_variant_alignment() { - // Creating a config with enum_variant_align_threshold that exceeds longest variant length let mut formatter = Formatter::default(); formatter.config.structures.field_alignment = FieldAlignment::AlignFields(20); check_with_formatter( @@ -212,10 +308,68 @@ fn enum_with_variant_alignment() { contract; enum Color { - Blue: (), Green: (), - Red: (), + Blue: (), Green: (), + Red: (), + Silver: () , + Grey: () , } + "#}, + indoc! {r#" + contract; + + enum Color { + Blue : (), + Green : (), + Red : (), + Silver : (), + Grey : (), + } + "#}, + &mut formatter, + ); +} + +#[test] +fn enum_without_variant_alignment_without_trailing_comma() { + // The last enum variant does not have trailing comma. + check( + indoc! {r#" + contract; + + enum Color { + Blue: (), Green : (), + Red : (), + Silver: () , + Grey: () } + "#}, + indoc! {r#" + contract; + + enum Color { + Blue: (), + Green: (), + Red: (), Silver: (), - Grey: (), } + Grey: (), + } + "#}, + ); +} + +#[test] +#[ignore = "Bug in `swayfmt`. Activate this test once https://github.com/FuelLabs/sway/issues/6805 is fixed."] +fn enum_with_variant_alignment_without_trailing_comma() { + // The last enum variant does not have trailing comma. + let mut formatter = Formatter::default(); + formatter.config.structures.field_alignment = FieldAlignment::AlignFields(20); + check_with_formatter( + indoc! {r#" + contract; + + enum Color { + Blue: (), Green : (), + Red : (), + Silver: () , + Grey: () } "#}, indoc! {r#" contract; @@ -232,6 +386,119 @@ fn enum_with_variant_alignment() { ); } +#[test] +fn configurable_without_alignment() { + check( + indoc! {r#" + contract; + + configurable { + Blue: u64 = 0, Green: u64 = 0, + Red: u64=0, + Silver: u64= 0, + Grey: u64 =0, } + "#}, + indoc! {r#" + contract; + + configurable { + Blue: u64 = 0, + Green: u64 = 0, + Red: u64 = 0, + Silver: u64 = 0, + Grey: u64 = 0, + } + "#}, + ); +} + +#[test] +fn configurable_with_alignment() { + let mut formatter = Formatter::default(); + formatter.config.structures.field_alignment = FieldAlignment::AlignFields(20); + check_with_formatter( + indoc! {r#" + contract; + + configurable { + Blue: u64 = 0, Green: u64 = 0, + Red: u64=0, + Silver: u64= 0, + Grey: u64 =0, } + "#}, + indoc! {r#" + contract; + + configurable { + Blue : u64 = 0, + Green : u64 = 0, + Red : u64 = 0, + Silver : u64 = 0, + Grey : u64 = 0, + } + "#}, + &mut formatter, + ); +} + +#[test] +fn configurable_without_alignment_without_trailing_comma() { + // The last configurable does not have trailing comma. + check( + indoc! {r#" + contract; + + configurable { + Blue: u64 = 0, Green: u64 = 0, + Red: u64=0, + Silver: u64= 0, + Grey: u64 =0 } + "#}, + indoc! {r#" + contract; + + configurable { + Blue: u64 = 0, + Green: u64 = 0, + Red: u64 = 0, + Silver: u64 = 0, + Grey: u64 = 0, + } + "#}, + ); +} + +#[test] +#[ignore = "Bug in `swayfmt`. Activate this test once https://github.com/FuelLabs/sway/issues/6805 is fixed."] +fn configurable_with_alignment_without_trailing_comma() { + // The last configurable does not have trailing comma. + let mut formatter = Formatter::default(); + formatter.config.structures.field_alignment = FieldAlignment::AlignFields(20); + check_with_formatter( + indoc! {r#" + contract; + + configurable { + Blue: u64 = 0, Green: u64 = 0, + Red: u64=0, + Silver: u64= 0, + Grey: u64 =0 } + "#}, + indoc! {r#" + contract; + + configurable { + Blue : u64 = 0, + Green : u64 = 0, + Red : u64 = 0, + Silver : u64 = 0, + Grey : u64 = 0, + } + "#}, + &mut formatter, + ); +} + #[test] fn item_abi_with_generics_and_attributes() { check( @@ -3155,3 +3422,30 @@ fn retain_in_keyword() { "#}, ); } + +#[test] +fn tuple_field_access() { + check( + indoc! {r#" + contract; + + fn fun() { + let t = (1, 1); + let a = t . 0; + let b = t + . + 1 + ; + } + "#}, + indoc! {r#" + contract; + + fn fun() { + let t = (1, 1); + let a = t.0; + let b = t.1; + } + "#}, + ); +} From 40b3968b659fd9b48eaef84a17aea94d1fe1152b Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 8 Jan 2025 15:17:57 +0700 Subject: [PATCH 46/52] Add modulo inline tests (#6817) ## Description Add inline test for modulo operator for primitive types u8 u16 u32 u64 and u256 Closes #6776 ## 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). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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). - [ ] I have requested a review from the relevant team or maintainers. --- .../math_inline_tests/src/main.sw | 2 + .../math_inline_tests/src/modulo.sw | 147 ++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 test/src/in_language_tests/test_programs/math_inline_tests/src/modulo.sw diff --git a/test/src/in_language_tests/test_programs/math_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/math_inline_tests/src/main.sw index c2641d71272..7a320860c83 100644 --- a/test/src/in_language_tests/test_programs/math_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/math_inline_tests/src/main.sw @@ -1,5 +1,7 @@ library; +mod modulo; + use std::{flags::{disable_panic_on_overflow, disable_panic_on_unsafe_math}, registers::flags}; #[test] diff --git a/test/src/in_language_tests/test_programs/math_inline_tests/src/modulo.sw b/test/src/in_language_tests/test_programs/math_inline_tests/src/modulo.sw new file mode 100644 index 00000000000..43187e0b69d --- /dev/null +++ b/test/src/in_language_tests/test_programs/math_inline_tests/src/modulo.sw @@ -0,0 +1,147 @@ +library; + +use std::flags::disable_panic_on_unsafe_math; + +// u8 +#[test] +pub fn u8_modulo() { + let u8_max = u8::max(); + + assert(0u8 % 1u8 == 0u8); + assert(0u8 % 2u8 == 0u8); + assert(1u8 % 1u8 == 0u8); + assert(1u8 % 2u8 == 1u8); + + assert(u8_max % 1u8 == 0u8); + assert(u8_max % 2u8 == 1u8); + assert(u8_max % u8_max == 0u8); + assert(254u8 % u8_max == 254u8); +} + +#[test(should_revert)] +pub fn u8_modulo_panic_on_undefined_math() { + log(1u8 % 0u8); +} + +#[test] +pub fn u8_modulo_unsafe_math() { + disable_panic_on_unsafe_math(); + assert(0u8 % 0u8 == 0u8); + assert(1u8 % 0u8 == 0u8); + assert(u8::max() % 0u8 == 0u8); +} + +// u16 +#[test] +pub fn u16_modulo() { + let u16_max = u16::max(); + + assert(0u16 % 1u16 == 0u16); + assert(0u16 % 2u16 == 0u16); + assert(1u16 % 1u16 == 0u16); + assert(1u16 % 2u16 == 1u16); + + assert(u16_max % 1u16 == 0u16); + assert(u16_max % 2u16 == 1u16); + assert(u16_max % u16_max == 0u16); + assert((u16_max - 1u16) % u16_max == (u16_max - 1u16)); +} + +#[test(should_revert)] +pub fn u16_modulo_panic_on_undefined_math() { + log(1u16 % 0u16); +} + +#[test] +pub fn u16_modulo_unsafe_math() { + disable_panic_on_unsafe_math(); + assert(0u16 % 0u16 == 0u16); + assert(1u16 % 0u16 == 0u16); + assert(u16::max() % 0u16 == 0u16); +} + +// u32 +#[test] +pub fn u32_modulo() { + let u32_max = u32::max(); + + assert(0u32 % 1u32 == 0u32); + assert(0u32 % 2u32 == 0u32); + assert(1u32 % 1u32 == 0u32); + assert(1u32 % 2u32 == 1u32); + + assert(u32_max % 1u32 == 0u32); + assert(u32_max % 2u32 == 1u32); + assert(u32_max % u32_max == 0u32); + assert((u32_max - 1u32) % u32_max == (u32_max - 1u32)); +} + +#[test(should_revert)] +pub fn u32_modulo_panic_on_undefined_math() { + log(1u32 % 0u32); +} + +#[test] +pub fn u32_modulo_unsafe_math() { + disable_panic_on_unsafe_math(); + assert(0u32 % 0u32 == 0u32); + assert(1u32 % 0u32 == 0u32); + assert(u32::max() % 0u32 == 0u32); +} + +// u64 +#[test] +pub fn u64_modulo() { + let u64_max = u64::max(); + + assert(0u64 % 1u64 == 0u64); + assert(0u64 % 2u64 == 0u64); + assert(1u64 % 1u64 == 0u64); + assert(1u64 % 2u64 == 1u64); + + assert(u64_max % 1u64 == 0u64); + assert(u64_max % 2u64 == 1u64); + assert(u64_max % u64_max == 0u64); + assert((u64_max - 1u64) % u64_max == (u64_max - 1u64)); +} + +#[test(should_revert)] +pub fn u64_modulo_panic_on_undefined_math() { + log(1u64 % 0u64); +} + +#[test] +pub fn u64_modulo_unsafe_math() { + disable_panic_on_unsafe_math(); + assert(0u64 % 0u64 == 0u64); + assert(1u64 % 0u64 == 0u64); + assert(u64::max() % 0u64 == 0u64); +} + +// u256 +#[test] +pub fn u256_modulo() { + let u256_max = u256::max(); + + assert(0x0u256 % 0x1u256 == 0x0u256); + assert(0x1u256 % 0x1u256 == 0x0u256); + assert(0x1u256 % 0x2u256 == 0x1u256); + + assert(u256_max % 0x1u256 == 0x0u256); + assert(u256_max % 0x2u256 == 0x1u256); + assert(u256_max % u256_max == 0x0u256); + assert((u256_max - 0x1u256) % u256_max == (u256_max - 0x1u256)); +} + +#[test(should_revert)] +pub fn u256_modulo_panic_on_undefined_math() { + log(0x1u256 % 0x0u256); +} + +#[test] +pub fn u256_modulo_unsafe_math() { + disable_panic_on_unsafe_math(); + assert(0x0u256 % 0x0u256 == 0x0u256); + assert(0x1u256 % 0x0u256 == 0x0u256); + assert(u256::max() % 0x0u256 == 0x0u256); +} From 96ee0b86a7f25115902787986185c03acd3a2afb Mon Sep 17 00:00:00 2001 From: AMIR <31338382+amiremohamadi@users.noreply.github.com> Date: Thu, 9 Jan 2025 01:47:37 +0330 Subject: [PATCH 47/52] fix: formatting for loop (#6807) ## Description Fix #6804 ## Checklist - [x] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] 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). - [ ] I have requested a review from the relevant team or maintainers. Co-authored-by: IGI-111 --- swayfmt/src/utils/language/expr/mod.rs | 2 +- swayfmt/src/utils/language/expr/tests.rs | 10 ++++++ swayfmt/tests/mod.rs | 40 ++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/swayfmt/src/utils/language/expr/mod.rs b/swayfmt/src/utils/language/expr/mod.rs index 9fd5005a24a..95a53c01c30 100644 --- a/swayfmt/src/utils/language/expr/mod.rs +++ b/swayfmt/src/utils/language/expr/mod.rs @@ -279,7 +279,7 @@ impl Format for Expr { |formatter| -> Result<(), FormatterError> { write!(formatted_code, "{} ", ForToken::AS_STR)?; value_pattern.format(formatted_code, formatter)?; - write!(formatted_code, "{} ", InToken::AS_STR)?; + write!(formatted_code, " {} ", InToken::AS_STR)?; iterator.format(formatted_code, formatter)?; IfExpr::open_curly_brace(formatted_code, formatter)?; block.get().format(formatted_code, formatter)?; diff --git a/swayfmt/src/utils/language/expr/tests.rs b/swayfmt/src/utils/language/expr/tests.rs index ef84d8b0c61..6472940e346 100644 --- a/swayfmt/src/utils/language/expr/tests.rs +++ b/swayfmt/src/utils/language/expr/tests.rs @@ -264,3 +264,13 @@ intermediate_whitespace "{ let i = 42; }"); + +fmt_test_expr!(basic_for_loop +"for iter in [0, 1, 7, 8, 15] { + let i = 42; +}", +intermediate_whitespace +"for iter in [0, 1, 7, 8, 15]{ +let i = 42; +}" +); diff --git a/swayfmt/tests/mod.rs b/swayfmt/tests/mod.rs index c3369d150c3..75f46632b23 100644 --- a/swayfmt/tests/mod.rs +++ b/swayfmt/tests/mod.rs @@ -3449,3 +3449,43 @@ fn tuple_field_access() { "#}, ); } + +#[test] +fn contract_for_loop() { + check( + indoc! {r#" + contract; + + abi MyContract { + fn test_function() -> bool; + } + + impl MyContract for Contract { + fn test_function() -> bool { + let mut my_vec: Vec = Vec::new(); + for iter in my_vec.iter() { + + } + + true + } + } + "#}, + indoc! {r#" + contract; + + abi MyContract { + fn test_function() -> bool; + } + + impl MyContract for Contract { + fn test_function() -> bool { + let mut my_vec: Vec = Vec::new(); + for iter in my_vec.iter() { } + + true + } + } + "#}, + ); +} From bb855e8acd0cf29906c86db80e1f84f5d758d53a Mon Sep 17 00:00:00 2001 From: AMIR <31338382+amiremohamadi@users.noreply.github.com> Date: Thu, 9 Jan 2025 04:15:47 +0330 Subject: [PATCH 48/52] Rename forc doc `--manifest-path` to `--path` (#6797) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Closes https://github.com/FuelLabs/sway/issues/5789 ## Checklist - [x] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] 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). - [ ] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: Cameron Carstens Co-authored-by: Joshua Batty Co-authored-by: Kaya Gökalp --- .github/workflows/ci.yml | 2 +- .github/workflows/gh-pages.yml | 2 +- forc-plugins/forc-doc/README.md | 6 +++--- forc-plugins/forc-doc/src/cli.rs | 11 ++++++----- forc-plugins/forc-doc/src/lib.rs | 2 +- .../forc-doc/src/tests/expects/impl_trait/mod.rs | 4 ++-- forc-plugins/forc-doc/tests/lib.rs | 4 ++-- forc-plugins/forc-fmt/src/main.rs | 4 +++- 8 files changed, 19 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7438d9fee0f..5f1199a3d8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -287,7 +287,7 @@ jobs: run: | cargo install --locked --debug --path ./forc-plugins/forc-doc - name: Build sway-lib-std docs - run: forc doc --manifest-path ./sway-lib-std + run: forc doc --path ./sway-lib-std build-forc-test-project: runs-on: buildjet-4vcpu-ubuntu-2204 diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index fa2ac16b866..7e3201451c5 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -50,7 +50,7 @@ jobs: run: mdbook build docs/reference - name: Build Sway std library - run: forc doc --manifest-path ./sway-lib-std + run: forc doc --path ./sway-lib-std - name: Deploy master std uses: peaceiris/actions-gh-pages@v3 diff --git a/forc-plugins/forc-doc/README.md b/forc-plugins/forc-doc/README.md index 90531e248cd..c82602aa225 100644 --- a/forc-plugins/forc-doc/README.md +++ b/forc-plugins/forc-doc/README.md @@ -78,7 +78,7 @@ $ cargo install --path forc-plugins/forc-doc Great! Let's check everything is working as intended. Try running `forc doc` on one of the test directories: ```sh -$ forc doc --manifest-path src/tests/data/impl_traits --open +$ forc doc --path src/tests/data/impl_traits --open ``` If it succeeded, you should be seeing the test docs in your browser. @@ -274,10 +274,10 @@ Now we can call this function anytime we need to generate a searchbar for our we Once you've made some changes, run the `forc doc` binary, passing it a path containing a `Forc.toml`: ```sh -cargo run -- --manifest-path path/to/manifest --open +cargo run -- --path path/to/manifest --open ``` -> **Tip:** VS Code user? Try the Live Server plugin to make viewing changes even easier. It will reload a webpage on updates, so you only need to rebuild the docs (`cargo run -- --manifest-path path/to/manifest`). Just right click the index file of docs produced by `forc doc` which can be found in the `out/doc` directory, and choose the option "open with Live Server". Voila! +> **Tip:** VS Code user? Try the Live Server plugin to make viewing changes even easier. It will reload a webpage on updates, so you only need to rebuild the docs (`cargo run -- --path path/to/manifest`). Just right click the index file of docs produced by `forc doc` which can be found in the `out/doc` directory, and choose the option "open with Live Server". Voila! [forc-reference]: https://fuellabs.github.io/sway/master/book/forc/index.html "forc reference" [manifest-reference]: https://fuellabs.github.io/sway/master/book/forc/manifest_reference.html "manifest reference" diff --git a/forc-plugins/forc-doc/src/cli.rs b/forc-plugins/forc-doc/src/cli.rs index 309bfb880d6..dff10298122 100644 --- a/forc-plugins/forc-doc/src/cli.rs +++ b/forc-plugins/forc-doc/src/cli.rs @@ -6,7 +6,7 @@ forc_util::cli_examples! { crate::cli::Command { [ Build the docs for a project in the current path => "forc doc"] [ Build the docs for a project in the current path and open it in the browser => "forc doc --open" ] - [ Build the docs for a project located in another path => "forc doc --manifest-path {path}" ] + [ Build the docs for a project located in another path => "forc doc --path {path}" ] [ Build the docs for the current project exporting private types => "forc doc --document-private-items" ] [ Build the docs offline without downloading any dependency from the network => "forc doc --offline" ] } @@ -20,10 +20,11 @@ forc_util::cli_examples! { version )] pub struct Command { - /// Path to the Forc.toml file. By default, forc-doc searches for the Forc.toml - /// file in the current directory or any parent directory. - #[clap(long)] - pub manifest_path: Option, + /// Path to the project. + /// + /// If not specified, current working directory will be used. + #[clap(short, long, alias = "manifest-path")] + pub path: Option, /// Include non-public items in the documentation. #[clap(long)] pub document_private_items: bool, diff --git a/forc-plugins/forc-doc/src/lib.rs b/forc-plugins/forc-doc/src/lib.rs index 4043cfde1f2..ffaf5a5dbe8 100644 --- a/forc-plugins/forc-doc/src/lib.rs +++ b/forc-plugins/forc-doc/src/lib.rs @@ -57,7 +57,7 @@ pub fn compile_html( get_doc_dir: &dyn Fn(&Command) -> String, ) -> Result<(PathBuf, Box)> { // get manifest directory - let dir = if let Some(ref path) = build_instructions.manifest_path { + let dir = if let Some(ref path) = build_instructions.path { PathBuf::from(path) } else { std::env::current_dir()? diff --git a/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs b/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs index 602b66f49d7..555954ce244 100644 --- a/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs +++ b/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs @@ -21,7 +21,7 @@ fn test_impl_traits_default() { let doc_dir_name: &str = "impl_traits_default"; let project_name = "impl_traits"; let command = Command { - manifest_path: Some(format!("{}/{}", DATA_DIR, project_name)), + path: Some(format!("{}/{}", DATA_DIR, project_name)), doc_path: Some(doc_dir_name.into()), ..Default::default() }; @@ -171,7 +171,7 @@ fn test_impl_traits_no_deps() { let doc_dir_name: &str = "impl_traits_no_deps"; let project_name: &str = "impl_traits_clone"; let command = Command { - manifest_path: Some(format!("{}/{}", DATA_DIR, project_name)), + path: Some(format!("{}/{}", DATA_DIR, project_name)), doc_path: Some(doc_dir_name.into()), no_deps: true, ..Default::default() diff --git a/forc-plugins/forc-doc/tests/lib.rs b/forc-plugins/forc-doc/tests/lib.rs index 9624b656a4f..996e095645b 100644 --- a/forc-plugins/forc-doc/tests/lib.rs +++ b/forc-plugins/forc-doc/tests/lib.rs @@ -5,10 +5,10 @@ use std::path::Path; fn builds_lib_std_docs() { let path = Path::new("./../../sway-lib-std"); let build_instructions = Command { - manifest_path: Some(path.to_str().unwrap().to_string()), + path: Some(path.to_str().unwrap().to_string()), ..Default::default() }; - println!("Building docs for {:?}", build_instructions.manifest_path); + println!("Building docs for {:?}", build_instructions.path); let res = compile_html(&build_instructions, &get_doc_dir); assert!(res.is_ok()); } diff --git a/forc-plugins/forc-fmt/src/main.rs b/forc-plugins/forc-fmt/src/main.rs index fffefbbd840..331c3e51373 100644 --- a/forc-plugins/forc-fmt/src/main.rs +++ b/forc-plugins/forc-fmt/src/main.rs @@ -45,7 +45,9 @@ pub struct App { /// - Exits with `1` and prints a diff if formatting is required. #[clap(short, long)] pub check: bool, - /// Path to the project, if not specified, current working directory will be used. + /// Path to the project. + /// + /// If not specified, current working directory will be used. #[clap(short, long)] pub path: Option, #[clap(short, long)] From e1c3fa38ca64c27062ee8a1818d66279841993f0 Mon Sep 17 00:00:00 2001 From: Vaivaswatha N Date: Thu, 9 Jan 2025 15:10:47 +0530 Subject: [PATCH 49/52] fix bug in `memcopyopt` related to killing defined symbols (#6820) --- sway-ir/src/optimize/memcpyopt.rs | 11 ++++++-- .../Forc.lock | 13 +++++++++ .../Forc.toml | 8 ++++++ .../src/lib.sw | 19 +++++++++++++ .../src/main.sw | 27 +++++++++++++++++++ .../test.toml | 3 +++ 6 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/lib.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/test.toml diff --git a/sway-ir/src/optimize/memcpyopt.rs b/sway-ir/src/optimize/memcpyopt.rs index 265db81695b..fbce2059c59 100644 --- a/sway-ir/src/optimize/memcpyopt.rs +++ b/sway-ir/src/optimize/memcpyopt.rs @@ -301,7 +301,6 @@ fn local_copy_prop( available_copies.remove(copy); } } - copies.retain(|copy| available_copies.contains(copy)); } if let Some(copies) = dest_to_copies.get_mut(&sym) { for copy in &*copies { @@ -333,9 +332,17 @@ fn local_copy_prop( available_copies.remove(copy); } } - copies.retain(|copy| available_copies.contains(copy)); } } + // Update src_to_copies and dest_to_copies to remove every copy not in available_copies. + src_to_copies.retain(|_, copies| { + copies.retain(|copy| available_copies.contains(copy)); + !copies.is_empty() + }); + dest_to_copies.retain(|_, copies| { + copies.retain(|copy| available_copies.contains(copy)); + !copies.is_empty() + }); } ReferredSymbols::Incomplete(_) => { // The only safe thing we can do is to clear all information. diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.lock new file mode 100644 index 00000000000..e52d486e352 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-1F6D5E67DD060824" + +[[package]] +name = "mutability_of_references_memcpy_bug" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-1F6D5E67DD060824" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.toml new file mode 100644 index 00000000000..66e2ad87de3 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "mutability_of_references_memcpy_bug" + +[dependencies] +std = { path = "../../../../../reduced_std_libs/sway-lib-std-assert" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/lib.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/lib.sw new file mode 100644 index 00000000000..88c1bfa547f --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/lib.sw @@ -0,0 +1,19 @@ +library; + +#[inline(never)] +pub fn unit(b: u256) -> u256 { + b +} + +#[inline(never)] +pub fn weird(_b: u256) { + let mut b = _b; // b = _b = 2 + + log(b); + + let mut b_tmp = b; // b_tmp = b = 2 + + b = 0x03u256; // b = a = 1 + + assert(unit(b_tmp) == 0x02u256); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/main.sw new file mode 100644 index 00000000000..91454432859 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/main.sw @@ -0,0 +1,27 @@ +contract; + +pub mod lib; + +use ::lib::weird; + +abi MyContract { + fn test_function(b: u256) -> u256; +} + +impl MyContract for Contract { + + fn test_function(_b: u256) -> u256 { + weird(_b); + 0x00u256 + } +} + + + +#[test] +fn test() { + let caller = abi(MyContract, CONTRACT_ID); + let b = 0x02u256; + + let _ = caller.test_function(b); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/test.toml new file mode 100644 index 00000000000..ad1782559e7 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/test.toml @@ -0,0 +1,3 @@ +category = "unit_tests_pass" +validate_abi = false +expected_warnings = 0 From 561007df9345e3879ec60f7ca633bf000b6052af Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Thu, 9 Jan 2025 18:11:25 +0700 Subject: [PATCH 50/52] Remove instances of multiple impl blocks (#6822) ## Description Previously due to issue #1548 it was not possible to use a method defined in an impl block in another method defined in the same impl block, that issue is now fixed. ## Checklist - [ ] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] 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). - [ ] I have requested a review from the relevant team or maintainers. --- sway-lib-core/src/primitive_conversions.sw | 9 --------- sway-lib-std/src/bytes.sw | 3 --- 2 files changed, 12 deletions(-) diff --git a/sway-lib-core/src/primitive_conversions.sw b/sway-lib-core/src/primitive_conversions.sw index 3160a5eca02..f0a1a14de81 100644 --- a/sway-lib-core/src/primitive_conversions.sw +++ b/sway-lib-core/src/primitive_conversions.sw @@ -45,10 +45,7 @@ impl u32 { input: u64 } } -} -// TODO: This must be in a separate impl block until https://github.com/FuelLabs/sway/issues/1548 is resolved -impl u32 { /// Extends a `u32` to a `u256`. /// /// # Returns @@ -114,10 +111,7 @@ impl u16 { input: u64 } } -} -// TODO: This must be in a separate impl block until https://github.com/FuelLabs/sway/issues/1548 is resolved -impl u16 { /// Extends a `u16` to a `u256`. /// /// # Returns @@ -204,10 +198,7 @@ impl u8 { input: u64 } } -} -// TODO: This must be in a separate impl block until https://github.com/FuelLabs/sway/issues/1548 is resolved -impl u8 { /// Extends a `u8` to a `u256`. /// /// # Returns diff --git a/sway-lib-std/src/bytes.sw b/sway-lib-std/src/bytes.sw index cb6a8edb521..5b5c817e914 100644 --- a/sway-lib-std/src/bytes.sw +++ b/sway-lib-std/src/bytes.sw @@ -584,10 +584,7 @@ impl Bytes { pub fn ptr(self) -> raw_ptr { self.buf.ptr() } -} -// Need to use separate impl blocks for now: https://github.com/FuelLabs/sway/issues/1548 -impl Bytes { /// Divides one Bytes into two at an index. /// /// # Additional Information From faf399e094c60898d379660f151ae14a8929e983 Mon Sep 17 00:00:00 2001 From: Marcos Henrich Date: Thu, 9 Jan 2025 13:26:18 +0000 Subject: [PATCH 51/52] Fixes array oob on reassignment. (#6819) ## Description When using literal on array reasignement we were not checking the array length. We now throw an array oob error in this case. Fixes #6393 ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. Co-authored-by: Joshua Batty --- .../ast_node/expression/typed_expression.rs | 19 +++++++++++++++++-- .../array_oob_reassignment/Forc.lock | 8 ++++++++ .../array_oob_reassignment/Forc.toml | 9 +++++++++ .../array_oob_reassignment/src/main.sw | 16 ++++++++++++++++ .../array_oob_reassignment/test.toml | 19 +++++++++++++++++++ 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/test.toml diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 06220dcac74..62f88759358 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -2536,12 +2536,27 @@ impl ty::TyExpression { full_span_for_error = Span::join(full_span_for_error, index_span); } ( - TypeInfo::Array(elem_ty, _), - ty::ProjectionKind::ArrayIndex { index_span, .. }, + TypeInfo::Array(elem_ty, array_length), + ty::ProjectionKind::ArrayIndex { index, index_span }, ) => { parent_rover = symbol; symbol = elem_ty.type_id; symbol_span = index_span.clone(); + + if let Some(index_literal) = index + .expression + .as_literal() + .and_then(|x| x.cast_value_to_u64()) + { + if index_literal >= array_length.val() as u64 { + return Err(handler.emit_err(CompileError::ArrayOutOfBounds { + index: index_literal, + count: array_length.val() as u64, + span: index.span.clone(), + })); + } + } + // `index_span` does not contain the enclosing square brackets. // Which means, if this array index access is the last one before the // erroneous expression, the `full_span_for_error` will be missing the diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.lock new file mode 100644 index 00000000000..7f8a3338563 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "array_oob_reassignment" +source = "member" +dependencies = ["core"] + +[[package]] +name = "core" +source = "path+from-root-CC73096846C1E083" diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.toml new file mode 100644 index 00000000000..cc38134eea8 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +license = "Apache-2.0" +name = "array_oob_reassignment" +entry = "main.sw" +implicit-std = false + +[dependencies] +core = { path = "../../../../../../sway-lib-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/src/main.sw new file mode 100644 index 00000000000..cd5d7979225 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/src/main.sw @@ -0,0 +1,16 @@ +script; + +fn main() { + let mut a = [u64; 0]; + a[0] = 1; + + + let mut b = [[u64; 1]; 1]; + b[0][1] = 1; + + + b[1][0] = 1; + + + a[0] = return; +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/test.toml new file mode 100644 index 00000000000..e3c8288e736 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/test.toml @@ -0,0 +1,19 @@ +category = "fail" + +# check: $()let mut a = [u64; 0]; +# nextln: $()This declaration is never used. + +# check: $()let mut b = [[u64; 1]; 1]; +# nextln: $()This declaration is never used. + +# check: $()a[0] = 1; +# nextln: $()Index out of bounds; the length is 0 but the index is 0. + +# check: $()b[0][1] = 1; +# nextln: $()Index out of bounds; the length is 1 but the index is 1. + +# check: $()b[1][0] = 1; +# nextln: $()Index out of bounds; the length is 1 but the index is 1. + +# check: $()a[0] = return; +# nextln: $()Index out of bounds; the length is 0 but the index is 0. \ No newline at end of file From 1192b3f134547d7f0a31ffcc061553d0ca7ab4b6 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Fri, 10 Jan 2025 17:17:06 +0700 Subject: [PATCH 52/52] add erroneously missing #[test()] attribute (#6824) ## Description A few bytes tests are erroneously missing the test attribute, meaning they are not actually run. ## 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). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] 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. --- .../test_programs/bytes_inline_tests/src/main.sw | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw index 65597943ef7..e32d25da40b 100644 --- a/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw @@ -779,6 +779,7 @@ fn bytes_append_to_empty() { }; } +#[test()] fn bytes_append_self() { let (mut bytes, a, b, c) = setup(); assert(bytes.len() == 3); @@ -797,6 +798,7 @@ fn bytes_append_self() { assert(bytes.get(5).unwrap() == c); } +#[test()] fn bytes_append_empty_self() { let mut empty_bytes = Bytes::new();