| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
LSP: Support multiple workspaces (#7214) ## Description The langauge server now supports multiple workspaces and individual projects in a single server instance. For example, in the sway repo itself, we have 3 large sway project workspaces. Before this change, LSP would only work for the first workspace you opened. Now you can freely move between projects and workspaces. There is a bit of code quality associated with this PR to better reflect the new approach rather than the contained `Session` type that we had previously. ## Other changes * This PR fixes a bug with `forc-pkg` that would panic if it was called from an async context. i.e `forc-lsp` or `forc-doc`. We now check if a `tokio` runtime exists and use that to avoid crashing in these situations. * Document symbols are now collected for more types. We also check that document symbols are present for all files in the std library as well as semantic tokens during the test. ## 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). - [x] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com> | 1 年前 | |
fix modified in optimisation passes so they converge (#7666) ## Description This PR fix the `modified` return of some optimisation passes, so we can run optimisations multiple times until they converge. To guarantee that they are correct, we now have an "env var" named "SWAY_VERIFY_FORCE" that forces IR verification and checks whether the modified flag is the same as the comparison of the IR before and after the pass. The flag is being set for all snapshot tests. As discussed, it makes sense to remove the "verify" CLI flag. For this last check, I had to write the "mut" of function and block arguments in the IR; otherwise, the "mutability-tagger" pass would return true, but without any visible change in the IR, the check would always fail. This triggered a LOT of changes, given that we assume everything is mutable by default. On the bright side is that it is now much easier to see improvements to the tagger pass. There are also other small improvements in the form of "TODO", because if Sway can guarantee that a value is never written, we can generate the initial IR already flagging something as immutable. Another big change was the removal of "file-checks" for some IR tests. We already have snapshot tests for them, and given that the snapshot shows the complete diff, it is much easier to see the exact difference of each pass. I left normal comments though. ## 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. | 2 个月前 | |
fix modified in optimisation passes so they converge (#7666) ## Description This PR fix the `modified` return of some optimisation passes, so we can run optimisations multiple times until they converge. To guarantee that they are correct, we now have an "env var" named "SWAY_VERIFY_FORCE" that forces IR verification and checks whether the modified flag is the same as the comparison of the IR before and after the pass. The flag is being set for all snapshot tests. As discussed, it makes sense to remove the "verify" CLI flag. For this last check, I had to write the "mut" of function and block arguments in the IR; otherwise, the "mutability-tagger" pass would return true, but without any visible change in the IR, the check would always fail. This triggered a LOT of changes, given that we assume everything is mutable by default. On the bright side is that it is now much easier to see improvements to the tagger pass. There are also other small improvements in the form of "TODO", because if Sway can guarantee that a value is never written, we can generate the initial IR already flagging something as immutable. Another big change was the removal of "file-checks" for some IR tests. We already have snapshot tests for them, and given that the snapshot shows the complete diff, it is much easier to see the exact difference of each pass. I left normal comments though. ## 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. | 2 个月前 | |
chore: bumpt rust version to 1.90 (#7427) ## Description Bumping the rust version to 1.90 and fixing the clippy lints along the way | 11 个月前 | |
Rewrite `TypeEngine` for performance, robustness, and simplicity (#6613) ## 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<u64, bool>` are unchangeable while `Numeric`, `Unknown` or `MyStruct<T1, T1>` 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_<built-in-type>` 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<TypeSourceInfo>`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_<type>()` and `insert_<type>` 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_<type>` 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 <joshpbatty@gmail.com> Co-authored-by: João Matos <joao@tritao.eu> | 1 年前 |
Sway Language Server
This extension provides LSP support for the Sway smart contract programming language.
Features
- go-to type definition
- types and documentation on hover
- inlay hints for types and parameter names
- semantic syntax highlighting
- symbol renaming
- code actions
- imports insertion
Coming Soon
- code completion
- apply suggestions from errors
- find all references, workspace symbol search
- ... and many more
Quick start
- Install the Fuel toolchain.
- Ensure
forc-lspis installed correctly by enteringforc-lsp --versioninto your terminal. - Install the Sway VSCode plugin.
Trying out the local version
To try out the local LSP version:
- Install the local version of the server:
cargo install --path ./forc-plugins/forc-lsp. - Open VSCode settings and set the
Sway-lsp › Diagnostic: Bin Pathto the installedforc-lspbinary. The path to the binary will be listed at the end of thecargo installcommand and is usually:/home/<user>/.cargo/bin/forc-lsp. - Open an arbitrary Sway project. E.g.,
./examples/arrays. - Open the Output window in VSCode and select Sway Language Server from the drop down menu.
- Start coding and observe the LSP output in the Output window. This window will also show any
dbg!oreprintln!lines.