diff --git a/.cargo/config.toml b/.cargo/config.toml index eb89fa1e55..7e4e7a0f90 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,8 +1,8 @@ [alias] xtask = "run --package xtask --" -# @fb-only: [build] -# @fb-only: target-dir = "../../../buck-out/elp" +# @fb-only +# @fb-only [profile.release] codegen-units = 1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e9980283f2..471b9d2418 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: strategy: fail-fast: false matrix: - platform-arch: [ubuntu-22.04-x64, ubuntu-22.04-arm, macos-15-x64, macos-latest-arm, windows-2022-x64] + platform-arch: [ubuntu-22.04-x64, ubuntu-22.04-arm, macos-13-x64, macos-latest-arm, windows-2022-x64] otp-version: [26.2, 27.3, 28.0] include: - otp-version: 26.2 @@ -55,8 +55,8 @@ jobs: os: linux target: aarch64-unknown-linux-gnu vscode-target: linux-arm64 - - platform-arch: macos-15-x64 - platform: macos-15-intel + - platform-arch: macos-13-x64 + platform: macos-13 os: macos target: x86_64-apple-darwin vscode-target: darwin-x64 @@ -97,8 +97,6 @@ jobs: run: | sudo apt-get update sudo apt-get install -y crossbuild-essential-arm64 - - name: Install Buck2 - uses: dtolnay/install-buck2@latest - id: setup-erlang uses: ./.github/actions/setup-erlang with: @@ -137,7 +135,7 @@ jobs: - name: Test elp # Do not run the tests in case of cross-compilation or on Windows if: matrix.platform-arch != 'macos-latest-arm' && matrix.os != 'windows' - run: 'cargo test --workspace --target ${{ matrix.target }}' + run: 'cargo test --no-default-features --workspace --target ${{ matrix.target }}' - name: Build elp (No Windows) if: matrix.os != 'windows' run: 'cargo build --release --target ${{ matrix.target }} --config target.aarch64-unknown-linux-gnu.linker=\"aarch64-linux-gnu-gcc\"' @@ -202,8 +200,6 @@ jobs: node-version: 20 - name: Install VSCE run: npm install -g vsce - - name: Install OVSX - run: npm install -g ovsx - name: Prepare VS Code Extension to host binaries (No Windows) if: matrix.os != 'windows' run: mkdir -p editors/code/bin @@ -289,7 +285,3 @@ jobs: working-directory: editors/code if: ${{ github.event_name == 'release' && matrix.vscode-publish && matrix.os != 'windows' }} run: vsce publish -p ${{ secrets.VSCE_PAT }} --packagePath erlang-language-platform.vsix - - name: Publish extension to OpenVSX marketplace - working-directory: editors/code - if: ${{ github.event_name == 'release' && matrix.vscode-publish && matrix.os != 'windows' }} - run: ovsx publish -p ${{ secrets.OVSX_PAT }} --packagePath erlang-language-platform.vsix diff --git a/.llms/rules/elp_development.md b/.llms/rules/elp_development.md index efd132ac4b..579764599a 100644 --- a/.llms/rules/elp_development.md +++ b/.llms/rules/elp_development.md @@ -3,34 +3,13 @@ llms-gk: 'devmate_elp_development_md' apply_to_regex: '^(.*\.rs|.*\.md)$' oncalls: ['vscode_erlang'] --- -# ELP Development Rules for LLMs (OSS) + +# ELP Development Rules for LLMs + ## Project Overview -ELP (Erlang Language Platform) is a language server and development tools suite -for Erlang, built in Rust. This project provides IDE features, diagnostics, and -code analysis for Erlang codebases. - -## Build System - -Use standard Cargo commands: - -```bash -# Build -cargo build --release - -# Run tests -cargo test --workspace - -# Run clippy -cargo clippy --tests - -# Format code -cargo fmt - -# Code generation -cargo xtask codegen -``` +ELP (Erlang Language Platform) is a language server and development tools suite for Erlang, built in Rust. This project provides IDE features, diagnostics, and code analysis for Erlang codebases. ## Diagnostic Code Management @@ -38,13 +17,13 @@ cargo xtask codegen When adding new diagnostic codes to `DiagnosticCode` enum: -1. **Naming Convention**: Use descriptive PascalCase names that clearly indicate - the issue +1. **Naming Convention**: Use descriptive PascalCase names that clearly indicate the issue - Good: `UnusedFunctionArg`, `MissingCompileWarnMissingSpec` - Bad: `Error1`, `BadCode` 2. **Code Assignment**: Follow the established numbering scheme - `W0000-W9999`: Native ELP diagnostics, visible in the OSS version + - `WA000-WA999`: WhatsApp-specific warnings, only visible in Meta builds - Use the next available number in the appropriate range - Never change the number of an existing diagnostic code - Never change the label of an existing diagnostic code @@ -58,8 +37,7 @@ When adding new diagnostic codes to `DiagnosticCode` enum: 4. **Documentation**: Add comments explaining complex diagnostic codes -5. **Documentation File**: Create a corresponding documentation file in the - website +5. **Documentation File**: Create a corresponding documentation file in the website - Location: `website/docs/erlang-error-index/{namespace}/{code}.md` - Example: `W0051` → `website/docs/erlang-error-index/w/W0051.md` - Include frontmatter with `sidebar_position` matching the code number @@ -73,19 +51,16 @@ When adding new diagnostic codes to `DiagnosticCode` enum: ### Creating DiagnosticDescriptor -Every diagnostic must have a corresponding `DiagnosticDescriptor` that defines -when and how the diagnostic runs: +Every diagnostic must have a corresponding `DiagnosticDescriptor` that defines when and how the diagnostic runs: -1. **Static Descriptor Declaration**: Create a public static descriptor in your - diagnostic module +1. **Static Descriptor Declaration**: Create a public static descriptor in your diagnostic module - Use `pub(crate) static DESCRIPTOR: DiagnosticDescriptor` pattern - Define `DiagnosticConditions` with appropriate flags - Provide a checker function that implements the diagnostic logic 2. **Diagnostic Conditions**: Configure when the diagnostic should run - `experimental`: Mark as true for experimental/unstable diagnostics - - `include_generated`: Set to false if diagnostic shouldn't run on generated - code + - `include_generated`: Set to false if diagnostic shouldn't run on generated code - `include_tests`: Set to false if diagnostic shouldn't run on test files - `default_disabled`: Set to true if diagnostic requires explicit enabling @@ -94,8 +69,7 @@ when and how the diagnostic runs: - Push diagnostics to the `diags` vector using `Diagnostic::new()` - Use helper functions to keep the checker clean and focused -4. **Registration**: Add the descriptor to `diagnostics_descriptors()` function - in `diagnostics.rs` +4. **Registration**: Add the descriptor to `diagnostics_descriptors()` function in `diagnostics.rs` - Include your module's `DESCRIPTOR` in the returned vector 5. **Module Structure**: Follow the established pattern @@ -104,6 +78,12 @@ when and how the diagnostic runs: - Include comprehensive tests with `#[cfg(test)]` - Use SSR patterns when appropriate for complex matching +### Meta-Only vs OSS Code + +- Use `@fb-only` and `@oss-only` comments to mark platform-specific code +- Meta-only diagnostics should use `MetaOnlyDiagnosticCode` wrapper +- Ensure OSS builds work by providing fallbacks for Meta-only features + ## Rust Code Style ### Error Handling @@ -140,40 +120,24 @@ when and how the diagnostic runs: ### Declarative Test Fixtures -ELP uses a declarative test fixture system that allows you to write tests with -inline annotations and markers directly in test strings. This system is defined -in `crates/project_model/src/test_fixture.rs`. +ELP uses a declarative test fixture system that allows you to write tests with inline annotations and markers directly in test strings. This system is defined in `/data/sandcastle/boxes/fbsource/fbcode/whatsapp/elp/crates/project_model/src/test_fixture.rs`. #### Key Features -1. **File Organization**: Use `//- /path/to/file.erl` to define multiple files - in a single test -2. **Metadata Markers**: Specify app names, include paths, OTP apps, etc. using - metadata after the path +1. **File Organization**: Use `//- /path/to/file.erl` to define multiple files in a single test +2. **Metadata Markers**: Specify app names, include paths, OTP apps, etc. using metadata after the path 3. **Annotations**: Mark expected diagnostics or ranges using `%% ^^^` syntax -4. **Cursors and Ranges**: Use `~` markers to indicate positions or ranges in - test code +4. **Cursors and Ranges**: Use `~` markers to indicate positions or ranges in test code #### Annotation Syntax -Annotations allow you to mark expected diagnostics, types, or other information -directly in test code: +Annotations allow you to mark expected diagnostics, types, or other information directly in test code: -- **Basic annotation**: `%% ^^^ some text` - Points to the range above matching - the caret length -- **Top-of-file marker**: `%% <<< text` (at file start) - Creates annotation at - position 0..0 -- **File-wide annotation**: `%% ^^^file text` - Annotation spans the entire file - contents -- **Left-margin annotation**: `%%<^^^ text` - Annotation starts at `%%` position - instead of first `^` +- **Basic annotation**: `%% ^^^ some text` - Points to the range above matching the caret length +- **Top-of-file marker**: `%% <<< text` (at file start) - Creates annotation at position 0..0 +- **File-wide annotation**: `%% ^^^file text` - Annotation spans the entire file contents +- **Left-margin annotation**: `%%<^^^ text` - Annotation starts at `%%` position instead of first `^` - **Multiline annotations**: Use continuation lines with `%% | next line` - - Continuation lines are particularly useful for diagnostics with related information: - ```erlang - foo() -> syntax error oops. - %% ^^^^^ error: P1711: syntax error before: error - %% | Related info: 0:45-50 function foo/0 undefined - ``` #### Example Test Fixture @@ -182,8 +146,9 @@ let fixture = r#" //- /src/main.erl -module(main). -foo( -> ok. %% -%% ^ error: W0004: Missing ')'~ +foo(X) -> + X + undefined. + %% ^^^^^^^^^ error: type mismatch "#; ``` @@ -195,37 +160,34 @@ foo( -> ok. %% ### Running Tests for Specific Crates -When running tests for a specific crate, you need to specify the crate name, not -the directory name. The mapping is: +When running tests for a specific crate, you need to specify the crate name, not the directory name. The mapping is: -| Crate Name | Directory Name | -| -------------------- | ----------------------- | -| `elp` | `crates/elp` | -| `elp_base_db` | `crates/base_db` | -| `elp_eqwalizer` | `crates/eqwalizer` | +| Crate Name | Directory Name | +|------------|----------------| +| `elp_base_db` | `crates/base_db` | +| `elp_eqwalizer` | `crates/eqwalizer` | | `elp_erlang_service` | `crates/erlang_service` | -| `elp_ide` | `crates/ide` | -| `elp_ide_assists` | `crates/ide_assists` | +| `elp_ide` | `crates/ide` | +| `elp_ide_assists` | `crates/ide_assists` | | `elp_ide_completion` | `crates/ide_completion` | -| `elp_ide_db` | `crates/ide_db` | -| `elp_ide_ssr` | `crates/ide_ssr` | -| `elp_log` | `crates/elp_log` | -| `elp_project_model` | `crates/project_model` | -| `elp_syntax` | `crates/syntax` | -| `elp_text_edit` | `crates/text_edit` | -| `elp_types_db` | `crates/types_db` | -| `hir` | `crates/hir` | +| `elp_ide_db` | `crates/ide_db` | +| `elp_ide_ssr` | `crates/ide_ssr` | +| `elp_log` | `crates/elp_log` | +| `elp_project_model` | `crates/project_model` | +| `elp_syntax` | `crates/syntax` | +| `elp_text_edit` | `crates/text_edit` | +| `elp_types_db` | `crates/types_db` | +| `hir` | `crates/hir` | +| `erl_ast` | `crates/erl_ast` | Example: To run tests for the `elp_ide` crate: - ```bash -cargo test -p elp_ide +./meta/cargo.sh test -p elp_ide ``` Or to run tests in a specific directory: - ```bash -cargo test --manifest-path crates/ide/Cargo.toml +./meta/cargo.sh test --manifest-path crates/ide/Cargo.toml ``` ### Existing tests @@ -315,8 +277,14 @@ cargo test --manifest-path crates/ide/Cargo.toml - Collect multiple errors rather than failing on the first one - Provide partial results when full analysis isn't possible +### Tools + +- ELP uses a cargo workspace. +- Inside Meta, use `./meta/cargo.sh` instead of `cargo` +- Inside Meta, use `./meta/clippy.sh` to run clippy +- Use `arc lint --apply-patches` for formatting. + ### Process -- Always run tests before finishing -- Always run `cargo clippy --tests` before submitting PRs -- Use `cargo fmt` for code formatting +- Always run tests before finishing. +- Always run `./meta/cargo.sh clippy --tests` before submitting a diff diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 7572a84e98..51f0340659 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,7 +4,7 @@ { "label": "ELP: build (debug)", "type": "shell", - // @fb-only: "command": "./meta/cargo.sh build", + // @fb-only "command": "cargo build", // @oss-only "group": { "kind": "build", @@ -19,7 +19,7 @@ { "label": "ELP: build (release)", "type": "shell", - // @fb-only: "command": "./meta/cargo.sh build --release", + // @fb-only "command": "cargo build --release", // @oss-only "group": { "kind": "build", @@ -34,7 +34,7 @@ { "label": "ELP: build (release-thin)", "type": "shell", - // @fb-only: "command": "./meta/cargo.sh build --profile release-thin --bins", + // @fb-only "command": "cargo build --profile release-thin --bins", // @oss-only "group": { "kind": "build", @@ -49,7 +49,7 @@ { "label": "ELP: run clippy on workspace", "type": "shell", - // @fb-only: "command": "./meta/clippy.sh --workspace --tests", + // @fb-only "command": "cargo clippy --workspace --tests", // @oss-only "group": { "kind": "build", @@ -64,7 +64,7 @@ { "label": "ELP: run clippy on workspace, apply fixes", "type": "shell", - // @fb-only: "command": "./meta/clippy.sh --workspace --tests --fix", + // @fb-only "command": "cargo clippy --workspace --tests --fix", // @oss-only "group": { "kind": "build", @@ -79,7 +79,7 @@ { "label": "ELP: run tests on workspace", "type": "shell", - // @fb-only: "command": "./meta/cargo.sh test --workspace", + // @fb-only "command": "cargo test --workspace", // @oss-only "group": { "kind": "build", diff --git a/Cargo.lock b/Cargo.lock index 2da9907eca..03f23763eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -446,10 +446,10 @@ dependencies = [ "crossbeam-channel", "elp_eqwalizer", "elp_ide", - "elp_ide_db", "elp_log", "elp_project_model", "elp_syntax", + "elp_text_edit", "env_logger", "expect-test", "fs_extra", @@ -572,6 +572,7 @@ dependencies = [ "elp_ide_ssr", "elp_project_model", "elp_syntax", + "elp_text_edit", "elp_types_db", "env_logger", "expect-test", @@ -603,6 +604,7 @@ dependencies = [ "cov-mark", "elp_ide_db", "elp_syntax", + "elp_text_edit", "expect-test", "fxhash", "hir", @@ -635,7 +637,6 @@ name = "elp_ide_db" version = "1.1.0" dependencies = [ "anyhow", - "cov-mark", "eetf", "either", "elp_base_db", @@ -643,12 +644,12 @@ dependencies = [ "elp_erlang_service", "elp_project_model", "elp_syntax", + "elp_text_edit", "elp_types_db", "expect-test", "fxhash", "hir", "indexmap 2.9.0", - "itertools 0.10.5", "lazy_static", "log", "memchr", @@ -663,7 +664,6 @@ dependencies = [ "strum", "strum_macros", "tempfile", - "text-size", "toml", "tracing", ] @@ -734,8 +734,10 @@ dependencies = [ name = "elp_syntax" version = "1.1.0" dependencies = [ + "cov-mark", "eetf", "elp_ide_db", + "elp_text_edit", "expect-test", "fxhash", "indexmap 2.9.0", @@ -755,6 +757,14 @@ dependencies = [ "tree-sitter-erlang", ] +[[package]] +name = "elp_text_edit" +version = "1.1.0" +dependencies = [ + "itertools 0.10.5", + "text-size", +] + [[package]] name = "elp_types_db" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 825530fe4c..5814517745 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,9 +30,13 @@ elp_ide_ssr = { path = "./crates/ide_ssr" } elp_log = { path = "./crates/elp_log" } elp_project_model = { path = "./crates/project_model" } elp_syntax = { path = "./crates/syntax" } +elp_text_edit = { path = "./crates/text_edit" } elp_types_db = { path = "./crates/types_db" } hir = { path = "./crates/hir" } +# Forks +erl_ast = { path = "./crates/erl_ast" } + # External crates trie-rs = "0.4.2" always-assert = "0.1.3" diff --git a/bench_runner/example_bench/benches/main.rs b/bench_runner/example_bench/benches/main.rs new file mode 100644 index 0000000000..6b2733b5b9 --- /dev/null +++ b/bench_runner/example_bench/benches/main.rs @@ -0,0 +1,60 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is dual-licensed under either the MIT license found in the + * LICENSE-MIT file in the root directory of this source tree or the Apache + * License, Version 2.0 found in the LICENSE-APACHE file in the root directory + * of this source tree. You may select, at your option, one of the + * above-listed licenses. + */ + +use std::thread; +use std::time; + +use criterion::BenchmarkId; +use criterion::Criterion; +use criterion::criterion_group; +use criterion::criterion_main; + +fn fibonacci_slow(n: u64) -> u64 { + match n { + 0 => 1, + 1 => 1, + n => fibonacci_slow(n - 1) + fibonacci_slow(n - 2), + } +} + +fn fibonacci_fast(n: u64) -> u64 { + let mut a = 0; + let mut b = 1; + let millis = time::Duration::from_millis(12); + thread::sleep(millis); + + match n { + 0 => b, + _ => { + for _ in 0..n { + let c = a + b; + a = b; + b = c; + } + b + } + } +} + +fn bench_fibs(c: &mut Criterion) { + let mut group = c.benchmark_group("Fibonacci"); + for i in [20u64, 21u64].iter() { + group.bench_with_input(BenchmarkId::new("Recursive", i), i, |b, i| { + b.iter(|| fibonacci_slow(*i)) + }); + group.bench_with_input(BenchmarkId::new("Iterative", i), i, |b, i| { + b.iter(|| fibonacci_fast(*i)) + }); + } + group.finish(); +} + +criterion_group!(benches, bench_fibs); +criterion_main!(benches); diff --git a/bench_runner/runner/main.rs b/bench_runner/runner/main.rs new file mode 100644 index 0000000000..f895c08c52 --- /dev/null +++ b/bench_runner/runner/main.rs @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is dual-licensed under either the MIT license found in the + * LICENSE-MIT file in the root directory of this source tree or the Apache + * License, Version 2.0 found in the LICENSE-APACHE file in the root directory + * of this source tree. You may select, at your option, one of the + * above-listed licenses. + */ + +use std::env; + +fn main() { + let args: Vec = env::args().collect(); + println!("ARGS: {:?}", args); +} diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs index cd1328d14d..d6d2205ce9 100644 --- a/crates/base_db/src/fixture.rs +++ b/crates/base_db/src/fixture.rs @@ -87,7 +87,6 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { let (fixture, change) = ChangeFixture::parse(fixture_str); let mut db = Self::default(); change.apply(&mut db, &|path| fixture.resolve_file_id(path)); - fixture.validate(&db); (db, fixture) } } @@ -102,7 +101,6 @@ pub struct ChangeFixture { pub diagnostics_enabled: DiagnosticsEnabled, pub tags: FxHashMap)>>, pub annotations: FxHashMap>, - pub expect_parse_errors: bool, } struct Builder { @@ -174,7 +172,6 @@ impl ChangeFixture { let FixtureWithProjectMeta { fixture, mut diagnostics_enabled, - expect_parse_errors, } = fixture_with_meta.clone(); let builder = Builder::new(diagnostics_enabled.clone()); @@ -347,7 +344,6 @@ impl ChangeFixture { diagnostics_enabled, tags, annotations, - expect_parse_errors, }, change, project, @@ -409,64 +405,6 @@ impl ChangeFixture { .get(&VfsPath::from(path.clone())) .cloned() } - - /// Validate all files in the fixture for syntax errors. - /// Panics with context if any syntax errors are found. - /// Skips validation if `expect_parse_errors` is set to true. - #[track_caller] - pub fn validate(&self, db: &DB) { - if self.expect_parse_errors { - return; - } - - let mut errors_found = Vec::new(); - - for file_id in &self.files { - let parse = db.parse(*file_id); - let errors = parse.errors(); - - if !errors.is_empty() { - let path = self - .files_by_path - .iter() - .find_map(|(vfs_path, id)| { - if id == file_id { - Some( - vfs_path - .as_path() - .map(|p| p.to_string()) - .unwrap_or_else(|| format!("{:?}", vfs_path)), - ) - } else { - None - } - }) - .unwrap_or_else(|| format!("FileId({:?})", file_id)); - - let file_text = SourceDatabaseExt::file_text(db, *file_id); - let tree = parse.tree(); - errors_found.push((path, file_text.to_string(), errors.to_vec(), tree)); - } - } - - if !errors_found.is_empty() { - let mut message = - String::from("Fixture validation failed: syntax errors found in test fixture\n\n"); - - for (path, text, errors, tree) in errors_found { - message.push_str(&format!("File: {}\n", path)); - message.push_str(&format!("Errors: {:?}\n", errors)); - message.push_str(&format!("Content:\n{}\n", text)); - message.push_str(&format!("Parse Tree:\n{:#?}\n", tree)); - message.push_str("---\n"); - } - message.push_str( - "If this is expected, add `//- expect_parse_errors` to the start of the fixture\n", - ); - - panic!("{}", message); - } - } } fn inc_file_id(file_id: &mut FileId) { diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs index 0cd8df74c9..6b3757ff43 100644 --- a/crates/base_db/src/lib.rs +++ b/crates/base_db/src/lib.rs @@ -32,7 +32,7 @@ mod module_index; // Public API pub mod fixture; -// @fb-only: mod meta_only; +// @fb-only pub mod test_utils; pub use change::Change; pub use elp_project_model::AppType; @@ -476,7 +476,7 @@ static ref IGNORED_SOURCES: Vec = { let regexes: Vec> = vec![ vec![Regex::new(r"^.*_SUITE_data/.+$").unwrap()], //ignore sources goes here - // @fb-only: meta_only::ignored_sources_regexes() + // @fb-only ]; regexes.into_iter().flatten().collect::>() }; diff --git a/crates/elp/Cargo.toml b/crates/elp/Cargo.toml index 2a1b6e8b65..66552ada1d 100644 --- a/crates/elp/Cargo.toml +++ b/crates/elp/Cargo.toml @@ -18,10 +18,10 @@ workspace = true [dependencies] elp_eqwalizer.workspace = true elp_ide.workspace = true -elp_ide_db.workspace = true elp_log.workspace = true elp_project_model.workspace = true elp_syntax.workspace = true +elp_text_edit.workspace = true hir.workspace = true always-assert.workspace = true diff --git a/crates/elp/src/arc_types.rs b/crates/elp/src/arc_types.rs index 374dcdba2f..c113311661 100644 --- a/crates/elp/src/arc_types.rs +++ b/crates/elp/src/arc_types.rs @@ -8,8 +8,8 @@ * above-listed licenses. */ -// @fb-only: /// Types as defined in https://www.internalfb.com/intern/wiki/Linting/adding-linters/#flow-type -// @fb-only: /// and https://www.internalfb.com/code/fbsource/[1238f73dac0efd4009443fee6a345a680dc9401b]/whatsapp/server/erl/tools/lint/arcanist.py?lines=17 +// @fb-only +// @fb-only use std::path::Path; use serde::Serialize; diff --git a/crates/elp/src/bin/args.rs b/crates/elp/src/bin/args.rs index c9790e9314..343f6bd820 100644 --- a/crates/elp/src/bin/args.rs +++ b/crates/elp/src/bin/args.rs @@ -11,7 +11,6 @@ use std::cmp::Ordering; use std::env; use std::fs; -use std::io::IsTerminal; use std::path::PathBuf; use anyhow::Result; @@ -72,17 +71,6 @@ pub struct ParseAllElp { /// Report system memory usage and other statistics #[bpaf(long("report-system-stats"))] pub report_system_stats: bool, - /// Minimum severity level to report. Valid values: error, warning, weak_warning, information - #[bpaf( - argument("SEVERITY"), - complete(severity_completer), - fallback(None), - guard( - severity_guard, - "Please use error, warning, weak_warning, or information" - ) - )] - pub severity: Option, } #[derive(Clone, Debug, Bpaf)] @@ -155,6 +143,8 @@ pub struct EqwalizeAll { /// Also eqwalize opted-in generated modules from project (deprecated) #[bpaf(hide)] pub include_generated: bool, + /// Also eqwalize test modules from project + pub include_tests: bool, /// Exit with a non-zero status code if any errors are found pub bail_on_error: bool, /// Print statistics when done @@ -171,6 +161,8 @@ pub struct EqwalizeTarget { /// Also eqwalize opted-in generated modules from application (deprecated) #[bpaf(hide)] pub include_generated: bool, + /// Also eqwalize test modules from project + pub include_tests: bool, /// Exit with a non-zero status code if any errors are found pub bail_on_error: bool, /// target, like //erl/chatd/... @@ -189,6 +181,8 @@ pub struct EqwalizeApp { /// Also eqwalize opted-in generated modules from project (deprecated) #[bpaf(hide)] pub include_generated: bool, + /// Also eqwalize test modules from project + pub include_tests: bool, /// Run with rebar pub rebar: bool, /// Exit with a non-zero status code if any errors are found @@ -211,6 +205,8 @@ pub struct EqwalizeStats { /// Also eqwalize opted-in generated modules from project (deprecated) #[bpaf(hide)] pub include_generated: bool, + /// Also eqwalize test modules from project + pub include_tests: bool, /// If specified, use the provided CLI severity mapping instead of the default one pub use_cli_severity: bool, } @@ -278,6 +274,8 @@ pub struct Lint { guard(format_guard, "Please use json") )] pub format: Option, + /// Optional prefix to prepend to each diagnostic file path. Only used when --format=json is set + pub prefix: Option, /// Include diagnostics produced by erlc pub include_erlc_diagnostics: bool, @@ -334,9 +332,6 @@ pub struct Lint { #[bpaf(long("report-system-stats"))] pub report_system_stats: bool, - /// Disable streaming of diagnostics when applying fixes (collect all before printing) - pub no_stream: bool, - /// Rest of args are space separated list of apps to ignore #[bpaf(positional("IGNORED_APPS"))] pub ignore_apps: Vec, @@ -391,33 +386,6 @@ pub struct Ssr { #[bpaf(long("parens"))] pub paren_strategy: bool, - /// Dump a configuration snippet that can be put in .elp_lint.toml to match the given SSR patterns - pub dump_config: bool, - - /// Show source code context for matches - #[bpaf(long("show-source"))] - pub show_source: bool, - - /// Print NUM lines of leading context, enables --show-source - #[bpaf(short('B'), long("before-context"), argument("NUM"))] - pub before_context: Option, - - /// Print NUM lines of trailing context, enables --show-source - #[bpaf(short('A'), long("after-context"), argument("NUM"))] - pub after_context: Option, - - /// Print NUM lines of output context, enables --show-source - #[bpaf(short('C'), long("context"), argument("NUM"))] - pub context: Option, - - /// Print SEP on line between matches with context, enables --show-source - #[bpaf(long("group-separator"), argument("SEP"))] - pub group_separator: Option, - - /// Do not print separator for matches with context, enables --show-source - #[bpaf(long("no-group-separator"))] - pub no_group_separator: bool, - /// Report system memory usage and other statistics #[bpaf(long("report-system-stats"))] pub report_system_stats: bool, @@ -474,6 +442,8 @@ pub struct Glean { pub pretty: bool, /// Output each fact separately pub multi: bool, + /// Optional prefix to prepend to each fact + pub prefix: Option, } #[derive(Clone, Debug, Bpaf)] @@ -520,16 +490,6 @@ pub struct Args { /// Use buck2 targets for first stage project loading pub buck_quick_start: bool, - /// Use color in output; WHEN is 'always', 'never', or 'auto' - #[bpaf( - long("color"), - long("colour"), - argument("WHEN"), - fallback(Some("always".to_string())), - guard(color_guard, "Please use always, never, or auto") - )] - pub color: Option, - #[bpaf(external(command))] pub command: Command, } @@ -544,20 +504,6 @@ impl Args { BuckQueryConfig::BuildGeneratedCode } } - - /// Determine if color should be used based on the --color argument - pub fn should_use_color(&self) -> bool { - match self.color.as_deref() { - Some("always") => true, - Some("never") => false, - Some("auto") | None => { - // Check NO_COLOR environment variable - if set (regardless of value), disable color - // Also check if stdout is connected to a TTY - env::var("NO_COLOR").is_err() && std::io::stdout().is_terminal() - } - _ => false, // Should be caught by the guard, but handle anyway - } - } } pub fn command() -> impl Parser { @@ -629,12 +575,6 @@ pub fn command() -> impl Parser { .command("lint") .help("Parse files in project and emit diagnostics, optionally apply fixes."); - let search = ssr() - .map(Command::Ssr) - .to_options() - .command("search") - .help("Alias for 'ssr': Run SSR (Structural Search and Replace) pattern matching on project files."); - let ssr = ssr() .map(Command::Ssr) .to_options() @@ -696,7 +636,6 @@ pub fn command() -> impl Parser { dialyze_all, lint, ssr, - search, parse_all, parse_elp, explain, @@ -786,25 +725,6 @@ fn format_guard(format: &Option) -> bool { } } -fn severity_completer(_: &Option) -> Vec<(String, Option)> { - vec![ - ("error".to_string(), None), - ("warning".to_string(), None), - ("weak_warning".to_string(), None), - ("information".to_string(), None), - ] -} - -fn severity_guard(severity: &Option) -> bool { - match severity { - None => true, - Some(s) if s == "error" || s == "warning" || s == "weak_warning" || s == "information" => { - true - } - _ => false, - } -} - fn macros_completer(_: &Option) -> Vec<(String, Option)> { vec![ ("expand".to_string(), None), @@ -820,14 +740,6 @@ fn macros_guard(format: &Option) -> bool { } } -fn color_guard(color: &Option) -> bool { - match color { - None => true, - Some(c) if c == "always" || c == "never" || c == "auto" => true, - _ => false, - } -} - #[allow(clippy::ptr_arg)] // This is needed in the BPAF macros fn at_least_1(data: &Vec) -> bool { !data.is_empty() @@ -908,11 +820,6 @@ impl Lint { pub fn is_format_json(&self) -> bool { self.format == Some("json".to_string()) } - - /// To prevent flaky test results we allow disabling streaming when applying fixes - pub fn skip_stream_print(&self) -> bool { - self.apply_fix || self.no_stream - } } fn parse_macro_strategy(macro_strategy: &Option) -> Result { diff --git a/crates/elp/src/bin/elp_parse_cli.rs b/crates/elp/src/bin/elp_parse_cli.rs index 770ab60456..fcc8652ec2 100644 --- a/crates/elp/src/bin/elp_parse_cli.rs +++ b/crates/elp/src/bin/elp_parse_cli.rs @@ -24,6 +24,7 @@ use elp::cli::Cli; use elp::convert; use elp::memory_usage::MemoryUsage; use elp::otp_file_to_ignore; +use elp::server::file_id_to_url; use elp_eqwalizer::Mode; use elp_ide::Analysis; use elp_ide::diagnostics; @@ -57,35 +58,6 @@ use crate::args::ParseAllElp; use crate::reporting; use crate::reporting::print_memory_usage; -fn parse_severity(severity: &str) -> Option { - match severity { - "error" => Some(diagnostics::Severity::Error), - "warning" => Some(diagnostics::Severity::Warning), - "weak_warning" => Some(diagnostics::Severity::WeakWarning), - "information" => Some(diagnostics::Severity::Information), - _ => None, - } -} - -fn severity_rank(severity: diagnostics::Severity) -> u8 { - match severity { - diagnostics::Severity::Error => 1, - diagnostics::Severity::Warning => 2, - diagnostics::Severity::WeakWarning => 3, - diagnostics::Severity::Information => 4, - } -} - -fn meets_severity_threshold( - diag_severity: diagnostics::Severity, - min_severity: Option, -) -> bool { - match min_severity { - None => true, - Some(min) => severity_rank(diag_severity) <= severity_rank(min), - } -} - #[derive(Debug)] struct ParseResult { name: String, @@ -160,7 +132,8 @@ pub fn parse_all( (None, _, true) => do_parse_all_seq(cli, &loaded, &cfg, &args.to)?, (None, _, false) => do_parse_all_par(cli, &loaded, &cfg, &args.to)?, (Some(file_id), Some(name), _) => { - do_parse_one(&analysis, &cfg, &args.to, file_id, &name)?.map_or(vec![], |x| vec![x]) + do_parse_one(&analysis, &loaded.vfs, &cfg, &args.to, file_id, &name)? + .map_or(vec![], |x| vec![x]) } (Some(file_id), _, _) => panic!("Could not get name from file_id for {file_id:?}"), }; @@ -171,24 +144,15 @@ pub fn parse_all( let db = loaded.analysis_host.raw_database(); + // We need a `Url` for converting to the lsp_types::Diagnostic for + // printing, but do not print it out. So just create a dummy value + let url = lsp_types::Url::parse("file:///unused_url").ok().unwrap(); + telemetry::report_elapsed_time("parse-elp operational", start_time); let memory_end = MemoryUsage::now(); let memory_used = memory_end - memory_start; - let min_severity = args - .severity - .as_ref() - .and_then(|s| parse_severity(s.as_str())); - - res.retain(|parse_result| { - parse_result - .diagnostics - .diagnostics_for(parse_result.file_id) - .iter() - .any(|diag| meets_severity_threshold(diag.severity, min_severity)) - }); - if res.is_empty() { if args.is_format_normal() { writeln!(cli, "No errors reported")?; @@ -207,7 +171,6 @@ pub fn parse_all( for diags in res { let mut combined: Vec = diags.diagnostics.diagnostics_for(diags.file_id); - combined.retain(|diag| meets_severity_threshold(diag.severity, min_severity)); if args.is_format_normal() { writeln!(cli, " {}: {}", diags.name, combined.len())?; } @@ -234,7 +197,7 @@ pub fn parse_all( cli, )?; } else { - print_diagnostic(&diag, &line_index, &mut err_in_diag, cli)?; + print_diagnostic(&diag, &line_index, &url, &mut err_in_diag, cli)?; } } } @@ -279,10 +242,11 @@ fn print_diagnostic_json( fn print_diagnostic( diag: &diagnostics::Diagnostic, line_index: &LineIndex, + url: &lsp_types::Url, err_in_diag: &mut bool, cli: &mut dyn Cli, ) -> Result<(), anyhow::Error> { - let diag = convert::ide_to_lsp_diagnostic(line_index, diag, |_file_id| None); + let diag = convert::ide_to_lsp_diagnostic(line_index, url, diag); let severity = match diag.severity { None => DiagnosticSeverity::ERROR, Some(sev) => { @@ -325,6 +289,7 @@ fn do_parse_all_par( let pb = cli.progress(module_iter.len() as u64, "Parsing modules"); + let vfs = &loaded.vfs; Ok(module_iter .par_bridge() .progress_with(pb) @@ -335,7 +300,7 @@ fn do_parse_all_par( && file_source == FileSource::Src && db.file_app_type(file_id).ok() != Some(Some(AppType::Dep)) { - do_parse_one(db, config, to, file_id, module_name.as_str()).unwrap() + do_parse_one(db, vfs, config, to, file_id, module_name.as_str()).unwrap() } else { None } @@ -356,6 +321,7 @@ fn do_parse_all_seq( let pb = cli.progress(module_iter.len() as u64, "Parsing modules (sequential)"); + let vfs = &loaded.vfs; let db = loaded.analysis(); Ok(module_iter .progress_with(pb) @@ -364,7 +330,7 @@ fn do_parse_all_seq( && file_source == FileSource::Src && db.file_app_type(file_id).ok() != Some(Some(AppType::Dep)) { - do_parse_one(&db, config, to, file_id, module_name.as_str()).unwrap() + do_parse_one(&db, vfs, config, to, file_id, module_name.as_str()).unwrap() } else { None } @@ -374,11 +340,13 @@ fn do_parse_all_seq( fn do_parse_one( db: &Analysis, + vfs: &Vfs, config: &DiagnosticsConfig, to: &Option, file_id: FileId, name: &str, ) -> Result> { + let url = file_id_to_url(vfs, file_id); let native = db.native_diagnostics(config, &vec![], file_id)?; let erlang_service_diagnostics = db.erlang_service_diagnostics(file_id, config, RemoveElpReported::Yes)?; @@ -396,13 +364,11 @@ fn do_parse_one( let mut output = File::create(to_path)?; for diagnostic in native.iter() { - let diagnostic = - convert::ide_to_lsp_diagnostic(&line_index, diagnostic, |_file_id| None); + let diagnostic = convert::ide_to_lsp_diagnostic(&line_index, &url, diagnostic); writeln!(output, "{diagnostic:?}")?; } for diagnostic in erlang_service.iter() { - let diagnostic = - convert::ide_to_lsp_diagnostic(&line_index, diagnostic, |_file_id| None); + let diagnostic = convert::ide_to_lsp_diagnostic(&line_index, &url, diagnostic); writeln!(output, "{diagnostic:?}")?; } } diff --git a/crates/elp/src/bin/eqwalizer_cli.rs b/crates/elp/src/bin/eqwalizer_cli.rs index 141b2157d0..c946babe42 100644 --- a/crates/elp/src/bin/eqwalizer_cli.rs +++ b/crates/elp/src/bin/eqwalizer_cli.rs @@ -186,7 +186,10 @@ pub fn do_eqwalize_all( .par_bridge() .progress_with(pb.clone()) .map_with(analysis.clone(), |analysis, (name, _source, file_id)| { - if analysis.should_eqwalize(file_id).unwrap() && !otp_file_to_ignore(analysis, file_id) + if analysis + .should_eqwalize(file_id, args.include_tests) + .unwrap() + && !otp_file_to_ignore(analysis, file_id) { if args.stats { add_stat(name.to_string()); @@ -266,7 +269,9 @@ pub fn do_eqwalize_app( .iter_own() .filter_map(|(_name, _source, file_id)| { if analysis.file_app_name(file_id).ok()? == Some(AppName(args.app.clone())) - && analysis.should_eqwalize(file_id).unwrap() + && analysis + .should_eqwalize(file_id, args.include_tests) + .unwrap() && !otp_file_to_ignore(analysis, file_id) { Some(file_id) @@ -334,7 +339,9 @@ pub fn eqwalize_target( let vfs_path = VfsPath::from(src.clone()); if let Some((file_id, _)) = loaded.vfs.file_id(&vfs_path) { at_least_one_found = true; - if analysis.should_eqwalize(file_id).unwrap() + if analysis + .should_eqwalize(file_id, args.include_tests) + .unwrap() && !otp_file_to_ignore(analysis, file_id) { file_ids.push(file_id); @@ -401,7 +408,9 @@ pub fn eqwalize_stats( .par_bridge() .progress_with(pb.clone()) .map_with(analysis.clone(), |analysis, (name, _source, file_id)| { - if analysis.should_eqwalize(file_id).expect("cancelled") + if analysis + .should_eqwalize(file_id, args.include_tests) + .expect("cancelled") && !otp_file_to_ignore(analysis, file_id) { analysis @@ -473,6 +482,8 @@ fn eqwalize( bail!("No files to eqWAlize detected") } + pre_parse_for_speed(reporter, analysis.clone(), &file_ids); + let files_count = file_ids.len(); let pb = reporter.progress(files_count as u64, "EqWAlizing"); let output = loaded.with_eqwalizer_progress_bar(pb.clone(), move |analysis| { @@ -591,6 +602,17 @@ fn eqwalize( } } +fn pre_parse_for_speed(reporter: &dyn Reporter, analysis: Analysis, file_ids: &[FileId]) { + let pb = reporter.progress(file_ids.len() as u64, "Parsing modules"); + file_ids + .par_iter() + .progress_with(pb.clone()) + .for_each_with(analysis, |analysis, &file_id| { + let _ = analysis.module_ast(file_id); + }); + pb.finish(); +} + fn set_eqwalizer_config(loaded: &mut LoadResult) { let config = EqwalizerConfig::default(); let db = loaded.analysis_host.raw_database_mut(); diff --git a/crates/elp/src/bin/erlang_service_cli.rs b/crates/elp/src/bin/erlang_service_cli.rs index 5b39a4aa06..6611bdffae 100644 --- a/crates/elp/src/bin/erlang_service_cli.rs +++ b/crates/elp/src/bin/erlang_service_cli.rs @@ -150,15 +150,14 @@ pub fn do_parse_one( .chain(result.warnings.iter()) .map(|err| { let relative_path: &Path = err.path.strip_prefix(root_dir).unwrap_or(&err.path); - let (range, line_num) = match &err.location { + let (range, line_num) = match err.location { None => (None, convert::position(&line_index, 0.into()).line + 1), Some(DiagnosticLocation::Normal(range)) => ( Some(range), convert::position(&line_index, range.start()).line + 1, ), Some(DiagnosticLocation::Included { - file_attribute_location: directive_location, - error_path: _, + directive_location, error_location: _, }) => ( Some(directive_location), @@ -170,7 +169,7 @@ pub fn do_parse_one( relative_path: relative_path.to_owned(), line_num, msg: err.msg.to_owned(), - range: range.copied(), + range, } }) .collect(); diff --git a/crates/elp/src/bin/glean.rs b/crates/elp/src/bin/glean.rs index cb420261d2..dad833e0c1 100644 --- a/crates/elp/src/bin/glean.rs +++ b/crates/elp/src/bin/glean.rs @@ -11,6 +11,7 @@ use core::option::Option::None; use std::io::Write; use std::mem; +use std::path::Path; use anyhow::Result; use elp::build::load; @@ -84,7 +85,7 @@ const REC_ARITY: u32 = 99; const HEADER_ARITY: u32 = 100; const FACTS_FILE: &str = "facts.json"; -// @fb-only: mod meta_only; +// @fb-only #[derive(Serialize, Debug, Eq, Hash, PartialEq, Clone)] struct GleanFileId(u32); @@ -92,6 +93,7 @@ struct GleanFileId(u32); #[derive(Clone, Debug, Default)] struct IndexConfig { pub multi: bool, + pub prefix: Option, } impl From for FileId { @@ -767,7 +769,10 @@ pub struct GleanIndexer { pub fn index(args: &Glean, cli: &mut dyn Cli, query_config: &BuckQueryConfig) -> Result<()> { let (indexer, _loaded) = GleanIndexer::new(args, cli, query_config)?; - let config = IndexConfig { multi: args.multi }; + let config = IndexConfig { + multi: args.multi, + prefix: args.prefix.clone(), + }; let (facts, module_index) = indexer.index(config)?; write_results(facts, module_index, cli, args) } @@ -856,7 +861,14 @@ impl GleanIndexer { let source_root_id = db.file_source_root(file_id); let source_root = db.source_root(source_root_id); let path = source_root.path_for_file(&file_id).unwrap(); - match Self::index_file(db, file_id, path, project_id, &module_index) { + match Self::index_file( + db, + file_id, + path, + project_id, + &module_index, + config.prefix.as_ref(), + ) { Some((file, line, decl, xref, facts, module_fact)) => { let mut result = FxHashMap::default(); result.insert( @@ -872,7 +884,14 @@ impl GleanIndexer { .into_par_iter() .map_with(self.analysis.clone(), |analysis, (file_id, path)| { analysis.with_db(|db| { - Self::index_file(db, file_id, &path, project_id, &module_index) + Self::index_file( + db, + file_id, + &path, + project_id, + &module_index, + config.prefix.as_ref(), + ) }) }) .flatten() @@ -929,6 +948,7 @@ impl GleanIndexer { path: &VfsPath, project_id: ProjectId, module_index: &FxHashMap, + prefix: Option<&String>, ) -> Option<( FileFact, FileLinesFact, @@ -937,7 +957,7 @@ impl GleanIndexer { Option<(Vec, XRefFact)>, Option, )> { - let file_fact = Self::file_fact(db, file_id, path, project_id)?; + let file_fact = Self::file_fact(db, file_id, path, project_id, prefix)?; let line_fact = Self::line_fact(db, file_id); let mut xref_v2 = Self::xrefs_v2(db, file_id, module_index); let mut file_decl = Self::declarations_v2(db, file_id, path)?; @@ -994,7 +1014,7 @@ impl GleanIndexer { .filter(|text| !text.is_empty()) }); - // @fb-only: let exdoc_link = elp_ide::meta_only::exdoc_links::module_exdoc_link(&module, &sema); + // @fb-only let exdoc_link: Option = None; // @oss-only ModuleFact::new( @@ -1153,12 +1173,16 @@ impl GleanIndexer { file_id: FileId, path: &VfsPath, project_id: ProjectId, + prefix: Option<&String>, ) -> Option { let project_data = db.project_data(project_id); let root = project_data.root_dir.as_path(); let file_path = path.as_path()?; let file_path = file_path.strip_prefix(root)?; - let file_path = file_path.as_str().to_string(); + let file_path = match prefix { + Some(prefix) => Path::new(&prefix).join(file_path).to_str()?.into(), + None => file_path.as_str().to_string(), + }; Some(FileFact::new(file_id, file_path)) } @@ -1532,7 +1556,7 @@ impl GleanIndexer { }) => { let def = macro_def.as_ref()?; let mut resolved = Self::resolve_macro_v2(sema, def, source_file, ctx)?; - // @fb-only: meta_only::resolve_macro_expansion(sema, *expansion, ctx, &mut resolved); + // @fb-only Some(resolved) } hir::AnyExpr::Pat(Pat::MacroCall { macro_def, .. }) @@ -1560,7 +1584,7 @@ impl GleanIndexer { vars: FxHashMap<&Location, &String>, ) -> Vec { let mut result = vec![]; - if !db.is_eqwalizer_enabled(file_id) { + if !db.is_eqwalizer_enabled(file_id, false) { return result; } let module_diagnostics = db.eqwalizer_diagnostics_by_project(project_id, vec![file_id]); @@ -1875,9 +1899,9 @@ impl GleanIndexer { let source_file = sema.parse(file_id); let range = Self::find_range(sema, ctx, &source_file, &expr_source)?; - // @fb-only: use elp_ide::meta_only::wam_links; - // @fb-only: let wam_ctx = wam_links::WamEventCtx::new(sema.db.upcast()); - // @fb-only: let wam_url = wam_ctx.build_wam_link(name).map(|link| link.url()); + // @fb-only + // @fb-only + // @fb-only let wam_url = None; // @oss-only Some(XRef { @@ -2039,6 +2063,7 @@ mod tests { v2: true, pretty: false, multi: false, + prefix: None, }; let mut module_index = FxHashMap::default(); module_index.insert(file_id.into(), module_name.to_string()); @@ -2065,6 +2090,25 @@ mod tests { ); } + #[test] + fn file_fact_prefix_test() { + let spec = r#" + //- /glean/app_glean/src/glean_module2.erl + -module(glean_module2). + "#; + let config = IndexConfig { + multi: false, + prefix: Some("my/prefix".to_string()), + }; + let result = facts_with_annotations_with_config(spec, config).0; + assert_eq!(result.file_facts.len(), 1); + let file_fact = &result.file_facts[0]; + assert_eq!( + file_fact.file_path.as_str(), + "my/prefix/glean/app_glean/src/glean_module2.erl" + ); + } + #[test] fn line_fact_with_new_line_test() { let spec = r#" @@ -2335,10 +2379,10 @@ mod tests { fn xref_types_test() { let spec = r#" //- /glean/app_glean/src/glean_module81.erl - -type small() :: {non_neg_integer() | infinity}. + -type small() :: #{non_neg_integer() | infinity}. //- /glean/app_glean/src/glean_module8.erl - -type huuuge() :: {non_neg_integer() | infinity}. + -type huuuge() :: #{non_neg_integer() | infinity}. -spec baz( A :: huuuge(), %% ^^^^^^ glean_module8/huuuge/0 @@ -2393,10 +2437,10 @@ mod tests { fn xref_types_v2_test() { let spec = r#" //- /glean/app_glean/src/glean_module81.erl - -type small() :: {non_neg_integer() | infinity}. + -type small() :: #{non_neg_integer() | infinity}. //- /glean/app_glean/src/glean_module8.erl - -type huuuge() :: {non_neg_integer() | infinity}. + -type huuuge() :: #{non_neg_integer() | infinity}. -spec baz( A :: huuuge(), %% ^^^^^^ glean_module8.erl/type/huuuge/0 diff --git a/crates/elp/src/bin/lint_cli.rs b/crates/elp/src/bin/lint_cli.rs index 241a3d4481..4ddf80b5c2 100644 --- a/crates/elp/src/bin/lint_cli.rs +++ b/crates/elp/src/bin/lint_cli.rs @@ -13,14 +13,13 @@ use std::fs; use std::fs::File; use std::io::Write; use std::path::Path; +use std::path::PathBuf; use std::str; use std::sync::Arc; -use std::thread; use std::time::SystemTime; use anyhow::Result; use anyhow::bail; -use crossbeam_channel::unbounded; use elp::build::load; use elp::build::types::LoadResult; use elp::cli::Cli; @@ -53,16 +52,17 @@ use elp_ide::elp_ide_db::elp_base_db::ProjectId; use elp_ide::elp_ide_db::elp_base_db::Vfs; use elp_ide::elp_ide_db::elp_base_db::VfsPath; use elp_ide::elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextSize; use elp_log::telemetry; use elp_project_model::AppName; use elp_project_model::AppType; use elp_project_model::DiscoverConfig; use elp_project_model::buck::BuckQueryConfig; +use elp_text_edit::TextSize; use fxhash::FxHashMap; use fxhash::FxHashSet; use hir::FormIdx; use hir::InFile; +use indicatif::ParallelProgressIterator; use itertools::Itertools; use paths::Utf8PathBuf; use rayon::prelude::ParallelBridge; @@ -132,101 +132,47 @@ pub fn load_project( ) } -fn do_diagnostics_all( - cli: &mut dyn Cli, +fn do_parse_all( + cli: &dyn Cli, analysis: &Analysis, project_id: &ProjectId, config: &DiagnosticsConfig, args: &Lint, - loaded: &LoadResult, - module: &Option, -) -> Result<(Vec<(String, FileId, DiagnosticCollection)>, bool, bool)> { +) -> Result> { let module_index = analysis.module_index(*project_id).unwrap(); + let module_iter = module_index.iter_own(); let ignored_apps: FxHashSet>> = args .ignore_apps .iter() .map(|name| Some(Some(AppName(name.to_string())))) .collect(); + let pb = cli.progress(module_iter.len() as u64, "Parsing modules"); let app_name = args.app.as_ref().map(|name| AppName(name.to_string())); - // Create a channel for streaming results - let (tx, rx) = unbounded(); - - // Collect modules into an owned vector - let modules: Vec<_> = module_index - .iter_own() - .map(|(name, source, file_id)| (name.as_str().to_string(), source, file_id)) - .collect(); - - let analysis_clone = analysis.clone(); - let config_clone = config.clone(); - let args_clone = args.clone(); - - let join_handle = thread::spawn(move || { - modules - .into_iter() - .par_bridge() - .map_with( - (analysis_clone, tx), - |(db, tx), (module_name, _file_source, file_id)| { - if !otp_file_to_ignore(db, file_id) - && db.file_app_type(file_id).ok() != Some(Some(AppType::Dep)) - && !ignored_apps.contains(&db.file_app_name(file_id).ok()) - && (app_name.is_none() - || db.file_app_name(file_id).ok().as_ref() == Some(&app_name)) - && let Ok(Some(result)) = do_diagnostics_one( - db, - &config_clone, - file_id, - &module_name, - &args_clone, - ) - { - // Send result through channel - let _ = tx.send(result); - } - }, - ) - .for_each(|_| {}); // Consume the iterator - }); - - // Collect results as they arrive from the channel - let mut results = Vec::new(); - let mut err_in_diag = false; - let mut module_count = 0; - let mut any_diagnostics_printed = false; - - for result in rx { - let printed = if args.skip_stream_print() { - false - } else { - print_diagnostic_result( - cli, - analysis, - config, - args, - loaded, - module, - &mut err_in_diag, - &mut module_count, - &result, - )? - }; - any_diagnostics_printed = any_diagnostics_printed || printed; - results.push(result); - } - - // Wait for the thread to complete before returning - // This ensures that analysis_clone is dropped and its read lock is released - join_handle - .join() - .expect("Failed to join diagnostics thread"); - - Ok((results, err_in_diag, any_diagnostics_printed)) + Ok(module_iter + .par_bridge() + .progress_with(pb) + .map_with( + analysis.clone(), + |db, (module_name, _file_source, file_id)| { + if !otp_file_to_ignore(db, file_id) + && db.file_app_type(file_id).ok() != Some(Some(AppType::Dep)) + && !ignored_apps.contains(&db.file_app_name(file_id).ok()) + && (app_name.is_none() + || db.file_app_name(file_id).ok().as_ref() == Some(&app_name)) + { + do_parse_one(db, config, file_id, module_name.as_str(), args).unwrap() + } else { + None + } + }, + ) + .flatten() + .collect()) } -fn do_diagnostics_one( +fn do_parse_one( db: &Analysis, config: &DiagnosticsConfig, file_id: FileId, @@ -293,8 +239,6 @@ pub fn do_codemod( ) -> Result<()> { // Declare outside the block so it has the right lifetime for filter_diagnostics let res; - let streamed_err_in_diag; - let mut any_diagnostics_printed = false; let mut initial_diags = { // We put this in its own block so that analysis is // freed before we apply lints. To apply lints @@ -335,18 +279,7 @@ pub fn do_codemod( res = match (file_id, name) { (None, _) => { - let (results, err_in_diag, any_printed) = do_diagnostics_all( - cli, - &analysis, - &loaded.project_id, - diagnostics_config, - args, - loaded, - &args.module, - )?; - streamed_err_in_diag = err_in_diag; - any_diagnostics_printed = any_printed; - results + do_parse_all(cli, &analysis, &loaded.project_id, diagnostics_config, args)? } (Some(file_id), Some(name)) => { if let Some(app) = &args.app @@ -355,124 +288,87 @@ pub fn do_codemod( { panic!("Module {} does not belong to app {}", name.as_str(), app) } - let result = - do_diagnostics_one(&analysis, diagnostics_config, file_id, &name, args)? - .map_or(vec![], |x| vec![x]); - - // Print diagnostics for the single file - let mut err_in_diag = false; - let mut module_count = 0; - if args.skip_stream_print() { - any_diagnostics_printed = false; - } else { - for r in &result { - let printed = print_diagnostic_result( - cli, - &analysis, - diagnostics_config, - args, - loaded, - &args.module, - &mut err_in_diag, - &mut module_count, - r, - )?; - any_diagnostics_printed = any_diagnostics_printed || printed; - } - } - - streamed_err_in_diag = err_in_diag; - result + do_parse_one(&analysis, diagnostics_config, file_id, &name, args)? + .map_or(vec![], |x| vec![x]) } (Some(file_id), _) => { panic!("Could not get name from file_id for {file_id:?}") } }; - res + filter_diagnostics( + &analysis, + &args.module, + Some(&diagnostics_config.enabled), + &res, + &FxHashSet::default(), + )? }; - let mut err_in_diag = streamed_err_in_diag; - // At this point, the analysis variable from above is dropped - - // When streaming is disabled (--no-stream) and we're not applying fixes, - // we need to print diagnostics now since they weren't printed during streaming - if args.no_stream && !args.apply_fix && !initial_diags.is_empty() { - let analysis = loaded.analysis(); - let mut module_count = 0; - initial_diags.sort_by(|(a, _, _), (b, _, _)| a.cmp(b)); - for result in &initial_diags { - let printed = print_diagnostic_result( - cli, - &analysis, - diagnostics_config, - args, - loaded, - &args.module, - &mut err_in_diag, - &mut module_count, - result, - )?; - any_diagnostics_printed = any_diagnostics_printed || printed; + if initial_diags.is_empty() { + if args.is_format_normal() { + writeln!(cli, "No diagnostics reported")?; } - } + } else { + initial_diags.sort_by(|(a, _, _), (b, _, _)| a.cmp(b)); + let mut err_in_diag = false; + if args.is_format_json() { + for (_name, file_id, diags) in &initial_diags { + if args.print_diags { + for diag in diags { + // We use JSON output for CI, and want to see warnings too. + // So do not filter on errors only + err_in_diag = true; + let vfs_path = loaded.vfs.file_path(*file_id); + let analysis = loaded.analysis(); + let root_path = &analysis + .project_data(*file_id) + .unwrap_or_else(|_err| panic!("could not find project data")) + .unwrap_or_else(|| panic!("could not find project data")) + .root_dir; + let relative_path = reporting::get_relative_path(root_path, vfs_path); + let prefix = args.prefix.as_ref(); + print_diagnostic_json( + diag, + &analysis, + *file_id, + with_prefix(relative_path, prefix).as_path(), + args.use_cli_severity, + cli, + )?; + } + } + } + } else { + writeln!( + cli, + "Diagnostics reported in {} modules:", + initial_diags.len() + )?; - // Handle apply_fix case separately since it needs to filter diagnostics anyway - if args.apply_fix { - if diagnostics_config.enabled.all_enabled() { + for (name, file_id, diags) in &initial_diags { + writeln!(cli, " {}: {}", name, diags.len())?; + if args.print_diags { + for diag in diags { + if let diagnostics::Severity::Error = diag.severity { + err_in_diag = true; + }; + print_diagnostic( + diag, + &loaded.analysis(), + *file_id, + args.use_cli_severity, + cli, + )?; + } + } + } + } + if args.apply_fix && diagnostics_config.enabled.all_enabled() { bail!( "We cannot apply fixes if all diagnostics enabled. Perhaps provide --diagnostic-filter" ); } - - let mut filtered_diags = { - let analysis = loaded.analysis(); - filter_diagnostics( - &analysis, - &args.module, - Some(&diagnostics_config.enabled), - &initial_diags, - &FxHashSet::default(), - )? - }; - - if filtered_diags.is_empty() { - if args.is_format_normal() { - writeln!(cli, "No diagnostics reported")?; - } - } else { - if args.skip_stream_print() { - filtered_diags.sort_by(|(a, _, _), (b, _, _)| a.cmp(b)); - let module_count: &mut i32 = &mut 0; - let has_diagnostics: &mut bool = &mut false; - if args.is_format_json() { - do_print_diagnostics_json_filtered( - cli, - args, - loaded, - &mut err_in_diag, - module_count, - has_diagnostics, - &filtered_diags, - )?; - } else { - { - // Scope the analysis instance to ensure it's dropped before creating Lints - let analysis = loaded.analysis(); - do_print_diagnostics_filtered( - cli, - &analysis, - args, - loaded, - &mut err_in_diag, - module_count, - has_diagnostics, - &filtered_diags, - )?; - // Analysis is dropped here - } - } - } - + if args.apply_fix && !diagnostics_config.enabled.all_enabled() { let mut changed_files = FxHashSet::default(); let mut lints = Lints::new( &mut loaded.analysis_host, @@ -480,7 +376,7 @@ pub fn do_codemod( &mut loaded.vfs, args, &mut changed_files, - filtered_diags, + initial_diags, ); // We handle the fix application result here, so // the overall status of whether error-severity @@ -492,225 +388,14 @@ pub fn do_codemod( writeln!(cli, "Apply fix failed: {err:#}").ok(); } }; - - if err_in_diag { - bail!("Errors found") - } } - } else { - // Non-apply-fix case: rely on any_diagnostics_printed which is set - // correctly based on filtered diagnostics during streaming/batch printing - if !any_diagnostics_printed { - if args.is_format_normal() { - writeln!(cli, "No diagnostics reported")?; - } - } else if err_in_diag { + if err_in_diag { bail!("Errors found") } } Ok(()) } -#[allow(clippy::too_many_arguments)] -fn print_diagnostic_result( - cli: &mut dyn Cli, - analysis: &Analysis, - config: &DiagnosticsConfig, - args: &Lint, - loaded: &LoadResult, - module: &Option, - err_in_diag: &mut bool, - module_count: &mut i32, - result: &(String, FileId, DiagnosticCollection), -) -> Result { - if args.is_format_json() { - do_print_diagnostic_collection_json( - cli, - analysis, - config, - args, - loaded, - module, - err_in_diag, - module_count, - result, - ) - } else { - do_print_diagnostic_collection( - cli, - analysis, - config, - args, - loaded, - module, - err_in_diag, - module_count, - result, - ) - } -} - -#[allow(clippy::too_many_arguments)] -fn do_print_diagnostic_collection( - cli: &mut dyn Cli, - analysis: &Analysis, - config: &DiagnosticsConfig, - args: &Lint, - loaded: &LoadResult, - module: &Option, - err_in_diag: &mut bool, - module_count: &mut i32, - result: &(String, FileId, DiagnosticCollection), -) -> Result { - let single_result = vec![result.clone()]; - let mut has_diagnostics = false; - if let Ok(filtered) = filter_diagnostics( - analysis, - module, - Some(&config.enabled), - &single_result, - &FxHashSet::default(), - ) { - do_print_diagnostics_filtered( - cli, - analysis, - args, - loaded, - err_in_diag, - module_count, - &mut has_diagnostics, - &filtered, - )?; - } - Ok(has_diagnostics) -} - -#[allow(clippy::too_many_arguments)] -fn do_print_diagnostics_filtered( - cli: &mut dyn Cli, - analysis: &Analysis, - args: &Lint, - loaded: &LoadResult, - err_in_diag: &mut bool, - module_count: &mut i32, - has_diagnostics: &mut bool, - filtered: &[(String, FileId, Vec)], -) -> Result<(), anyhow::Error> { - let _: () = for (name, file_id, diags) in filtered { - if !diags.is_empty() { - *has_diagnostics = true; - if *module_count == 0 { - writeln!(cli, "Diagnostics reported:")?; - } - *module_count += 1; - if !args.print_diags { - writeln!(cli, " {}: {}", name, diags.len())?; - } else { - for diag in diags { - if let diagnostics::Severity::Error = diag.severity { - *err_in_diag = true; - }; - // Get relative path for diagnostic output - let vfs_path = loaded.vfs.file_path(*file_id); - let root_path = &analysis - .project_data(*file_id) - .unwrap_or_else(|_err| panic!("could not find project data")) - .unwrap_or_else(|| panic!("could not find project data")) - .root_dir; - let relative_path = reporting::get_relative_path(root_path, vfs_path); - print_diagnostic( - diag, - analysis, - &loaded.vfs, - *file_id, - Some(relative_path), - args.use_cli_severity, - cli, - )?; - } - } - } - }; - Ok(()) -} - -#[allow(clippy::too_many_arguments)] -fn do_print_diagnostic_collection_json( - cli: &mut dyn Cli, - analysis: &Analysis, - config: &DiagnosticsConfig, - args: &Lint, - loaded: &LoadResult, - module: &Option, - err_in_diag: &mut bool, - module_count: &mut i32, - result: &(String, FileId, DiagnosticCollection), -) -> Result { - let single_result = vec![result.clone()]; - let mut has_diagnostics = false; - if let Ok(filtered) = filter_diagnostics( - analysis, - module, - Some(&config.enabled), - &single_result, - &FxHashSet::default(), - ) { - do_print_diagnostics_json_filtered( - cli, - args, - loaded, - err_in_diag, - module_count, - &mut has_diagnostics, - &filtered, - )?; - } - Ok(has_diagnostics) -} - -fn do_print_diagnostics_json_filtered( - cli: &mut dyn Cli, - args: &Lint, - loaded: &LoadResult, - err_in_diag: &mut bool, - module_count: &mut i32, - has_diagnostics: &mut bool, - filtered: &[(String, FileId, Vec)], -) -> Result<(), anyhow::Error> { - let _: () = for (name, file_id, diags) in filtered { - if !diags.is_empty() { - *has_diagnostics = true; - *module_count += 1; - if !args.print_diags { - writeln!(cli, " {}: {}", name, diags.len())?; - } else { - for diag in diags { - *err_in_diag = true; - - // Get relative path for diagnostic output - let vfs_path = loaded.vfs.file_path(*file_id); - let analysis = loaded.analysis(); - let root_path = &analysis - .project_data(*file_id) - .unwrap_or_else(|_err| panic!("could not find project data")) - .unwrap_or_else(|| panic!("could not find project data")) - .root_dir; - let relative_path = reporting::get_relative_path(root_path, vfs_path); - print_diagnostic_json( - diag, - &analysis, - *file_id, - relative_path, - args.use_cli_severity, - cli, - )?; - } - } - } - }; - Ok(()) -} - fn get_diagnostics_config(args: &Lint) -> Result { let cfg_from_file = if args.read_config || args.config_file.is_some() { read_lint_config_file(&args.project, &args.config_file)? @@ -736,82 +421,12 @@ fn get_diagnostics_config(args: &Lint) -> Result { fn print_diagnostic( diag: &diagnostics::Diagnostic, analysis: &Analysis, - vfs: &Vfs, file_id: FileId, - path: Option<&Path>, use_cli_severity: bool, cli: &mut dyn Cli, ) -> Result<(), anyhow::Error> { let line_index = analysis.line_index(file_id)?; - let diag_str = diag.print(&line_index, use_cli_severity); - if let Some(path) = path { - writeln!(cli, "{}:{}", path.display(), diag_str)?; - } else { - writeln!(cli, " {}", diag_str)?; - } - - // Print any related information, indented - if let Some(related_info) = &diag.related_info { - for info in related_info { - let info_line_index = analysis.line_index(info.file_id)?; - let start = info_line_index.line_col(info.range.start()); - let end = info_line_index.line_col(info.range.end()); - - // Include file identifier if related info is from a different file - if info.file_id != file_id { - let file_identifier = - if let Ok(Some(module_name)) = analysis.module_name(info.file_id) { - // It's a module (.erl file), use module name - format!("[{}]", module_name.as_str()) - } else { - // Not a module (e.g., include file), use relative path - let vfs_path = vfs.file_path(info.file_id); - if let Ok(Some(project_data)) = analysis.project_data(info.file_id) { - let relative_path = - reporting::get_relative_path(&project_data.root_dir, vfs_path); - format!("[{}]", relative_path.display()) - } else { - // Fallback: just show location without file identifier - String::new() - } - }; - - if file_identifier.is_empty() { - writeln!( - cli, - " {}:{}-{}:{}: {}", - start.line + 1, - start.col_utf16 + 1, - end.line + 1, - end.col_utf16 + 1, - info.message - )?; - } else { - writeln!( - cli, - " {} {}:{}-{}:{}: {}", - file_identifier, - start.line + 1, - start.col_utf16 + 1, - end.line + 1, - end.col_utf16 + 1, - info.message - )?; - } - } else { - writeln!( - cli, - " {}:{}-{}:{}: {}", - start.line + 1, - start.col_utf16 + 1, - end.line + 1, - end.col_utf16 + 1, - info.message - )?; - } - } - } - + writeln!(cli, " {}", diag.print(&line_index, use_cli_severity))?; Ok(()) } @@ -996,10 +611,13 @@ impl<'a> Lints<'a> { if self.args.check_eqwalize_all { writeln!(cli, "Running eqwalize-all to check for knock-on problems.")?; } - let diags = { - let analysis = self.analysis_host.analysis(); - do_diagnostics_one(&analysis, self.cfg, file_id, &name, self.args)? - }; + let diags = do_parse_one( + &self.analysis_host.analysis(), + self.cfg, + file_id, + &name, + self.args, + )?; let err_in_diags = diags.iter().any(|(_, file_id, diags)| { let diags = diags.diagnostics_for(*file_id); diags @@ -1010,15 +628,14 @@ impl<'a> Lints<'a> { bail!("Applying change introduces an error diagnostic"); } else { self.changed_files.insert((file_id, name.clone())); - let changed_forms = { - let analysis = self.analysis_host.analysis(); - changes - .iter() - .filter_map(|d| form_from_diff(&analysis, file_id, d)) - .collect::>() - }; + let changes = changes + .iter() + .filter_map(|d| { + form_from_diff(&self.analysis_host.analysis(), file_id, d) + }) + .collect::>(); - for form_id in &changed_forms { + for form_id in &changes { self.changed_forms.insert(InFile::new(file_id, *form_id)); } @@ -1031,24 +648,24 @@ impl<'a> Lints<'a> { .flatten() .collect::>(); - let new_diagnostics = { - let analysis = self.analysis_host.analysis(); - filter_diagnostics(&analysis, &None, None, &new_diags, &self.changed_forms)? - }; + let new_diagnostics = filter_diagnostics( + &self.analysis_host.analysis(), + &None, + None, + &new_diags, + &self.changed_forms, + )?; self.diags = diagnostics_by_file_id(&new_diagnostics); if !self.diags.is_empty() { writeln!(cli, "---------------------------------------------\n")?; writeln!(cli, "New filtered diagnostics")?; - let analysis = self.analysis_host.analysis(); for (file_id, (name, diags)) in &self.diags { writeln!(cli, " {}: {}", name, diags.len())?; for diag in diags.iter() { print_diagnostic( diag, - &analysis, - self.vfs, + &self.analysis_host.analysis(), *file_id, - None, self.args.use_cli_severity, cli, )?; @@ -1120,13 +737,10 @@ impl<'a> Lints<'a> { if format_normal { writeln!(cli, "---------------------------------------------\n")?; writeln!(cli, "Applying fix in module '{name}' for")?; - let analysis = self.analysis_host.analysis(); print_diagnostic( diagnostic, - &analysis, - self.vfs, + &self.analysis_host.analysis(), file_id, - None, self.args.use_cli_severity, cli, )?; @@ -1193,9 +807,7 @@ impl<'a> Lints<'a> { print_diagnostic( &diagnostic, &self.analysis_host.analysis(), - self.vfs, file_id, - None, self.args.use_cli_severity, cli, )?; @@ -1330,6 +942,13 @@ fn get_form_id_at_offset( Some(form_id) } +fn with_prefix(path: &Path, prefix: Option<&String>) -> PathBuf { + match prefix { + Some(prefix) => Path::new(prefix).join(path), + None => path.into(), + } +} + #[cfg(test)] mod tests { use std::ffi::OsString; @@ -1469,11 +1088,11 @@ mod tests { head_mismatcX(0) -> 0. "#, expect![[r#" - module specified: lints - Diagnostics reported: - app_a/src/lints.erl:5:3-5:16::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch' - 4:3-4:16: Mismatched clause name - "#]], + module specified: lints + Diagnostics reported in 1 modules: + lints: 1 + 4:2-4:15::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch' + "#]], expect![""], ); } @@ -1490,8 +1109,9 @@ mod tests { "#, expect![[r#" module specified: lints - Diagnostics reported: - app_a/src/lints.erl:3:3-3:6::[Warning] [L1230] function foo/0 is unused + Diagnostics reported in 1 modules: + lints: 1 + 2:2-2:5::[Warning] [L1230] function foo/0 is unused "#]], expect![""], ); diff --git a/crates/elp/src/bin/main.rs b/crates/elp/src/bin/main.rs index 56535e4492..16b7bbdfbe 100644 --- a/crates/elp/src/bin/main.rs +++ b/crates/elp/src/bin/main.rs @@ -40,7 +40,7 @@ mod erlang_service_cli; mod explain_cli; mod glean; mod lint_cli; -// @fb-only: mod meta_only; +// @fb-only mod reporting; mod shell; mod ssr_cli; @@ -65,14 +65,9 @@ const THREAD_STACK_SIZE: usize = 10_000_000; fn main() { let _timer = timeit!("main"); + let mut cli = cli::Real::default(); let args = args::args().run(); - let use_color = args.should_use_color(); - let mut cli: Box = if use_color { - Box::new(cli::Real::default()) - } else { - Box::new(cli::NoColor::default()) - }; - let res = try_main(&mut *cli, args); + let res = try_main(&mut cli, args); let code = handle_res(res, cli.err()); process::exit(code); } @@ -110,7 +105,7 @@ fn setup_cli_telemetry(args: &Args) { } _ => { // Initialize CLI telemetry, if used - // @fb-only: meta_only::initialize_telemetry(); + // @fb-only } } } @@ -124,7 +119,6 @@ fn try_main(cli: &mut dyn Cli, args: Args) -> Result<()> { setup_thread_pool(); }); let query_config = args.query_config(); - let use_color = args.should_use_color(); match args.command { args::Command::RunServer(_) => run_server(logger)?, args::Command::ParseAll(args) => erlang_service_cli::parse_all(&args, cli, &query_config)?, @@ -142,9 +136,7 @@ fn try_main(cli: &mut dyn Cli, args: Args) -> Result<()> { args::Command::BuildInfo(args) => build_info_cli::save_build_info(args, &query_config)?, args::Command::ProjectInfo(args) => build_info_cli::save_project_info(args, &query_config)?, args::Command::Lint(args) => lint_cli::run_lint_command(&args, cli, &query_config)?, - args::Command::Ssr(ssr_args) => { - ssr_cli::run_ssr_command(&ssr_args, cli, &query_config, use_color)? - } + args::Command::Ssr(args) => ssr_cli::run_ssr_command(&args, cli, &query_config)?, args::Command::GenerateCompletions(args) => { let instructions = args::gen_completions(&args.shell); writeln!(cli, "#Please run this:\n{instructions}")? @@ -288,7 +280,7 @@ mod tests { let (_stdout, stderr, code) = elp(args_vec![ "parse-all", "--project", - "../../test/test_projects/standard", + "../../test_projects/standard", "--to", tmp.path(), ]); @@ -306,7 +298,7 @@ mod tests { fn parse_all_complete(project: &str) -> Result { // Just check the command returns. - let project_path = format!("../../test/test_projects/{project}"); + let project_path = format!("../../test_projects/{project}"); let tmp = Builder::new().prefix("elp_parse_all_").tempdir().unwrap(); let (_stdout, _stderr, code) = elp(args_vec![ "parse-all", @@ -443,34 +435,33 @@ mod tests { }) .unwrap(); - let exp_path = expect_file!(format!( - "../resources/test/{}/{}/{}.pretty", - project, - app, - module.as_str(), - )); - let (stdout, _) = cli.to_strings(); - let otp_version = OTP_VERSION.as_ref().expect("MISSING OTP VERSION"); let otp_version_regex = - regex::bytes::Regex::new(&format!("{}OTP([0-9]+)Only", "@")).unwrap(); + regex::bytes::Regex::new(&format!("{}OTPVersionDependent", "@")) + .unwrap(); let contents = analysis.file_text(file_id).unwrap(); - let otp_version_capture = otp_version_regex - .captures(&contents.as_bytes()[0..(2001.min(contents.len()))]); - if let Some((_, [otp_version_only])) = - otp_version_capture.map(|cap| cap.extract()) - { - if otp_version_only == otp_version.as_bytes() { - assert_normalised_file( - exp_path, - &stdout, - project_path.into(), - false, - ); + let otp_version_dependent = otp_version_regex + .is_match(&contents.as_bytes()[0..(2001.min(contents.len()))]); + let exp_path = { + if otp_version_dependent { + expect_file!(format!( + "../resources/test/{}/{}/{}-OTP-{}.pretty", + project, + app, + module.as_str(), + otp_version, + )) + } else { + expect_file!(format!( + "../resources/test/{}/{}/{}.pretty", + project, + app, + module.as_str(), + )) } - } else { - assert_normalised_file(exp_path, &stdout, project_path.into(), false); - } + }; + let (stdout, _) = cli.to_strings(); + assert_normalised_file(exp_path, &stdout, project_path.into(), false); } } EqwalizerDiagnostics::NoAst { module } => { @@ -605,7 +596,10 @@ mod tests { fn eqwalize_target_diagnostics_match_snapshot_pretty() { if cfg!(feature = "buck") { simple_snapshot( - args_vec!["eqwalize-target", "//standard:app_a",], + args_vec![ + "eqwalize-target", + "//whatsapp/elp/test_projects/standard:app_a", + ], "standard", expect_file!("../resources/test/standard/eqwalize_target_diagnostics.pretty"), true, @@ -669,24 +663,6 @@ mod tests { ); } - #[test_case(false ; "rebar")] - #[test_case(true ; "buck")] - fn parse_all_diagnostics_severity(buck: bool) { - simple_snapshot_expect_error( - args_vec![ - "parse-elp", - "--module", - "diagnostics", - "--severity", - "error" - ], - "diagnostics", - expect_file!("../resources/test/diagnostics/parse_all_diagnostics_error.stdout"), - buck, - None, - ); - } - #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn parse_elp_file_attribute(buck: bool) { @@ -970,9 +946,7 @@ mod tests { assert!(tmp_file.clone().exists()); let content = fs::read_to_string(tmp_file).unwrap(); let mut buck_config = BuckConfig::default(); - buck_config.buck_root = Some(AbsPathBuf::assert_utf8( - current_dir().unwrap().join(path_str.clone()), - )); + buck_config.buck_root = Some(AbsPathBuf::assert_utf8(current_dir().unwrap())); let prelude_cell = get_prelude_cell(&buck_config).expect("could not get prelude"); let prelude_cell = prelude_cell.strip_prefix("/").unwrap(); let content = content.replace(prelude_cell, "/[prelude]/"); @@ -984,13 +958,38 @@ mod tests { Some(AbsPathBuf::assert(Utf8PathBuf::from_path_buf(abs).unwrap())); let content = normalise_prelude_path(content, buck_config); - let content = sort_json(&content); - expect![[r#" { "apps": [ { + "name": "test_exec", + "dir": "/[prelude]//erlang/common_test/test_exec/src", + "src_dirs": [ + "" + ], + "extra_src_dirs": [], + "include_dirs": [], + "macros": {} + }, + { + "name": "diagnostics_app_a", + "dir": "app_a", + "src_dirs": [ + "src" + ], + "extra_src_dirs": [], + "include_dirs": [ + "include" + ], + "macros": { + "COMMON_TEST": "true", + "TEST": "true" + } + }, + { + "name": "app_a_SUITE", "dir": "app_a/test", + "src_dirs": [], "extra_src_dirs": [ "" ], @@ -998,88 +997,61 @@ mod tests { "macros": { "COMMON_TEST": "true", "TEST": "true" - }, - "name": "app_a_SUITE", - "src_dirs": [] + } }, { - "dir": "/[prelude]//erlang/common_test/test_exec/src", - "extra_src_dirs": [], - "include_dirs": [], - "macros": {}, - "name": "test_exec", - "src_dirs": [ - "" - ] - }, - { - "dir": "/[prelude]//erlang/common_test/common", - "extra_src_dirs": [], - "include_dirs": [ - "include" - ], - "macros": {}, "name": "common", + "dir": "/[prelude]//erlang/common_test/common", "src_dirs": [ "src" - ] - }, - { - "dir": "/[prelude]//erlang/common_test/cth_hooks/src", - "extra_src_dirs": [], - "include_dirs": [ - "" ], - "macros": {}, - "name": "cth_hooks", - "src_dirs": [ - "" - ] - }, - { - "dir": "/[prelude]//erlang/shell/src", - "extra_src_dirs": [], - "include_dirs": [], - "macros": {}, - "name": "buck2_shell_utils", - "src_dirs": [ - "" - ] - }, - { - "dir": "app_a", "extra_src_dirs": [], "include_dirs": [ "include" ], - "macros": { - "COMMON_TEST": "true", - "TEST": "true" - }, - "name": "diagnostics_app_a", - "src_dirs": [ - "src" - ] + "macros": {} }, { - "dir": "/[prelude]//erlang/common_test/test_binary/src", + "name": "cth_hooks", + "dir": "/[prelude]//erlang/common_test/cth_hooks/src", + "src_dirs": [ + "" + ], + "extra_src_dirs": [], + "include_dirs": [ + "" + ], + "macros": {} + }, + { + "name": "buck2_shell_utils", + "dir": "/[prelude]//erlang/shell/src", + "src_dirs": [ + "" + ], "extra_src_dirs": [], "include_dirs": [], - "macros": {}, + "macros": {} + }, + { "name": "test_binary", + "dir": "/[prelude]//erlang/common_test/test_binary/src", "src_dirs": [ "" - ] - }, - { - "dir": "/[prelude]//erlang/common_test/test_cli_lib/src", + ], "extra_src_dirs": [], "include_dirs": [], - "macros": {}, + "macros": {} + }, + { "name": "test_cli_lib", + "dir": "/[prelude]//erlang/common_test/test_cli_lib/src", "src_dirs": [ "" - ] + ], + "extra_src_dirs": [], + "include_dirs": [], + "macros": {} } ], "deps": [] @@ -1094,12 +1066,6 @@ mod tests { content.replace(prelude_cell, "/[prelude]/") } - fn sort_json(content: &str) -> String { - let mut json: serde_json::Value = serde_json::from_str(content).unwrap(); - json.sort_all_objects(); - serde_json::to_string_pretty(&json).unwrap() - } - #[test] #[ignore] fn build_info_json_buck_bxl_generated() { @@ -1113,7 +1079,7 @@ mod tests { "--to", tmp_file.clone(), "--project", - path_str.clone() + path_str ]; let (stdout, stderr, code) = elp(args); assert_eq!( @@ -1128,9 +1094,7 @@ mod tests { assert!(tmp_file.clone().exists()); let content = fs::read_to_string(tmp_file).unwrap(); let mut buck_config = BuckConfig::default(); - buck_config.buck_root = Some(AbsPathBuf::assert_utf8( - current_dir().unwrap().join(path_str.clone()), - )); + buck_config.buck_root = Some(AbsPathBuf::assert_utf8(current_dir().unwrap())); let prelude_cell = get_prelude_cell(&buck_config).expect("could not get prelude"); let prelude_cell = prelude_cell.strip_prefix("/").unwrap(); let content = content.replace(prelude_cell, "/[prelude]/"); @@ -1366,7 +1330,6 @@ mod tests { check_lint_fix( args_vec![ "lint", - "--no-stream", "--diagnostic-filter", "W0010", "--experimental", @@ -1394,7 +1357,6 @@ mod tests { check_lint_fix( args_vec![ "lint", - "--no-stream", "--diagnostic-filter", "W0010", "--experimental", @@ -1420,7 +1382,7 @@ mod tests { fn lint_config_file_used(buck: bool) { let tmp_dir = make_tmp_dir(); let tmp_path = tmp_dir.path(); - check_lint_fix_stderr_sorted( + check_lint_fix_stderr( args_vec![ "lint", "--diagnostic-filter", @@ -1454,7 +1416,7 @@ mod tests { "lint", "--experimental", "--config-file", - "../../test/test_projects/linter/does_not_exist.toml" + "../../test_projects/linter/does_not_exist.toml" ], "linter", expect_file!("../resources/test/linter/parse_elp_lint_custom_config_invalid_output.stdout"), @@ -1466,7 +1428,7 @@ mod tests { &[], false, Some(expect![[r#" - unable to read "../../test/test_projects/linter/does_not_exist.toml": No such file or directory (os error 2) + unable to read "../../test_projects/linter/does_not_exist.toml": No such file or directory (os error 2) "#]]), ) .expect("bad test"); @@ -1477,12 +1439,12 @@ mod tests { fn lint_custom_config_file_used(buck: bool) { let tmp_dir = make_tmp_dir(); let tmp_path = tmp_dir.path(); - check_lint_fix_stderr_sorted( + check_lint_fix( args_vec![ "lint", "--experimental", "--config-file", - "../../test/test_projects/linter/elp_lint_test1.toml" + "../../test_projects/linter/elp_lint_test1.toml" ], "linter", expect_file!("../resources/test/linter/parse_elp_lint_custom_config_output.stdout"), @@ -1493,7 +1455,6 @@ mod tests { Path::new("../resources/test/lint/lint_recursive"), &[], false, - None, ) .expect("bad test"); } @@ -1508,7 +1469,7 @@ mod tests { "lint", "--experimental", "--config-file", - "../../test/test_projects/linter/elp_lint_adhoc.toml", + "../../test_projects/linter/elp_lint_adhoc.toml", "--module", "app_b", "--apply-fix", @@ -1532,14 +1493,14 @@ mod tests { #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn lint_diagnostic_ignore(buck: bool) { - simple_snapshot_sorted( + simple_snapshot( args_vec![ "lint", "--experimental", "--diagnostic-ignore", "W0011", "--config-file", - "../../test/test_projects/linter/elp_lint_test_ignore.toml" + "../../test_projects/linter/elp_lint_test_ignore.toml" ], "linter", expect_file!("../resources/test/linter/parse_elp_lint_ignore.stdout"), @@ -1583,7 +1544,7 @@ mod tests { &[], false, Some(expect![[r#" - failed to read "../../test/test_projects/linter_bad_config/.elp_lint.toml":expected a right bracket, found an identifier at line 6 column 4 + failed to read "../../test_projects/linter_bad_config/.elp_lint.toml":expected a right bracket, found an identifier at line 6 column 4 "#]]), ) .expect("bad test"); @@ -1592,8 +1553,8 @@ mod tests { #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn lint_no_diagnostics_filter_all_enabled(buck: bool) { - simple_snapshot_expect_error_sorted( - args_vec!["lint"], + simple_snapshot_expect_error( + args_vec!["lint",], "linter", expect_file!("../resources/test/linter/parse_elp_no_lint_specified_output.stdout"), buck, @@ -1601,24 +1562,10 @@ mod tests { ); } - #[test_case(false ; "rebar")] - #[test_case(true ; "buck")] - fn lint_no_stream_produces_output(buck: bool) { - if otp::supports_eep66_sigils() { - simple_snapshot_expect_error( - args_vec!["lint", "--no-stream"], - "diagnostics", - expect_file!("../resources/test/diagnostics/lint_no_stream.stdout"), - buck, - None, - ); - } - } - #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn lint_no_diagnostics_filter_all_enabled_json(buck: bool) { - simple_snapshot_expect_error_sorted( + simple_snapshot_expect_error( args_vec!["lint", "--format", "json"], "linter", expect_file!("../resources/test/linter/parse_elp_no_lint_specified_json_output.stdout"), @@ -1645,11 +1592,11 @@ mod tests { fn lint_explicit_enable_diagnostic(buck: bool) { let tmp_dir = make_tmp_dir(); let tmp_path = tmp_dir.path(); - check_lint_fix_stderr_sorted( + check_lint_fix_stderr( args_vec![ "lint", "--config-file", - "../../test/test_projects/linter/elp_lint_test2.toml" + "../../test_projects/linter/elp_lint_test2.toml" ], "linter", expect_file!("../resources/test/linter/parse_elp_lint_explicit_enable_output.stdout"), @@ -1672,7 +1619,7 @@ mod tests { fn lint_json_output(buck: bool) { let tmp_dir = make_tmp_dir(); let tmp_path = tmp_dir.path(); - check_lint_fix_stderr_sorted( + check_lint_fix_stderr( args_vec![ "lint", "--diagnostic-filter", @@ -1697,6 +1644,38 @@ mod tests { .expect("bad test"); } + #[test_case(false ; "rebar")] + #[test_case(true ; "buck")] + fn lint_json_output_prefix(buck: bool) { + let tmp_dir = make_tmp_dir(); + let tmp_path = tmp_dir.path(); + check_lint_fix_stderr( + args_vec![ + "lint", + "--diagnostic-filter", + "W0010", + "--experimental", + "--format", + "json", + "--prefix", + "my/prefix" + ], + "linter", + expect_file!("../resources/test/linter/parse_elp_lint_json_output_prefix.stdout"), + 101, + buck, + None, + tmp_path, + Path::new("../resources/test/lint/lint_recursive"), + &[], + false, + Some(expect![[r#" + Errors found + "#]]), + ) + .expect("bad test"); + } + #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn lint_applies_fix_using_to_dir(buck: bool) { @@ -1884,7 +1863,7 @@ mod tests { #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn lint_edoc(buck: bool) { - simple_snapshot_sorted( + simple_snapshot( args_vec![ "lint", "--include-edoc-diagnostics", @@ -1918,7 +1897,7 @@ mod tests { #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn lint_ct_include_tests(buck: bool) { - simple_snapshot_expect_error_sorted( + simple_snapshot_expect_error( args_vec![ "lint", "--include-ct-diagnostics", @@ -1936,8 +1915,8 @@ mod tests { #[test] fn lint_resolves_generated_includes() { if cfg!(feature = "buck") { - simple_snapshot_expect_error_sorted( - args_vec!["lint", "--module", "top_includer",], + simple_snapshot_expect_error( + args_vec!["lint"], "buck_tests_2", expect_file!("../resources/test/buck_tests_2/resolves_generated_includes.stdout"), true, @@ -1952,8 +1931,7 @@ mod tests { simple_snapshot_expect_stderror( args_vec!["lint",], "buck_bad_config", - // @fb-only: expect_file!("../resources/test/buck_bad_config/bxl_error_message.stdout"), - expect_file!("../resources/test/buck_bad_config/bxl_error_message_oss.stdout"), // @oss-only + expect_file!("../resources/test/buck_bad_config/bxl_error_message.stdout"), true, None, true, @@ -1963,12 +1941,11 @@ mod tests { #[test] fn lint_warnings_as_errors() { - simple_snapshot_expect_error_sorted( + simple_snapshot_expect_error( args_vec![ "lint", - "--no-stream" "--config-file", - "../../test/test_projects/linter/elp_lint_warnings_as_errors.toml" + "../../test_projects/linter/elp_lint_warnings_as_errors.toml" ], "linter", expect_file!("../resources/test/linter/warnings_as_errors.stdout"), @@ -1983,7 +1960,7 @@ mod tests { args_vec![ "lint", "--config-file", - "../../test/test_projects/linter/elp_lint_custom_function_matches.toml", + "../../test_projects/linter/elp_lint_custom_function_matches.toml", "--module", "custom_function_matches" ], @@ -1995,29 +1972,12 @@ mod tests { } #[test] - fn lint_unavailable_type() { + fn lint_ssr_from_config() { simple_snapshot( args_vec![ "lint", "--config-file", - "../../test/test_projects/xref/elp_lint_unavailable_type.toml", - "--module", - "unavailable_type" - ], - "xref", - expect_file!("../resources/test/xref/unavailable_type.stdout"), - true, - None, - ) - } - - #[test] - fn lint_ssr_from_config() { - simple_snapshot_sorted( - args_vec![ - "lint", - "--config-file", - "../../test/test_projects/linter/elp_lint_ssr_adhoc.toml", + "../../test_projects/linter/elp_lint_ssr_adhoc.toml", ], "linter", expect_file!("../resources/test/linter/ssr_ad_hoc.stdout"), @@ -2032,7 +1992,7 @@ mod tests { args_vec![ "lint", "--config-file", - "../../test/test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml", + "../../test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml", ], "linter", expect_file!("../resources/test/linter/ssr_ad_hoc_parse_fail.stdout"), @@ -2064,46 +2024,6 @@ mod tests { ) } - #[test] - fn lint_ssr_with_context_and_separator() { - simple_snapshot( - args_vec![ - "--colour", - "never", - "ssr", - "--context", - "2", - "--group-separator", - "====", - "{_@A, _@B}", - ], - "linter", - expect_file!("../resources/test/linter/ssr_context_separator.stdout"), - true, - None, - ) - } - - #[test] - fn lint_ssr_with_context_and_separator_color() { - simple_snapshot( - args_vec![ - "--colour", - "always", - "ssr", - "--context", - "2", - "--group-separator", - "====", - "{_@A, _@B}", - ], - "linter", - expect_file!("../resources/test/linter/ssr_context_separator_color.stdout"), - true, - None, - ) - } - #[test] fn lint_ssr_as_cli_arg_multiple_patterns() { simple_snapshot( @@ -2194,87 +2114,6 @@ mod tests { ) } - #[test] - fn lint_ssr_as_cli_dump_config() { - simple_snapshot( - args_vec!["ssr", "--dump-config", "?BAR(_@AA)", "{4}"], - "linter", - expect_file!("../resources/test/linter/ssr_ad_hoc_cli_dump_config.stdout"), - true, - None, - ) - } - - #[test] - fn lint_ssr_as_cli_dump_config_without_info() { - simple_snapshot( - args_vec!["ssr", "--dump-config", "?BAR(_@AA)", "{4}"], - "linter", - expect_file!("../resources/test/linter/ssr_ad_hoc_cli_dump_config.stdout"), - true, - None, - ) - } - - #[test_case(false ; "rebar")] - #[test_case(true ; "buck")] - fn ssr_exclude_generated_by_default(buck: bool) { - simple_snapshot( - args_vec!["ssr", "--module", "erlang_diagnostics_errors_gen", "ok"], - "diagnostics", - expect_file!("../resources/test/diagnostics/ssr_exclude_generated.stdout"), - buck, - None, - ); - } - - #[test_case(false ; "rebar")] - #[test_case(true ; "buck")] - fn ssr_include_generated_when_requested(buck: bool) { - simple_snapshot( - args_vec![ - "ssr", - "--module", - "erlang_diagnostics_errors_gen", - "--include-generated", - "ok" - ], - "diagnostics", - expect_file!("../resources/test/diagnostics/ssr_include_generated.stdout"), - buck, - None, - ); - } - - #[test_case(false ; "rebar")] - #[test_case(true ; "buck")] - // We cannot use `should_panic` for this test, since the OSS CI runs with the `buck` feature disabled. - // When this happens the test is translated into a no-op, which does not panic. - // TODO(T248259687): Switch to should_panic once Buck2 is available on GitHub. - // Or remove the ignore once hierarchical support is implemented. - #[ignore] // Support for hierarchical config is not implemented yet - fn lint_hierarchical_config_basic(buck: bool) { - simple_snapshot_sorted( - args_vec!["lint", "--read-config"], - "hierarchical_config", - expect_file!("../resources/test/hierarchical_config/basic.stdout"), - buck, - None, - ); - } - - #[test_case(false ; "rebar")] - #[test_case(true ; "buck")] - fn lint_linter_config_basic(buck: bool) { - simple_snapshot_sorted( - args_vec!["lint", "--read-config", "--no-stream"], - "linter_config", - expect_file!("../resources/test/linter_config/basic.stdout"), - buck, - None, - ); - } - #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn eqwalizer_tests_check(buck: bool) { @@ -2406,117 +2245,6 @@ mod tests { } } - #[test_case(false ; "rebar")] - #[test_case(true ; "buck")] - fn eqwalize_with_color_vs_no_color(buck: bool) { - if otp_supported_by_eqwalizer() { - // Test with color (default) - let (mut args_color, _path) = - add_project(args_vec!["eqwalize", "app_a"], "standard", None, None); - if !buck { - args_color.push("--rebar".into()); - } - - // Test without color - let (mut args_no_color, _) = add_project( - args_vec!["--color", "never", "eqwalize", "app_a"], - "standard", - None, - None, - ); - if !buck { - args_no_color.push("--rebar".into()); - } - - let (stdout_color, stderr_color, code_color) = elp(args_color); - let (stdout_no_color, stderr_no_color, code_no_color) = elp(args_no_color); - - // Both should have same exit code - assert_eq!(code_color, code_no_color); - - // Both should have same stderr behavior - if code_color == 0 { - assert!(stderr_color.is_empty()); - assert!(stderr_no_color.is_empty()); - } - - // The content should be similar but no-color version should not contain ANSI escape codes - // ANSI color codes typically start with \x1b[ or \u{1b}[ - let _has_ansi_color = stdout_color.contains('\x1b'); - let has_ansi_no_color = stdout_no_color.contains('\x1b'); - - // With --color never, there should be no ANSI escape sequences - assert!( - !has_ansi_no_color, - "Output with --color never should not contain ANSI escape codes" - ); - - // The outputs should be functionally equivalent when ANSI codes are stripped - let stripped_color = strip_ansi_codes(&stdout_color); - assert_eq!( - stripped_color, stdout_no_color, - "Content should be identical after stripping ANSI codes" - ); - } - } - - #[test_case(false ; "rebar")] - #[test_case(true ; "buck")] - fn eqwalize_with_no_color_env_var(buck: bool) { - if otp_supported_by_eqwalizer() { - // Test with NO_COLOR environment variable set - unsafe { - env::set_var("NO_COLOR", "1"); - } - - let (mut args_no_color_env, _) = - add_project(args_vec!["eqwalize", "app_a"], "standard", None, None); - if !buck { - args_no_color_env.push("--rebar".into()); - } - - let (stdout_no_color_env, stderr_no_color_env, code_no_color_env) = - elp(args_no_color_env); - - // Clean up environment variable - unsafe { - env::remove_var("NO_COLOR"); - } - - // Test with normal color (for comparison) - let (mut args_color, _) = - add_project(args_vec!["eqwalize", "app_a"], "standard", None, None); - if !buck { - args_color.push("--rebar".into()); - } - - let (stdout_color, stderr_color, code_color) = elp(args_color); - - // Both should have same exit code - assert_eq!(code_color, code_no_color_env); - - // Both should have same stderr behavior - if code_color == 0 { - assert!(stderr_color.is_empty()); - assert!(stderr_no_color_env.is_empty()); - } - - // The NO_COLOR env var version should not contain ANSI escape codes - let has_ansi_no_color_env = stdout_no_color_env.contains('\x1b'); - assert!( - !has_ansi_no_color_env, - "Output with NO_COLOR env var should not contain ANSI escape codes" - ); - - // The outputs should be functionally equivalent when ANSI codes are stripped - let stripped_color = strip_ansi_codes(&stdout_color); - assert_eq!( - stripped_color, stdout_no_color_env, - "Content should be identical after stripping ANSI codes" - ); - } - } - // ----------------------------------------------------------------- #[test] @@ -2617,16 +2345,6 @@ mod tests { expected.assert_eq(&stdout); } - #[test] - fn search_help() { - let args = args::args() - .run_inner(Args::from(&["search", "--help"])) - .unwrap_err(); - let expected = expect_file!["../resources/test/ssr_help.stdout"]; - let stdout = args.unwrap_stdout(); - expected.assert_eq(&stdout); - } - #[test] fn build_info_help() { let args = args::args() @@ -2845,61 +2563,6 @@ mod tests { } } - fn simple_snapshot_expect_error_sorted( - args: Vec, - project: &str, - expected: ExpectFile, - buck: bool, - file: Option<&str>, - ) { - if !buck || cfg!(feature = "buck") { - let (mut args, path) = add_project(args, project, file, None); - if !buck { - args.push("--rebar".into()); - } - let (stdout, stderr, code) = elp(args); - assert_eq!( - code, 101, - "Expected exit code 101, got: {code}\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - let sorted_stdout = sort_lines(&stdout); - assert_normalised_file(expected, &sorted_stdout, path, false); - } - } - - fn sort_lines(s: &str) -> String { - let mut lines: Vec<&str> = s.lines().collect(); - lines.sort(); - lines.join("\n") - } - - #[track_caller] - fn simple_snapshot_sorted( - args: Vec, - project: &str, - expected: ExpectFile, - buck: bool, - file: Option<&str>, - ) { - if !buck || cfg!(feature = "buck") { - let (mut args, path) = add_project(args, project, file, None); - if !buck { - args.push("--rebar".into()); - } - let (stdout, stderr, code) = elp(args); - assert_eq!( - code, 0, - "failed with unexpected exit code: got {code} not 0\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - let sorted_stdout = sort_lines(&stdout); - assert_normalised_file(expected, &sorted_stdout, path, false); - assert!( - stderr.is_empty(), - "expected stderr to be empty, got:\n{stderr}" - ) - } - } - fn simple_snapshot_expect_stderror( args: Vec, project: &str, @@ -3033,55 +2696,6 @@ mod tests { Ok(()) } - #[allow(clippy::too_many_arguments)] - fn check_lint_fix_stderr_sorted( - args: Vec, - project: &str, - expected: ExpectFile, - expected_code: i32, - buck: bool, - file: Option<&str>, - actual_dir: &Path, - expected_dir: &Path, - files: &[(&str, &str)], - backup_files: bool, - expected_stderr: Option, - ) -> Result<()> { - if !buck || cfg!(feature = "buck") { - let (mut args, path) = add_project(args, project, file, None); - if !buck { - args.push("--rebar".into()); - } - let orig_files = files.iter().map(|x| x.0).collect::>(); - // Take a backup. The Drop instance will restore at the end - let _backup = if backup_files { - BackupFiles::save_files(project, &orig_files) - } else { - BackupFiles::save_files(project, &[]) - }; - let (stdout, stderr, code) = elp(args); - assert_eq!( - code, expected_code, - "Expected exit code {expected_code}, got: {code}\nstdout:\n{stdout}\nstderr:\n{stderr}" - ); - if let Some(expected_stderr) = expected_stderr { - expected_stderr.assert_eq(&stderr); - } else { - expect![[""]].assert_eq(&stderr); - } - let sorted_stdout = sort_lines(&stdout); - assert_normalised_file(expected, &sorted_stdout, path, false); - for (expected_file, file) in files { - let expected = expect_file!(expected_dir.join(expected_file)); - let actual = actual_dir.join(file); - assert!(actual.exists()); - let content = fs::read_to_string(actual).unwrap(); - expected.assert_eq(content.as_str()); - } - } - Ok(()) - } - fn assert_normalised_file( expected: ExpectFile, actual: &str, @@ -3136,14 +2750,7 @@ mod tests { } fn project_path(project: &str) -> String { - format!("../../test/test_projects/{project}") - } - - fn strip_ansi_codes(s: &str) -> String { - lazy_static! { - static ref ANSI_RE: Regex = Regex::new(r"\x1b\[[0-9;]*m").unwrap(); - } - ANSI_RE.replace_all(s, "").to_string() + format!("../../test_projects/{project}") } struct BackupFiles { diff --git a/crates/elp/src/bin/reporting.rs b/crates/elp/src/bin/reporting.rs index 7ab10459fe..fe38287629 100644 --- a/crates/elp/src/bin/reporting.rs +++ b/crates/elp/src/bin/reporting.rs @@ -227,6 +227,9 @@ impl Reporter for JsonReporter<'_> { diagnostics: &[EqwalizerDiagnostic], ) -> Result<()> { let line_index = self.analysis.line_index(file_id)?; + // Pass include_Tests = false so that errors for tests files that are not opted-in are tagged as + // arc_types::Severity::Disabled and don't break CI. + let eqwalizer_enabled = self.analysis.is_eqwalizer_enabled(file_id, false).unwrap(); let file_path = &self.loaded.vfs.file_path(file_id); let root_path = &self .analysis @@ -235,8 +238,12 @@ impl Reporter for JsonReporter<'_> { .root_dir; let relative_path = get_relative_path(root_path, file_path); for diagnostic in diagnostics { - let diagnostic = - convert::eqwalizer_to_arc_diagnostic(diagnostic, &line_index, relative_path); + let diagnostic = convert::eqwalizer_to_arc_diagnostic( + diagnostic, + &line_index, + relative_path, + eqwalizer_enabled, + ); let diagnostic = serde_json::to_string(&diagnostic)?; writeln!(self.cli, "{diagnostic}")?; } diff --git a/crates/elp/src/bin/shell.rs b/crates/elp/src/bin/shell.rs index 13ff79ed36..84ab218710 100644 --- a/crates/elp/src/bin/shell.rs +++ b/crates/elp/src/bin/shell.rs @@ -157,9 +157,10 @@ impl ShellCommand { } "eqwalize-app" => { let include_generated = options.contains(&"--include-generated"); + let include_tests = options.contains(&"--include-tests"); if let Some(other) = options .into_iter() - .find(|&opt| opt != "--include-generated") + .find(|&opt| opt != "--include-generated" && opt != "--include-tests") { return Err(ShellError::UnexpectedOption( "eqwalize-app".into(), @@ -176,6 +177,7 @@ impl ShellCommand { rebar, app: app.into(), include_generated, + include_tests, bail_on_error: false, }))); } @@ -183,9 +185,10 @@ impl ShellCommand { } "eqwalize-all" => { let include_generated = options.contains(&"--include-generated"); + let include_tests = options.contains(&"--include-tests"); if let Some(other) = options .into_iter() - .find(|&opt| opt != "--include-generated") + .find(|&opt| opt != "--include-generated" && opt != "--include-tests") { return Err(ShellError::UnexpectedOption( "eqwalize-all".into(), @@ -201,6 +204,7 @@ impl ShellCommand { rebar, format: None, include_generated, + include_tests, bail_on_error: false, stats: false, list_modules: false, @@ -222,8 +226,10 @@ COMMANDS: eqwalize Eqwalize specified modules --clause-coverage Use experimental clause coverage checker eqwalize-all Eqwalize all modules in the current project + --include-tests Also eqwalize test modules from project --clause-coverage Use experimental clause coverage checker eqwalize-app Eqwalize all modules in specified application + --include-tests Also eqwalize test modules from project --clause-coverage Use experimental clause coverage checker "; diff --git a/crates/elp/src/bin/ssr_cli.rs b/crates/elp/src/bin/ssr_cli.rs index 36f26d4554..57c4f17928 100644 --- a/crates/elp/src/bin/ssr_cli.rs +++ b/crates/elp/src/bin/ssr_cli.rs @@ -11,12 +11,10 @@ use std::fs; use std::path::Path; use std::str; -use std::thread; use std::time::SystemTime; use anyhow::Result; use anyhow::bail; -use crossbeam_channel::unbounded; use elp::build::load; use elp::build::types::LoadResult; use elp::cli::Cli; @@ -30,9 +28,7 @@ use elp_ide::diagnostics; use elp_ide::diagnostics::DiagnosticsConfig; use elp_ide::diagnostics::FallBackToAll; use elp_ide::diagnostics::LintConfig; -use elp_ide::diagnostics::LintsFromConfig; use elp_ide::diagnostics::MatchSsr; -use elp_ide::elp_ide_db::LineCol; use elp_ide::elp_ide_db::elp_base_db::AbsPath; use elp_ide::elp_ide_db::elp_base_db::FileId; use elp_ide::elp_ide_db::elp_base_db::IncludeOtp; @@ -45,6 +41,7 @@ use elp_project_model::AppType; use elp_project_model::DiscoverConfig; use elp_project_model::buck::BuckQueryConfig; use hir::Semantic; +use indicatif::ParallelProgressIterator; use paths::Utf8PathBuf; use rayon::prelude::ParallelBridge; use rayon::prelude::ParallelIterator; @@ -65,7 +62,6 @@ pub fn run_ssr_command( args: &Ssr, cli: &mut dyn Cli, query_config: &BuckQueryConfig, - use_color: bool, ) -> Result<()> { let start_time = SystemTime::now(); let memory_start = MemoryUsage::now(); @@ -89,17 +85,10 @@ pub fn run_ssr_command( let mut lint_config = LintConfig::default(); for pattern in &args.ssr_specs { let normalized_pattern = normalize_ssr_pattern(pattern); - let severity = if args.dump_config { - // Set the severity so that squiggles are shown in the VS Code UI - Some(diagnostics::Severity::Information) - } else { - None - }; let ssr_lint = diagnostics::Lint::LintMatchSsr(MatchSsr { ssr_pattern: normalized_pattern, message: None, strategy: Some(strategy), - severity, }); lint_config.ad_hoc_lints.lints.push(ssr_lint); } @@ -116,20 +105,15 @@ pub fn run_ssr_command( .set_experimental(false) .set_use_cli_severity(false); - if args.dump_config { - let result = toml::to_string::(&diagnostics_config.lints_from_config)?; - // This is a subsection of .elp_lint.toml, add subsection prefix - let result = result.replace("[[lints]]", "[[ad_hoc_lints.lints]]"); - writeln!(cli, "\n# Add this to your .elp_lint.toml")?; - writeln!(cli, "{}", result)?; - return Ok(()); + if diagnostics_config.enabled.all_enabled() && args.is_format_normal() { + writeln!(cli, "Reporting all diagnostics codes")?; } // Load the project let mut loaded = load_project(args, cli, query_config)?; telemetry::report_elapsed_time("ssr operational", start_time); - let r = run_ssr(cli, &mut loaded, &diagnostics_config, args, use_color); + let r = run_ssr(cli, &mut loaded, &diagnostics_config, args); telemetry::report_elapsed_time("ssr done", start_time); @@ -149,7 +133,6 @@ pub fn run_ssr( loaded: &mut LoadResult, diagnostics_config: &DiagnosticsConfig, args: &Ssr, - use_color: bool, ) -> Result<()> { let analysis = loaded.analysis(); let (file_id, name) = match &args.module { @@ -183,23 +166,8 @@ pub fn run_ssr( }, }; - let mut match_count = 0; - - match (file_id, name) { - (None, _) => { - // Streaming case: process all modules - let project_id = loaded.project_id; - do_parse_all_streaming( - cli, - &analysis, - &project_id, - diagnostics_config, - args, - use_color, - loaded, - &mut match_count, - )?; - } + let mut diags = match (file_id, name) { + (None, _) => do_parse_all(cli, &analysis, &loaded.project_id, diagnostics_config, args)?, (Some(file_id), Some(name)) => { if let Some(app) = &args.app && let Ok(Some(file_app)) = analysis.file_app_name(file_id) @@ -207,171 +175,42 @@ pub fn run_ssr( { panic!("Module {} does not belong to app {}", name.as_str(), app) } - if let Some(diag) = do_parse_one(&analysis, diagnostics_config, file_id, &name, args)? { - match_count = 1; - print_single_result(cli, loaded, &diag, args, use_color)?; - } + do_parse_one(&analysis, diagnostics_config, file_id, &name, args)? + .map_or(vec![], |x| vec![x]) } (Some(file_id), _) => { panic!("Could not get name from file_id for {file_id:?}") } }; - - if match_count == 0 { + if diags.is_empty() { if args.is_format_normal() { writeln!(cli, "No matches found")?; } - } else if args.is_format_normal() { - writeln!(cli, "\nMatches found in {} modules", match_count)?; - } - - Ok(()) -} - -#[allow(clippy::too_many_arguments)] -fn do_parse_all_streaming( - cli: &mut dyn Cli, - analysis: &Analysis, - project_id: &ProjectId, - config: &DiagnosticsConfig, - args: &Ssr, - use_color: bool, - loaded: &mut LoadResult, - match_count: &mut usize, -) -> Result<()> { - let module_index = analysis.module_index(*project_id).unwrap(); - let app_name = args.app.as_ref().map(|name| AppName(name.to_string())); - - // Create a channel for streaming results - let (tx, rx) = unbounded(); - - // Spawn a thread to process modules in parallel and send results - let analysis_clone = analysis.clone(); - let config_clone = config.clone(); - let args_clone = args.clone(); - - // Collect modules into an owned vector - let modules: Vec<_> = module_index - .iter_own() - .map(|(name, source, file_id)| (name.as_str().to_string(), source, file_id)) - .collect(); - - thread::spawn(move || { - modules - .into_iter() - .par_bridge() - .map_with( - (analysis_clone, tx), - |(db, tx), (module_name, _file_source, file_id)| { - if !otp_file_to_ignore(db, file_id) - && db.file_app_type(file_id).ok() != Some(Some(AppType::Dep)) - && (app_name.is_none() - || db.file_app_name(file_id).ok().as_ref() == Some(&app_name)) - && let Ok(Some(result)) = - do_parse_one(db, &config_clone, file_id, &module_name, &args_clone) - { - // Send result through channel - let _ = tx.send(result); - } - }, - ) - .for_each(|_| {}); // Consume the iterator - // Channel is dropped here, signaling end of results - }); - - // Process and print results as they arrive from the channel - for result in rx { - *match_count += 1; - print_single_result(cli, loaded, &result, args, use_color)?; - } - - Ok(()) -} - -fn print_single_result( - cli: &mut dyn Cli, - loaded: &mut LoadResult, - result: &(String, FileId, Vec), - args: &Ssr, - use_color: bool, -) -> Result<()> { - let (name, file_id, diags) = result; - - if args.is_format_json() { - for diag in diags { - let vfs_path = loaded.vfs.file_path(*file_id); - let analysis = loaded.analysis(); - let root_path = &analysis - .project_data(*file_id) - .unwrap_or_else(|_err| panic!("could not find project data")) - .unwrap_or_else(|| panic!("could not find project data")) - .root_dir; - let relative_path = reporting::get_relative_path(root_path, vfs_path); - print_diagnostic_json(diag, &analysis, *file_id, relative_path, false, cli)?; - } } else { - writeln!(cli, " {}: {}", name, diags.len())?; - - // Determine if we should show source context - let show_source = args.show_source - || args.before_context.is_some() - || args.after_context.is_some() - || args.context.is_some() - || args.group_separator.is_some() - || args.no_group_separator; - let (before_lines, after_lines) = calculate_context_lines(args); - let has_context = before_lines > 0 || after_lines > 0; - let group_separator = should_show_group_separator(args, has_context && show_source); - - for (idx, diag) in diags.iter().enumerate() { - // Print group separator before each match (except the first) if showing source with context - if show_source - && idx > 0 - && let Some(ref sep) = group_separator - { - writeln!(cli, "{}", sep)?; - } - // Get relative path for diagnostic output - let vfs_path = loaded.vfs.file_path(*file_id); - let analysis = loaded.analysis(); - let root_path = &analysis - .project_data(*file_id) - .unwrap_or_else(|_err| panic!("could not find project data")) - .unwrap_or_else(|| panic!("could not find project data")) - .root_dir; - let relative_path = reporting::get_relative_path(root_path, vfs_path); - - // Only show path when showing source context - let path_to_show = if show_source { - Some(relative_path) - } else { - None - }; - print_diagnostic(diag, &loaded.analysis(), *file_id, path_to_show, false, cli)?; - - // Only show source context if --show-source or --show-source-markers is set - if show_source { - if use_color { - print_source_with_context( - diag, - &loaded.analysis(), - *file_id, - before_lines, - after_lines, - true, - cli, - )?; - } else { - print_source_with_context_markers( - diag, - &loaded.analysis(), - *file_id, - before_lines, - after_lines, - cli, - )?; + diags.sort_by(|(a, _, _), (b, _, _)| a.cmp(b)); + if args.is_format_json() { + for (_name, file_id, diags) in &diags { + for diag in diags { + // We use JSON output for CI, and want to see warnings too. + // So do not filter on errors only + let vfs_path = loaded.vfs.file_path(*file_id); + let analysis = loaded.analysis(); + let root_path = &analysis + .project_data(*file_id) + .unwrap_or_else(|_err| panic!("could not find project data")) + .unwrap_or_else(|| panic!("could not find project data")) + .root_dir; + let relative_path = reporting::get_relative_path(root_path, vfs_path); + print_diagnostic_json(diag, &analysis, *file_id, relative_path, false, cli)?; + } + } + } else { + writeln!(cli, "Matches found in {} modules:", diags.len())?; + for (name, file_id, diags) in &diags { + writeln!(cli, " {}: {}", name, diags.len())?; + for diag in diags { + print_diagnostic(diag, &loaded.analysis(), *file_id, false, cli)?; } - writeln!(cli)?; } } } @@ -394,6 +233,41 @@ fn load_project( query_config, ) } + +fn do_parse_all( + cli: &dyn Cli, + analysis: &Analysis, + project_id: &ProjectId, + config: &DiagnosticsConfig, + args: &Ssr, +) -> Result)>> { + let module_index = analysis.module_index(*project_id).unwrap(); + let module_iter = module_index.iter_own(); + + let pb = cli.progress(module_iter.len() as u64, "Scanning modules"); + let app_name = args.app.as_ref().map(|name| AppName(name.to_string())); + + Ok(module_iter + .par_bridge() + .progress_with(pb) + .map_with( + analysis.clone(), + |db, (module_name, _file_source, file_id)| { + if !otp_file_to_ignore(db, file_id) + && db.file_app_type(file_id).ok() != Some(Some(AppType::Dep)) + && (app_name.is_none() + || db.file_app_name(file_id).ok().as_ref() == Some(&app_name)) + { + do_parse_one(db, config, file_id, module_name.as_str(), args).unwrap() + } else { + None + } + }, + ) + .flatten() + .collect()) +} + fn do_parse_one( db: &Analysis, config: &DiagnosticsConfig, @@ -401,9 +275,6 @@ fn do_parse_one( name: &str, args: &Ssr, ) -> Result)>> { - if !args.include_generated && db.is_generated(file_id)? { - return Ok(None); - } if !args.include_tests && db.is_test_suite_or_test_helper(file_id)?.unwrap_or(false) { return Ok(None); } @@ -415,6 +286,7 @@ fn do_parse_one( config .lints_from_config .get_diagnostics(&mut diags, &sema, file_id); + sema.parse(file_id); diags })?; @@ -430,17 +302,11 @@ fn print_diagnostic( diag: &diagnostics::Diagnostic, analysis: &Analysis, file_id: FileId, - path: Option<&Path>, use_cli_severity: bool, cli: &mut dyn Cli, ) -> Result<(), anyhow::Error> { let line_index = analysis.line_index(file_id)?; - let diag_str = diag.print(&line_index, use_cli_severity); - if let Some(path) = path { - writeln!(cli, "{}:{}", path.display(), diag_str)?; - } else { - writeln!(cli, " {}", diag_str)?; - } + writeln!(cli, " {}", diag.print(&line_index, use_cli_severity))?; Ok(()) } @@ -464,254 +330,3 @@ fn print_diagnostic_json( )?; Ok(()) } - -/// Print a line with color highlighting -fn print_line_with_color( - line_num: usize, - line_content: &str, - is_match_line: bool, - start: &LineCol, - end: &LineCol, - current_line: u32, - cli: &mut dyn Cli, -) -> Result<(), anyhow::Error> { - // Line number in gray - write!(cli, "\x1b[90m{:4} |\x1b[0m ", line_num)?; - - if !is_match_line { - // Non-match line: print normally - writeln!(cli, "{}", line_content)?; - } else { - // Match line: highlight the matched portion - if current_line == start.line && current_line == end.line { - // Single-line match - let start_col = start.col_utf16 as usize; - let end_col = end.col_utf16 as usize; - - let before = &line_content[..start_col.min(line_content.len())]; - let matched = - &line_content[start_col.min(line_content.len())..end_col.min(line_content.len())]; - let after = &line_content[end_col.min(line_content.len())..]; - - write!(cli, "{}", before)?; - write!(cli, "\x1b[91;1m{}\x1b[0m", matched)?; // Red bold - writeln!(cli, "{}", after)?; - } else if current_line == start.line { - // First line of multi-line match - let start_col = start.col_utf16 as usize; - let before = &line_content[..start_col.min(line_content.len())]; - let matched = &line_content[start_col.min(line_content.len())..]; - - write!(cli, "{}", before)?; - writeln!(cli, "\x1b[91;1m{}\x1b[0m", matched)?; // Red bold - } else if current_line == end.line { - // Last line of multi-line match - let end_col = end.col_utf16 as usize; - let matched = &line_content[..end_col.min(line_content.len())]; - let after = &line_content[end_col.min(line_content.len())..]; - - write!(cli, "\x1b[91;1m{}\x1b[0m", matched)?; // Red bold - writeln!(cli, "{}", after)?; - } else { - // Middle line of multi-line match - writeln!(cli, "\x1b[91;1m{}\x1b[0m", line_content)?; // Red bold - } - } - - Ok(()) -} - -/// Calculate context lines from the new grep-style arguments -fn calculate_context_lines(args: &Ssr) -> (usize, usize) { - // -C/--context takes precedence and sets both before and after - if let Some(context) = args.context { - return (context, context); - } - - // Otherwise use individual before/after values, defaulting to 0 - let before = args.before_context.unwrap_or(0); - let after = args.after_context.unwrap_or(0); - (before, after) -} - -/// Determine if a group separator should be shown -fn should_show_group_separator(args: &Ssr, has_context: bool) -> Option { - // If --no-group-separator is set, don't show separator - if args.no_group_separator { - return None; - } - - // Only show separators if there's context to separate - if !has_context { - return None; - } - - // Use custom separator if provided, otherwise default to "--" - Some( - args.group_separator - .clone() - .unwrap_or_else(|| "--".to_string()), - ) -} - -/// Print source code context with the specified before/after context lines -fn print_source_with_context( - diag: &diagnostics::Diagnostic, - analysis: &Analysis, - file_id: FileId, - before_lines: usize, - after_lines: usize, - use_color: bool, - cli: &mut dyn Cli, -) -> Result<(), anyhow::Error> { - let line_index = analysis.line_index(file_id)?; - let source = &analysis.file_text(file_id)?; - - let range = diag.range; - let start = line_index.line_col(range.start()); - let end = line_index.line_col(range.end()); - - let lines: Vec<&str> = source.lines().collect(); - let total_lines = lines.len(); - - // Calculate the range of lines to display - let first_line = start.line.saturating_sub(before_lines as u32) as usize; - let last_line = ((end.line + after_lines as u32 + 1) as usize).min(total_lines); - - // Display the source context - for line_idx in first_line..last_line { - let line_num = line_idx + 1; - let line_content = lines.get(line_idx).unwrap_or(&""); - - // Check if this line contains part of the match - let is_match_line = line_idx >= start.line as usize && line_idx <= end.line as usize; - - if use_color { - print_line_with_color( - line_num, - line_content, - is_match_line, - &start, - &end, - line_idx as u32, - cli, - )?; - } else { - // Just print the line without any highlighting - write!(cli, "{:4} | ", line_num)?; - writeln!(cli, "{}", line_content)?; - } - } - - Ok(()) -} - -/// Print source code context with text markers -fn print_source_with_context_markers( - diag: &diagnostics::Diagnostic, - analysis: &Analysis, - file_id: FileId, - before_lines: usize, - after_lines: usize, - cli: &mut dyn Cli, -) -> Result<(), anyhow::Error> { - let line_index = analysis.line_index(file_id)?; - let source = &analysis.file_text(file_id)?; - - let range = diag.range; - let start = line_index.line_col(range.start()); - let end = line_index.line_col(range.end()); - - let lines: Vec<&str> = source.lines().collect(); - let total_lines = lines.len(); - - // Calculate the range of lines to display - let first_line = start.line.saturating_sub(before_lines as u32) as usize; - let last_line = ((end.line + after_lines as u32 + 1) as usize).min(total_lines); - - // Display the source context - for line_idx in first_line..last_line { - let line_num = line_idx + 1; - let line_content = lines.get(line_idx).unwrap_or(&""); - - // Check if this line contains part of the match - let is_match_line = line_idx >= start.line as usize && line_idx <= end.line as usize; - - print_line_with_markers( - line_num, - line_content, - is_match_line, - &start, - &end, - line_idx as u32, - cli, - )?; - } - - Ok(()) -} - -/// Print a line with text markers (like diagnostic carets) -fn print_line_with_markers( - line_num: usize, - line_content: &str, - is_match_line: bool, - start: &LineCol, - end: &LineCol, - current_line: u32, - cli: &mut dyn Cli, -) -> Result<(), anyhow::Error> { - // Line number - write!(cli, "{:4} | ", line_num)?; - writeln!(cli, "{}", line_content)?; - - if is_match_line { - // Print marker line with ^^^ under the match - write!(cli, " | ")?; // Indent to match line content - - if current_line == start.line && current_line == end.line { - // Single-line match - let start_col = start.col_utf16 as usize; - let end_col = end.col_utf16 as usize; - let marker_len = (end_col - start_col).max(1); - - // Spaces before the marker - for _ in 0..start_col { - write!(cli, " ")?; - } - // Marker carets - for _ in 0..marker_len { - write!(cli, "^")?; - } - writeln!(cli)?; - } else if current_line == start.line { - // First line of multi-line match - let start_col = start.col_utf16 as usize; - let marker_len = line_content.len().saturating_sub(start_col).max(1); - - for _ in 0..start_col { - write!(cli, " ")?; - } - for _ in 0..marker_len { - write!(cli, "^")?; - } - writeln!(cli)?; - } else if current_line == end.line { - // Last line of multi-line match - let end_col = end.col_utf16 as usize; - - for _ in 0..end_col { - write!(cli, "^")?; - } - writeln!(cli)?; - } else { - // Middle line of multi-line match - for _ in 0..line_content.len() { - write!(cli, "^")?; - } - writeln!(cli)?; - } - } - - Ok(()) -} diff --git a/crates/elp/src/cli.rs b/crates/elp/src/cli.rs index 0678aaebc1..b3070768d6 100644 --- a/crates/elp/src/cli.rs +++ b/crates/elp/src/cli.rs @@ -30,13 +30,18 @@ pub trait Cli: Write + WriteColor { fn err(&mut self) -> &mut dyn Write; } -pub struct StandardCli(StandardStream, Stderr); +pub struct Real(StandardStream, Stderr); -impl StandardCli { - fn new(color_choice: ColorChoice) -> Self { - Self(StandardStream::stdout(color_choice), std::io::stderr()) +impl Default for Real { + fn default() -> Self { + Self( + StandardStream::stdout(ColorChoice::Always), + std::io::stderr(), + ) } +} +impl Real { fn progress_with_style( &self, len: u64, @@ -54,7 +59,7 @@ impl StandardCli { } } -impl Cli for StandardCli { +impl Cli for Real { fn progress(&self, len: u64, prefix: &'static str) -> ProgressBar { self.progress_with_style(len, prefix, " {prefix:25!} {bar} {pos}/{len} {wide_msg}") } @@ -79,63 +84,6 @@ impl Cli for StandardCli { } } -impl Write for StandardCli { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.0.write(buf) - } - - fn flush(&mut self) -> std::io::Result<()> { - self.0.flush() - } -} - -impl WriteColor for StandardCli { - fn supports_color(&self) -> bool { - self.0.supports_color() - } - - fn set_color(&mut self, spec: &ColorSpec) -> std::io::Result<()> { - self.0.set_color(spec) - } - - fn reset(&mut self) -> std::io::Result<()> { - self.0.reset() - } -} - -pub struct Real(StandardCli); -pub struct NoColor(StandardCli); - -impl Default for Real { - fn default() -> Self { - Real(StandardCli::new(ColorChoice::Always)) - } -} - -impl Default for NoColor { - fn default() -> Self { - NoColor(StandardCli::new(ColorChoice::Never)) - } -} - -impl Cli for Real { - fn progress(&self, len: u64, prefix: &'static str) -> ProgressBar { - self.0.progress(len, prefix) - } - - fn simple_progress(&self, len: u64, prefix: &'static str) -> ProgressBar { - self.0.simple_progress(len, prefix) - } - - fn spinner(&self, prefix: &'static str) -> ProgressBar { - self.0.spinner(prefix) - } - - fn err(&mut self) -> &mut dyn Write { - self.0.err() - } -} - impl Write for Real { fn write(&mut self, buf: &[u8]) -> std::io::Result { self.0.write(buf) @@ -160,48 +108,6 @@ impl WriteColor for Real { } } -impl Cli for NoColor { - fn progress(&self, len: u64, prefix: &'static str) -> ProgressBar { - self.0.progress(len, prefix) - } - - fn simple_progress(&self, len: u64, prefix: &'static str) -> ProgressBar { - self.0.simple_progress(len, prefix) - } - - fn spinner(&self, prefix: &'static str) -> ProgressBar { - self.0.spinner(prefix) - } - - fn err(&mut self) -> &mut dyn Write { - self.0.err() - } -} - -impl Write for NoColor { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.0.write(buf) - } - - fn flush(&mut self) -> std::io::Result<()> { - self.0.flush() - } -} - -impl WriteColor for NoColor { - fn supports_color(&self) -> bool { - self.0.supports_color() - } - - fn set_color(&mut self, spec: &ColorSpec) -> std::io::Result<()> { - self.0.set_color(spec) - } - - fn reset(&mut self) -> std::io::Result<()> { - self.0.reset() - } -} - pub struct Fake(Buffer, Vec); impl Default for Fake { diff --git a/crates/elp/src/config.rs b/crates/elp/src/config.rs index 681a022261..2637eae5a2 100644 --- a/crates/elp/src/config.rs +++ b/crates/elp/src/config.rs @@ -30,7 +30,7 @@ use serde::de::DeserializeOwned; use serde_json::json; use crate::from_json; -// @fb-only: use crate::meta_only; +// @fb-only // Defines the server-side configuration of ELP. We generate *parts* // of VS Code's `package.json` config from this. @@ -180,7 +180,7 @@ impl Config { return; } self.data = ConfigData::from_json(json); - // @fb-only: meta_only::harmonise_gks(self); + // @fb-only } pub fn update_gks(&mut self, json: serde_json::Value) { diff --git a/crates/elp/src/convert.rs b/crates/elp/src/convert.rs index c8db07a5d0..3f68488f7d 100644 --- a/crates/elp/src/convert.rs +++ b/crates/elp/src/convert.rs @@ -26,7 +26,6 @@ use elp_ide::elp_ide_db::assists::AssistContextDiagnostic; use elp_ide::elp_ide_db::assists::AssistContextDiagnosticCode; use elp_ide::elp_ide_db::elp_base_db::AbsPath; use elp_ide::elp_ide_db::elp_base_db::AbsPathBuf; -use elp_ide::elp_ide_db::elp_base_db::FileId; use elp_ide::elp_ide_db::elp_base_db::VfsPath; use lsp_types::DiagnosticRelatedInformation; use lsp_types::Location; @@ -68,14 +67,11 @@ pub fn diagnostic_severity(severity: Severity) -> lsp_types::DiagnosticSeverity } } -pub fn ide_to_lsp_diagnostic( +pub fn ide_to_lsp_diagnostic( line_index: &LineIndex, + url: &Url, d: &Diagnostic, - get_file_info: F, -) -> lsp_types::Diagnostic -where - F: Fn(FileId) -> Option<(LineIndex, Url)>, -{ +) -> lsp_types::Diagnostic { let code_description = match &d.code_doc_uri { Some(uri) => match lsp_types::Url::parse(uri) { Ok(href) => Some(lsp_types::CodeDescription { href }), @@ -94,7 +90,7 @@ where code_description, source, message: d.message.clone(), - related_information: from_related(get_file_info, &d.related_info), + related_information: from_related(line_index, url, &d.related_info), tags: d.tag.as_ref().map(lsp_diagnostic_tags), data: None, } @@ -126,11 +122,18 @@ pub fn eqwalizer_to_arc_diagnostic( d: &EqwalizerDiagnostic, line_index: &LineIndex, relative_path: &Path, + eqwalizer_enabled: bool, ) -> arc_types::Diagnostic { let pos = position(line_index, d.range.start()); let line_num = pos.line + 1; let character = Some(pos.character + 1); - let severity = arc_types::Severity::Error; + let severity = if eqwalizer_enabled { + arc_types::Severity::Error + } else { + // We use Severity::Disabled so that diagnostics are reported in cont lint + // but not in CI. + arc_types::Severity::Disabled + }; // formatting: https://fburl.com/max_wiki_link_to_phabricator_rich_text let explanation = match &d.explanation { Some(s) => format!("```\n{s}\n```"), @@ -162,26 +165,22 @@ pub fn eqwalizer_to_arc_diagnostic( ) } -fn from_related( - get_file_info: F, +fn from_related( + line_index: &LineIndex, + url: &Url, r: &Option>, -) -> Option> -where - F: Fn(elp_ide::elp_ide_db::elp_base_db::FileId) -> Option<(LineIndex, Url)>, -{ +) -> Option> { r.as_ref().map(|ri| { ri.iter() - .filter_map(|i| { - // Get the line index and URL for the file that contains the related information - let (line_index, uri) = get_file_info(i.file_id)?; + .map(|i| { let location = Location { - range: range(&line_index, i.range), - uri, + range: range(line_index, i.range), + uri: url.clone(), }; - Some(DiagnosticRelatedInformation { + DiagnosticRelatedInformation { location, message: i.message.clone(), - }) + } }) .collect() }) diff --git a/crates/elp/src/lib.rs b/crates/elp/src/lib.rs index f462141e39..be14930f12 100644 --- a/crates/elp/src/lib.rs +++ b/crates/elp/src/lib.rs @@ -37,7 +37,7 @@ pub mod line_endings; pub mod lsp_ext; mod mem_docs; pub mod memory_usage; -// @fb-only: mod meta_only; +// @fb-only mod op_queue; mod project_loader; pub mod reload; @@ -108,7 +108,7 @@ pub fn otp_file_to_ignore(db: &Analysis, file_id: FileId) -> bool { "redbug_dtop", ] .iter() - // @fb-only: .chain(meta_only::FILES_TO_IGNORE.iter()) + // @fb-only .map(SmolStr::new) .collect(); } @@ -193,7 +193,6 @@ mod tests { ssr_pattern: "ssr: _@A = 10.".to_string(), message: None, strategy: None, - severity: None, }), ], }, diff --git a/crates/elp/src/project_loader.rs b/crates/elp/src/project_loader.rs index 103353e5db..d2c76cd270 100644 --- a/crates/elp/src/project_loader.rs +++ b/crates/elp/src/project_loader.rs @@ -192,7 +192,7 @@ impl ReloadManager { self.get_query_config() } - pub fn get_query_config(&self) -> BuckQueryConfig { + fn get_query_config(&self) -> BuckQueryConfig { if self.buck_quick_start { match self.buck_generated { BuckGenerated::NoLoadDone => BuckQueryConfig::BuckTargetsOnly, diff --git a/crates/elp/src/resources/test/buck_bad_config/bxl_error_message_oss.stdout b/crates/elp/src/resources/test/buck_bad_config/bxl_error_message_oss.stdout deleted file mode 100644 index f5225605a5..0000000000 --- a/crates/elp/src/resources/test/buck_bad_config/bxl_error_message_oss.stdout +++ /dev/null @@ -1 +0,0 @@ -Project Initialisation Failed: invalid or missing buck 2 configuration diff --git a/crates/elp/src/resources/test/buck_tests_2/resolves_generated_includes.stdout b/crates/elp/src/resources/test/buck_tests_2/resolves_generated_includes.stdout index d4954b84ee..7787c17575 100644 --- a/crates/elp/src/resources/test/buck_tests_2/resolves_generated_includes.stdout +++ b/crates/elp/src/resources/test/buck_tests_2/resolves_generated_includes.stdout @@ -1,7 +1,18 @@ - [check_include_separate_1/include/include_with_bug.hrl] 5:14-5:18: E1507: undefined macro 'FOO' - [check_include_separate_1/include/top_includer.hrl] 3:10-3:30: E1516: can't find include file "does_not_exist.hrl" -Diagnostics reported: Reporting all diagnostics codes -check_include/src/top_includer.erl:14:5-14:11::[Error] [E1508] undefined macro 'THIRD/2' -check_include/src/top_includer.erl:6:1-6:67::[Error] [L0000] Issue in included file -module specified: top_includer \ No newline at end of file +Diagnostics reported in 4 modules: + app_a: 3 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 5:9-5:31::[WeakWarning] [W0037] Unspecific include. + 0:8-0:13::[WeakWarning] [W0046] The module is not documented. + auto_gen_a: 2 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 0:8-0:18::[WeakWarning] [W0046] The module is not documented. + eqwalizer: 1 + 1:8-1:17::[WeakWarning] [W0046] The module is not documented. + wa_buck2_module_search: 6 + 19:0-19:18::[WeakWarning] [W0040] The function is non-trivial, exported, but not documented. + 2:8-2:30::[WeakWarning] [W0046] The module is not documented. + 54:18-54:31::[WeakWarning] [W0051] Binary string can be written using sigil syntax. + 56:18-56:28::[WeakWarning] [W0051] Binary string can be written using sigil syntax. + 56:38-56:51::[WeakWarning] [W0051] Binary string can be written using sigil syntax. + 60:30-60:40::[WeakWarning] [W0051] Binary string can be written using sigil syntax. diff --git a/crates/elp/src/resources/test/diagnostics/lint_no_stream.stdout b/crates/elp/src/resources/test/diagnostics/lint_no_stream.stdout deleted file mode 100644 index eef1c92c6d..0000000000 --- a/crates/elp/src/resources/test/diagnostics/lint_no_stream.stdout +++ /dev/null @@ -1,138 +0,0 @@ -Reporting all diagnostics codes -Diagnostics reported: -app_a/src/app_a.erl:52:3-52:23::[Warning] [W0006] this statement has no effect -app_a/src/app_a.erl:3:10-3:21::[WeakWarning] [W0037] Unspecific include. -app_a/src/app_a.erl:27:3-27:9::[Warning] [W0017] Function 'foo:ok/0' is undefined. -app_a/src/app_a.erl:28:4-28:11::[Warning] [W0017] Function 'mod:foo/0' is undefined. -app_a/src/app_a.erl:72:4-72:11::[Warning] [W0017] Function 'foo:bar/2' is undefined. -app_a/src/app_a.erl:37:11-37:28::[Warning] [W0017] Function 'mod_name:fun_name/2' is undefined. -app_a/src/app_a.erl:58:11-58:24::[WeakWarning] [W0051] Binary string can be written using sigil syntax. -app_a/src/app_a.erl:4:1-4:41::[Warning] [W0020] Unused file: inets/include/httpd.hrl -app_a/src/app_a.erl:39:7-39:28::[Error] [L1267] variable 'A' shadowed in 'named fun' -app_a/src/app_a.erl:55:32-55:35::[Error] [L1295] type uri/0 undefined -app_a/src/app_a.erl:56:20-56:26::[Error] [L1295] type binary/1 undefined -app_a/src/app_a.erl:72:3-72:34::[Error] [L1252] record record undefined -app_a/src/app_a.erl:75:5-75:16::[Error] [L1252] record record undefined -app_a/src/app_a.erl:35:1-35:2::[Warning] [L1230] function g/1 is unused -app_a/src/app_a.erl:35:3-35:4::[Warning] [L1268] variable 'A' is unused -app_a/src/app_a.erl:36:3-36:4::[Warning] [L1268] variable 'F' is unused -app_a/src/app_a.erl:37:3-37:4::[Warning] [L1268] variable 'G' is unused -app_a/src/app_a.erl:38:3-38:4::[Warning] [L1268] variable 'H' is unused -app_a/src/app_a.erl:39:3-39:4::[Warning] [L1268] variable 'I' is unused -app_a/src/app_a.erl:39:7-39:28::[Warning] [L1268] variable 'A' is unused -app_a/src/app_a.erl:41:1-41:2::[Warning] [L1230] function h/0 is unused -app_a/src/app_a.erl:45:1-45:2::[Warning] [L1230] function i/0 is unused -app_a/src/app_a.erl:50:1-50:2::[Warning] [L1230] function j/2 is unused -app_a/src/app_a.erl:50:15-50:16::[Warning] [L1268] variable 'A' is unused -app_a/src/app_a.erl:50:23-50:24::[Warning] [L1268] variable 'B' is unused -app_a/src/app_a.erl:55:1-55:46::[Warning] [L1296] type session(_) is unused -app_a/src/app_a.erl:55:1-55:46::[Warning] [L1313] opaque type session(_) is not exported -app_a/src/app_a.erl:56:7-56:13::[Warning] [L1296] type source(_) is unused -app_a/src/app_a.erl:58:1-58:4::[Warning] [L1230] function map/2 is unused -app_a/src/app_a.erl:60:1-60:9::[Warning] [L1230] function with_dot/0 is unused -app_a/src/app_a.erl:62:1-62:9::[Warning] [L1230] function lang_dir/1 is unused -app_a/src/app_a.erl:66:1-66:7::[Warning] [L1230] function escape/1 is unused -app_a/src/app_a.erl:66:13-66:17::[Warning] [L1268] variable 'T' is unused -app_a/src/app_a.erl:67:9-67:25::[Warning] [L1260] record all_configs_file is unused -app_a/src/app_a.erl:71:1-71:2::[Warning] [L1230] function k/0 is unused -app_a/src/app_a.erl:74:1-74:2::[Warning] [L1230] function l/1 is unused -app_a/src/app_a.erl:77:1-77:2::[Warning] [L1230] function m/0 is unused -app_a/src/broken_parse_trans.erl:10:21-10:22::[Error] [L1256] field b undefined in record a -app_a/src/broken_parse_trans.erl:10:32-10:33::[Error] [L1262] variable 'B' is unbound -app_a/src/cascading.erl:9:5-9:6::[Error] [W0004] Missing ')' - 3:10-3:15: function foo/0 undefined - 6:10-6:15: function foo/0 undefined - 8:7-8:10: spec for undefined function foo/0 -app_a/src/diagnostics.erl:3:10-3:27::[WeakWarning] [W0037] Unspecific include. -app_a/src/diagnostics.erl:4:10-4:34::[WeakWarning] [W0037] Unspecific include. -app_a/src/diagnostics.erl:12:8-12:12::[Warning] [W0060] Match on a bound variable -app_a/src/diagnostics.erl:4:1-4:36::[Error] [L0000] Issue in included file - [app_a/include/broken_diagnostics.hrl] 1:8-1:15: P1702: bad attribute - [app_a/include/broken_diagnostics.hrl] 3:6-3:15: P1702: bad attribute -app_a/src/diagnostics.erl:6:31-6:45::[Error] [L1295] type undefined_type/0 undefined -app_a/src/diagnostics.erl:7:1-7:5::[Warning] [L1230] function main/1 is unused -app_a/src/diagnostics.erl:10:1-10:4::[Warning] [L1230] function foo/0 is unused -app_a/src/lint_recursive.erl:23:5-23:14::[Warning] [W0006] this statement has no effect -app_a/src/lint_recursive.erl:6:5-6:7::[Warning] [W0006] this statement has no effect -app_a/src/lint_recursive.erl:14:5-14:12::[Warning] [L1268] variable 'Config1' is unused -app_a/src/lint_recursive.erl:19:5-19:12::[Warning] [L1268] variable 'Config1' is unused -app_a/src/lints.erl:5:1-5:14::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch' - 4:1-4:14: Mismatched clause name -app_a/src/lints.erl:4:22-4:23::[Warning] [W0018] Unexpected ';' -app_a/src/lints.erl:2:10-2:25::[Error] [L1227] function head_mismatch/1 undefined -app_a/src/otp27_docstrings.erl:34:9-34:24::[Warning] [W0002] Unused macro (THIS_IS_THE_END) -app_a/src/otp27_docstrings.erl:24:5-24:6::[Warning] [W0060] Match on a bound variable -app_a/src/otp27_docstrings.erl:30:5-30:6::[Warning] [W0060] Match on a bound variable -app_a/src/otp27_sigils.erl:11:6-11:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:12:5-12:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:13:5-13:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:14:5-14:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:15:5-15:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:17:6-17:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:18:5-18:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:19:5-19:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:20:5-20:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:21:5-21:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:23:6-23:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:24:5-24:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:25:5-25:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:26:5-26:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:27:5-27:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:29:6-29:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:30:5-30:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:31:5-31:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:32:5-32:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:33:5-33:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:35:6-35:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:36:5-36:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:37:5-37:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:38:5-38:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:39:5-39:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:41:6-41:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:42:5-42:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:43:5-43:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:44:5-44:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:45:5-45:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:47:6-47:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:48:5-48:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:49:5-49:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:50:5-50:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:51:5-51:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:53:6-53:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:53:6-53:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:54:5-54:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:54:5-54:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:55:5-55:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:55:5-55:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:56:5-56:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:57:5-57:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:59:6-59:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:60:5-60:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:61:5-61:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:62:5-62:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:63:5-63:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:65:6-65:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:66:5-66:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:67:5-67:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:68:5-68:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:69:5-69:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:76:5-79:8::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:76:5-79:8::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:80:5-84:9::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:80:5-84:9::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:85:5-89:10::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:85:5-89:10::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:90:5-94:11::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:95:5-99:12::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:102:5-102:24::[WeakWarning] [W0051] Binary string can be written using sigil syntax. -app_a/src/otp27_sigils.erl:128:9-128:24::[Warning] [W0002] Unused macro (THIS_IS_THE_END) -app_a/src/otp27_sigils.erl:112:4-112:5::[Error] [P1711] syntax error before: X - 4:15-4:18: function g/0 undefined - 74:7-74:8: spec for undefined function g/0 -app_a/src/otp27_sigils.erl:71:5-71:6::[Warning] [L1268] variable 'X' is unused -app_a/src/otp_7655.erl:5:1-5:28::[Error] [L1201] no module definition -app_a/src/parse_error_a_cascade.erl:10:20-11:1::[Error] [W0004] Missing 'atom' - 6:6-6:11: function bar/0 undefined -app_a/src/suppressed.erl:8:5-8:9::[Warning] [L1268] variable 'Life' is unused -app_a/src/syntax.erl:5:46-5:47::[Error] [P1711] syntax error before: ')' -app_a/src/syntax.erl:11:9-11:10::[Error] [W0004] Missing ')' diff --git a/crates/elp/src/resources/test/diagnostics/lint_report_suppressed.stdout b/crates/elp/src/resources/test/diagnostics/lint_report_suppressed.stdout index 523b8d4bc7..c8cdedb3ea 100644 --- a/crates/elp/src/resources/test/diagnostics/lint_report_suppressed.stdout +++ b/crates/elp/src/resources/test/diagnostics/lint_report_suppressed.stdout @@ -1,3 +1,4 @@ module specified: suppressed -Diagnostics reported: -app_a/src/suppressed.erl:8:5-8:9::[Warning] [W0007] match is redundant +Diagnostics reported in 1 modules: + suppressed: 1 + 7:4-7:8::[Warning] [W0007] match is redundant diff --git a/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics1.stdout b/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics1.stdout index 4b0a155055..a1db95ccbf 100644 --- a/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics1.stdout +++ b/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics1.stdout @@ -1,10 +1,9 @@ module specified: diagnostics Diagnostics reported in 1 modules: - diagnostics: 7 + diagnostics: 6 2:9-2:26::[Hint] [W0037] Unspecific include. - 3:0-3:35::[Error] [L0000] Issue in included file + 3:0-3:0::[Error] [L0000] Issue in included file 3:9-3:33::[Hint] [W0037] Unspecific include. 5:30-5:44::[Error] [L1295] type undefined_type/0 undefined 6:0-6:4::[Warning] [L1230] function main/1 is unused 9:0-9:3::[Warning] [L1230] function foo/0 is unused - 11:7-11:11::[Warning] [W0060] Match on a bound variable diff --git a/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_error.stdout b/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_error.stdout deleted file mode 100644 index 3af8bfb086..0000000000 --- a/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_error.stdout +++ /dev/null @@ -1,5 +0,0 @@ -module specified: diagnostics -Diagnostics reported in 1 modules: - diagnostics: 2 - 3:0-3:35::[Error] [L0000] Issue in included file - 5:30-5:44::[Error] [L1295] type undefined_type/0 undefined diff --git a/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_json.stdout b/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_json.stdout index ede82c7c5f..0c3e5ae9a3 100644 --- a/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_json.stdout +++ b/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_json.stdout @@ -4,4 +4,3 @@ {"path":"app_a/src/diagnostics.erl","line":6,"char":31,"code":"ELP","severity":"error","name":"L1295 (L1295)","original":null,"replacement":null,"description":"type undefined_type/0 undefined\n\nFor more information see: /erlang-error-index/l/L1295","docPath":null} {"path":"app_a/src/diagnostics.erl","line":7,"char":1,"code":"ELP","severity":"warning","name":"L1230 (L1230)","original":null,"replacement":null,"description":"function main/1 is unused\n\nFor more information see: /erlang-error-index/l/L1230","docPath":null} {"path":"app_a/src/diagnostics.erl","line":10,"char":1,"code":"ELP","severity":"warning","name":"L1230 (L1230)","original":null,"replacement":null,"description":"function foo/0 is unused\n\nFor more information see: /erlang-error-index/l/L1230","docPath":null} -{"path":"app_a/src/diagnostics.erl","line":12,"char":8,"code":"ELP","severity":"warning","name":"W0060 (bound_var_in_lhs)","original":null,"replacement":null,"description":"Match on a bound variable\n\nFor more information see: /erlang-error-index/w/W0060","docPath":"website/docs/erlang-error-index/w/W0060.md"} diff --git a/crates/elp/src/resources/test/diagnostics/parse_elp_lint_fix.stdout b/crates/elp/src/resources/test/diagnostics/parse_elp_lint_fix.stdout index f040cee98e..b3a5f365b7 100644 --- a/crates/elp/src/resources/test/diagnostics/parse_elp_lint_fix.stdout +++ b/crates/elp/src/resources/test/diagnostics/parse_elp_lint_fix.stdout @@ -1,12 +1,11 @@ module specified: lints -Diagnostics reported: -app_a/src/lints.erl:5:1-5:14::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch' - 4:1-4:14: Mismatched clause name +Diagnostics reported in 1 modules: + lints: 1 + 4:0-4:13::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch' --------------------------------------------- Applying fix in module 'lints' for - 5:1-5:14::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch' - 4:1-4:14: Mismatched clause name + 4:0-4:13::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch' @@ -1,6 +1,6 @@ -module(lints). -export([head_mismatch/1]). diff --git a/crates/elp/src/resources/test/diagnostics/parse_elp_lint_recursive.stdout b/crates/elp/src/resources/test/diagnostics/parse_elp_lint_recursive.stdout index a88f567370..6bcfecb8a6 100644 --- a/crates/elp/src/resources/test/diagnostics/parse_elp_lint_recursive.stdout +++ b/crates/elp/src/resources/test/diagnostics/parse_elp_lint_recursive.stdout @@ -1,11 +1,12 @@ module specified: lint_recursive -Diagnostics reported: -app_a/src/lint_recursive.erl:19:5-19:12::[Warning] [W0007] match is redundant -app_a/src/lint_recursive.erl:14:5-14:12::[Warning] [W0007] match is redundant +Diagnostics reported in 1 modules: + lint_recursive: 2 + 18:4-18:11::[Warning] [W0007] match is redundant + 13:4-13:11::[Warning] [W0007] match is redundant --------------------------------------------- Applying fix in module 'lint_recursive' for - 19:5-19:12::[Warning] [W0007] match is redundant + 18:4-18:11::[Warning] [W0007] match is redundant @@ -16,7 +16,7 @@ test_foo2(Config) -> @@ -20,12 +21,12 @@ Applying fix in module 'lint_recursive' for New filtered diagnostics lint_recursive: 2 - 14:5-14:12::[Warning] [W0007] match is redundant - 19:5-19:11::[Warning] [W0006] this statement has no effect + 13:4-13:11::[Warning] [W0007] match is redundant + 18:4-18:10::[Warning] [W0006] this statement has no effect --------------------------------------------- Applying fix in module 'lint_recursive' for - 14:5-14:12::[Warning] [W0007] match is redundant + 13:4-13:11::[Warning] [W0007] match is redundant @@ -11,7 +11,7 @@ %% something/0. test_foo(Config) -> @@ -40,12 +41,12 @@ Applying fix in module 'lint_recursive' for New filtered diagnostics lint_recursive: 2 - 19:5-19:11::[Warning] [W0006] this statement has no effect - 14:5-14:11::[Warning] [W0006] this statement has no effect + 18:4-18:10::[Warning] [W0006] this statement has no effect + 13:4-13:10::[Warning] [W0006] this statement has no effect --------------------------------------------- Applying fix in module 'lint_recursive' for - 19:5-19:11::[Warning] [W0006] this statement has no effect + 18:4-18:10::[Warning] [W0006] this statement has no effect @@ -16,7 +16,6 @@ test_foo2(Config) -> @@ -59,12 +60,12 @@ Applying fix in module 'lint_recursive' for New filtered diagnostics lint_recursive: 2 - 17:11-17:17::[Warning] [W0010] this variable is unused - 14:5-14:11::[Warning] [W0006] this statement has no effect + 16:10-16:16::[Warning] [W0010] this variable is unused + 13:4-13:10::[Warning] [W0006] this statement has no effect --------------------------------------------- Applying fix in module 'lint_recursive' for - 17:11-17:17::[Warning] [W0010] this variable is unused + 16:10-16:16::[Warning] [W0010] this variable is unused @@ -14,7 +14,7 @@ Config, clean_mocks(). @@ -79,11 +80,11 @@ Applying fix in module 'lint_recursive' for New filtered diagnostics lint_recursive: 1 - 14:5-14:11::[Warning] [W0006] this statement has no effect + 13:4-13:10::[Warning] [W0006] this statement has no effect --------------------------------------------- Applying fix in module 'lint_recursive' for - 14:5-14:11::[Warning] [W0006] this statement has no effect + 13:4-13:10::[Warning] [W0006] this statement has no effect @@ -11,7 +11,6 @@ %% something/0. test_foo(Config) -> @@ -97,11 +98,11 @@ Applying fix in module 'lint_recursive' for New filtered diagnostics lint_recursive: 1 - 12:10-12:16::[Warning] [W0010] this variable is unused + 11:9-11:15::[Warning] [W0010] this variable is unused --------------------------------------------- Applying fix in module 'lint_recursive' for - 12:10-12:16::[Warning] [W0010] this variable is unused + 11:9-11:15::[Warning] [W0010] this variable is unused @@ -9,7 +9,7 @@ %% We want to check that the "no effect" statements in test_foo/1 and %% test_foo2/1 are removed, but not the ones in clean_mocks/0 and diff --git a/crates/elp/src/resources/test/diagnostics/parse_otp27_docstrings.jsonl b/crates/elp/src/resources/test/diagnostics/parse_otp27_docstrings.jsonl index c34c9037db..5e286c673f 100644 --- a/crates/elp/src/resources/test/diagnostics/parse_otp27_docstrings.jsonl +++ b/crates/elp/src/resources/test/diagnostics/parse_otp27_docstrings.jsonl @@ -1,6 +1,4 @@ module specified: otp27_docstrings Diagnostics reported in 1 modules: - otp27_docstrings: 3 - 23:4-23:5::[Warning] [W0060] Match on a bound variable - 29:4-29:5::[Warning] [W0060] Match on a bound variable + otp27_docstrings: 1 33:8-33:23::[Warning] [W0002] Unused macro (THIS_IS_THE_END) diff --git a/crates/elp/src/resources/test/diagnostics/ssr_exclude_generated.stdout b/crates/elp/src/resources/test/diagnostics/ssr_exclude_generated.stdout deleted file mode 100644 index 1cef26124c..0000000000 --- a/crates/elp/src/resources/test/diagnostics/ssr_exclude_generated.stdout +++ /dev/null @@ -1,2 +0,0 @@ -module specified: erlang_diagnostics_errors_gen -No matches found diff --git a/crates/elp/src/resources/test/diagnostics/ssr_include_generated.stdout b/crates/elp/src/resources/test/diagnostics/ssr_include_generated.stdout deleted file mode 100644 index 2b88b6e10c..0000000000 --- a/crates/elp/src/resources/test/diagnostics/ssr_include_generated.stdout +++ /dev/null @@ -1,5 +0,0 @@ -module specified: erlang_diagnostics_errors_gen - erlang_diagnostics_errors_gen: 1 - 6:5-6:7::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: ok. - -Matches found in 1 modules diff --git a/crates/elp/src/resources/test/eqwalize_all_help.stdout b/crates/elp/src/resources/test/eqwalize_all_help.stdout index 67497c4000..43f66a0a3a 100644 --- a/crates/elp/src/resources/test/eqwalize_all_help.stdout +++ b/crates/elp/src/resources/test/eqwalize_all_help.stdout @@ -1,10 +1,11 @@ -Usage: [--project PROJECT] [--as PROFILE] [[--format FORMAT]] [--rebar] [--bail-on-error] [--stats] [--list-modules] +Usage: [--project PROJECT] [--as PROFILE] [[--format FORMAT]] [--rebar] [--include-tests] [--bail-on-error] [--stats] [--list-modules] Available options: --project Path to directory with project, or to a JSON file (defaults to `.`) --as Rebar3 profile to pickup (default is test) --format Show diagnostics in JSON format --rebar Run with rebar + --include-tests Also eqwalize test modules from project --bail-on-error Exit with a non-zero status code if any errors are found --stats Print statistics when done --list-modules When printing statistics, include the list of modules parsed diff --git a/crates/elp/src/resources/test/eqwalize_app.stdout b/crates/elp/src/resources/test/eqwalize_app.stdout index bb128f249a..eaf1d3126a 100644 --- a/crates/elp/src/resources/test/eqwalize_app.stdout +++ b/crates/elp/src/resources/test/eqwalize_app.stdout @@ -1,4 +1,4 @@ -Usage: [--project PROJECT] [--as PROFILE] [--rebar] [--bail-on-error] +Usage: [--project PROJECT] [--as PROFILE] [--include-tests] [--rebar] [--bail-on-error] Available positional items: app name @@ -6,6 +6,7 @@ Available positional items: Available options: --project Path to directory with project, or to a JSON file (defaults to `.`) --as Rebar3 profile to pickup (default is test) + --include-tests Also eqwalize test modules from project --rebar Run with rebar --bail-on-error Exit with a non-zero status code if any errors are found -h, --help Prints help information diff --git a/crates/elp/src/resources/test/eqwalize_target_help.stdout b/crates/elp/src/resources/test/eqwalize_target_help.stdout index e9a01166dd..eec74e4938 100644 --- a/crates/elp/src/resources/test/eqwalize_target_help.stdout +++ b/crates/elp/src/resources/test/eqwalize_target_help.stdout @@ -1,9 +1,10 @@ -Usage: [--project PROJECT] [--bail-on-error] +Usage: [--project PROJECT] [--include-tests] [--bail-on-error] Available positional items: target, like //erl/chatd/... Available options: --project Path to directory with project, or to a JSON file (defaults to `.`) + --include-tests Also eqwalize test modules from project --bail-on-error Exit with a non-zero status code if any errors are found -h, --help Prints help information diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/any_fun_type.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/any_fun_type.pretty index 69251d1a75..c2a5c42406 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/any_fun_type.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/any_fun_type.pretty @@ -37,6 +37,12 @@ Because in the expression's type: Here the type is: fun((term()) -> term()) Context expects type: fun((term(), term()) -> term()) +------------------------------ Detailed message ------------------------------ + + fun((term()) -> term()) is not compatible with f2() + because + fun((term()) -> term()) is not compatible with fun((term(), term()) -> term()) + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/any_fun_type.erl:64:1 │ @@ -61,6 +67,16 @@ Because in the expression's type: Differs from the expected type: 'a' ) +------------------------------ Detailed message ------------------------------ + + f5('a' | 'b') is not compatible with f4('a') + because + fun((term()) -> 'a' | 'b') is not compatible with f4('a') + because + fun((term()) -> 'a' | 'b') is not compatible with fun((...) -> 'a') + because + 'a' | 'b' is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/any_fun_type.erl:98:20 │ @@ -87,4 +103,14 @@ Because in the expression's type: Differs from the expected type: 'a' ) +------------------------------ Detailed message ------------------------------ + + fun((term()) -> 'a' | 'b') is not compatible with f4('a') + because + fun((term()) -> 'a' | 'b') is not compatible with fun((...) -> 'a') + because + 'a' | 'b' is not compatible with 'a' + because + 'b' is not compatible with 'a' + 7 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/approx.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/approx.pretty index 15655d9cac..0fe7555553 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/approx.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/approx.pretty @@ -60,6 +60,12 @@ Because in the expression's type: However the following candidate: string() Differs from the expected type: 'anything' +------------------------------ Detailed message ------------------------------ + + string() | dynamic() is not compatible with 'anything' + because + string() is not compatible with 'anything' + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/approx.erl:74:1 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports.pretty index 2c9ecb3a1f..f1d2ca6927 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports.pretty @@ -2,8 +2,15 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ check/src/auto_imports.erl:22:20 │ 22 │ erlang:error(ok, ok). - │ ^^ 'ok'. + │ ^^ + │ │ + │ 'ok'. Expression has type: 'ok' Context expected type: [term()] | 'none' + │ + + 'ok' is not compatible with [term()] | 'none' + because + 'ok' is not compatible with [term()] 1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/booleans.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/booleans.pretty index 7227163b41..4407c43d42 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/booleans.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/booleans.pretty @@ -22,4 +22,10 @@ Because in the expression's type: However the following candidate: 'false' Differs from the expected type: 'true' +------------------------------ Detailed message ------------------------------ + + 'false' | 'true' is not compatible with 'true' + because + 'false' is not compatible with 'true' + 2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-26.pretty new file mode 100644 index 0000000000..63be36e638 --- /dev/null +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-26.pretty @@ -0,0 +1,14 @@ +error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation) + ┌─ check/src/callbacks3_neg.erl:12:1 + │ +12 │ -behavior(gen_server). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ Incorrect return type for implementation of gen_server:handle_cast/2. Expected: {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()}, Got: 'wrong_ret'. + │ + + 'wrong_ret' is not compatible with {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()} + because + 'wrong_ret' is not compatible with {'noreply', term()} + +1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-27.pretty new file mode 100644 index 0000000000..63be36e638 --- /dev/null +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-27.pretty @@ -0,0 +1,14 @@ +error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation) + ┌─ check/src/callbacks3_neg.erl:12:1 + │ +12 │ -behavior(gen_server). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ Incorrect return type for implementation of gen_server:handle_cast/2. Expected: {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()}, Got: 'wrong_ret'. + │ + + 'wrong_ret' is not compatible with {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()} + because + 'wrong_ret' is not compatible with {'noreply', term()} + +1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-28.pretty new file mode 100644 index 0000000000..a24c7a6a48 --- /dev/null +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-28.pretty @@ -0,0 +1,14 @@ +error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation) + ┌─ check/src/callbacks3_neg.erl:12:1 + │ +12 │ -behavior(gen_server). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ Incorrect return type for implementation of gen_server:handle_cast/2. Expected: {'noreply', term()} | {'noreply', term(), gen_server:action()} | {'stop', term(), term()}, Got: 'wrong_ret'. + │ + + 'wrong_ret' is not compatible with {'noreply', term()} | {'noreply', term(), gen_server:action()} | {'stop', term(), term()} + because + 'wrong_ret' is not compatible with {'noreply', term()} + +1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg.pretty deleted file mode 100644 index 6cb2012096..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg.pretty +++ /dev/null @@ -1,27 +0,0 @@ -error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation) - ┌─ check/src/callbacks3_neg.erl:13:1 - │ -13 │ -behavior(gen_server). - │ ^^^^^^^^^^^^^^^^^^^^^ Incorrect return type for implementation of gen_server:handle_cast/2. -Expected: {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()} -Got: 'wrong_ret' - -error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation) - ┌─ check/src/callbacks3_neg.erl:13:1 - │ -13 │ -behavior(gen_server). - │ ^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ Incorrect return type for implementation of gen_server:handle_info/2. -Expected: {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()} -Got: {'noreply', 'ok', 'wrong_atom'} - │ - -Because in the expression's type: - { 'noreply', 'ok', - Here the type is: 'wrong_atom' - Context expects type: 'infinity' | number() | 'hibernate' | {'continue', term()} - No candidate matches in the expected union. - } - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates.pretty index a3bc7c96f9..9aff530657 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates.pretty @@ -72,6 +72,17 @@ Because in the expression's type: Differs from the expected type: pid() } +------------------------------ Detailed message ------------------------------ + + {'p', pid() | reference()} is not compatible with {'a', atom()} | {'p', pid()} + because + at tuple index 2: + {'p', pid() | reference()} is not compatible with {'p', pid()} + because + pid() | reference() is not compatible with pid() + because + reference() is not compatible with pid() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/case_predicates.erl:144:10 │ @@ -88,6 +99,14 @@ Because in the expression's type: However the following candidate: 'restarting' Differs from the expected type: {'p', pid()} | 'undefined' +------------------------------ Detailed message ------------------------------ + + 'undefined' | 'restarting' is not compatible with {'p', pid()} | 'undefined' + because + 'restarting' is not compatible with {'p', pid()} | 'undefined' + because + 'restarting' is not compatible with {'p', pid()} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/case_predicates.erl:174:16 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps.pretty index aae5348c54..3143803509 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps.pretty @@ -14,6 +14,10 @@ Because in the expression's type: Context expects type: #{...} The expected map has no corresponding key for: c. +------------------------------ Detailed message ------------------------------ + +key `c` is declared in the former but not in the latter and the latter map has no default association + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/complex_maps.erl:17:21 │ @@ -31,6 +35,15 @@ Because in the expression's type: Context expects type: number() , ... } +------------------------------ Detailed message ------------------------------ + + #{a => 'b', c => 'd'} is not compatible with #{a => 'b', atom() => number()} + because + #{a => 'b', c => 'd'} is not compatible with #{a => 'b', atom() => number()} + key `c` is declared in the former but not in the latter and key `c` isn't compatible with the default association of the latter map + because + 'd' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/complex_maps.erl:20:19 │ @@ -47,6 +60,13 @@ Because in the expression's type: Context expects type: #{...} (no default association) The expected map has no default association while the type of the expression has one. +------------------------------ Detailed message ------------------------------ + + #{a => 'b', atom() => atom()} is not compatible with #{a => 'b', c => 'd'} + key c is not present in the former map but is incompatible with its default association + because + atom() is not compatible with 'd' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/complex_maps.erl:23:19 │ @@ -65,6 +85,13 @@ Because in the expression's type: , ... } The context introduces a new association c => 'd' which is incompatible with the expression's default association. +------------------------------ Detailed message ------------------------------ + + #{a => 'b', atom() => number()} is not compatible with #{a => 'b', c => 'd', atom() => number()} + key c is not present in the former map but is incompatible with its default association + because + number() is not compatible with 'd' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/complex_maps.erl:38:21 │ @@ -81,6 +108,13 @@ Because in the expression's type: Context expects type: #{...} (no default association) The expected map has no default association while the type of the expression has one. +------------------------------ Detailed message ------------------------------ + + #{a => 'b', atom() => atom()} is not compatible with #{a => 'b'} + because + #{a => 'b', atom() => atom()} is not compatible with #{a => 'b'} + the latter map has no default association while the first map has one + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/complex_maps.erl:44:26 │ @@ -97,6 +131,13 @@ Because in the expression's type: Context expects type: #{...} (no default association) The expected map has no default association while the type of the expression has one. +------------------------------ Detailed message ------------------------------ + + #{a => 'b', dynamic(atom()) => atom()} is not compatible with #{a => 'b'} + because + #{a => 'b', dynamic(atom()) => atom()} is not compatible with #{a => 'b'} + the latter map has no default association while the first map has one + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/complex_maps.erl:47:26 │ @@ -113,6 +154,13 @@ Because in the expression's type: Context expects type: #{...} (no default association) The expected map has no default association while the type of the expression has one. +------------------------------ Detailed message ------------------------------ + + #{a => 'b', atom() => dynamic(atom())} is not compatible with #{a => 'b'} + because + #{a => 'b', atom() => dynamic(atom())} is not compatible with #{a => 'b'} + the latter map has no default association while the first map has one + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/complex_maps.erl:56:44 │ @@ -170,6 +218,13 @@ Because in the expression's type: Context expects type: atom() , ... } +------------------------------ Detailed message ------------------------------ + + #{atom() => binary()} is not compatible with #{a => binary(), atom() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/complex_maps.erl:83:28 │ @@ -187,6 +242,13 @@ Because in the expression's type: Context expects type: atom() , ... } +------------------------------ Detailed message ------------------------------ + + #{a := 'b', atom() => binary()} is not compatible with #{a => 'b', {c, d} => atom() | binary(), term() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/complex_maps.erl:86:28 │ @@ -204,6 +266,13 @@ Because in the expression's type: Context expects type: atom() , ... } +------------------------------ Detailed message ------------------------------ + + #{a := 'b', atom() => binary()} is not compatible with #{a => 'b', {c, d} => atom() | binary(), atom() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/complex_maps.erl:89:29 │ @@ -221,4 +290,11 @@ Because in the expression's type: Context expects type: binary() , ... } +------------------------------ Detailed message ------------------------------ + + #{dynamic() => atom()} is not compatible with #{dynamic() => binary()} + the default associations are not compatible + because + atom() is not compatible with binary() + 16 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions.pretty index 2b387ca9b9..396ce7fc52 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions.pretty @@ -15,6 +15,12 @@ Because in the expression's type: Context expects type: atom() ] +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [atom()] + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/comprehensions.erl:40:16 │ @@ -80,6 +86,12 @@ Because in the expression's type: Context expects type: binary() ] +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [binary()] + because + number() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/comprehensions.erl:72:5 │ @@ -258,6 +270,12 @@ Because in the expression's type: Context expects type: binary() ] +------------------------------ Detailed message ------------------------------ + + [atom()] is not compatible with [binary()] + because + atom() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/comprehensions.erl:226:5 │ @@ -275,6 +293,12 @@ Because in the expression's type: Context expects type: 'false' ] +------------------------------ Detailed message ------------------------------ + + ['true'] is not compatible with ['false'] + because + 'true' is not compatible with 'false' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/comprehensions.erl:231:5 │ @@ -292,6 +316,12 @@ Because in the expression's type: Context expects type: 'false' ] +------------------------------ Detailed message ------------------------------ + + ['true'] is not compatible with ['false'] + because + 'true' is not compatible with 'false' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/comprehensions.erl:239:5 │ @@ -309,6 +339,12 @@ Because in the expression's type: Context expects type: atom() ] +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [atom()] + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/comprehensions.erl:267:5 │ @@ -327,6 +363,14 @@ Because in the expression's type: Differs from the expected type: binary() ] +------------------------------ Detailed message ------------------------------ + + [binary() | 'undefined'] is not compatible with [binary()] + because + binary() | 'undefined' is not compatible with binary() + because + 'undefined' is not compatible with binary() + error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) ┌─ check/src/comprehensions.erl:386:9 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/contravariant.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/contravariant.pretty index f228f5cd50..69c58c0e77 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/contravariant.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/contravariant.pretty @@ -16,4 +16,14 @@ Because in the expression's type: Differs from the expected type: 'a' ) -> 'ok') +------------------------------ Detailed message ------------------------------ + + ref_contravariant('a') is not compatible with ref_contravariant_ab() + because + contravariant('a') is not compatible with ref_contravariant_ab() + because + fun(('a') -> 'ok') is not compatible with ref_contravariant_ab() + because + fun(('a') -> 'ok') is not compatible with ref_contravariant('a' | 'b') + 1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/custom.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-26.pretty similarity index 77% rename from crates/elp/src/resources/test/eqwalizer_tests/check/custom.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-26.pretty index efc8c47aa0..370f7689e9 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/custom.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-26.pretty @@ -37,6 +37,12 @@ Because in the expression's type: However the following candidate: [dynamic()] Differs from the expected type: tuple() +------------------------------ Detailed message ------------------------------ + + {atom(), string()} | [dynamic()] is not compatible with tuple() + because + [dynamic()] is not compatible with tuple() + error: index_out_of_bounds (See https://fb.me/eqwalizer_errors#index_out_of_bounds) ┌─ check/src/custom.erl:48:5 │ @@ -68,6 +74,12 @@ Because in the expression's type: However the following candidate: number() Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + atom() | number() is not compatible with atom() + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:68:5 │ @@ -84,6 +96,12 @@ Because in the expression's type: However the following candidate: number() Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + dynamic() | number() is not compatible with atom() + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:86:5 │ @@ -100,6 +118,12 @@ Because in the expression's type: However the following candidate: string() Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + 'foo' | 'ok' | 'error' | number() | string() is not compatible with atom() + because + string() is not compatible with atom() + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/custom.erl:91:1 │ @@ -178,6 +202,12 @@ Because in the expression's type: However the following candidate: number() Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with atom() + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:200:5 │ @@ -194,6 +224,12 @@ Because in the expression's type: However the following candidate: number() Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with atom() + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:206:5 │ @@ -213,6 +249,15 @@ Because in the expression's type: Differs from the expected type: number() } +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {atom(), 'undefined' | number()} is not compatible with {atom(), number()} + because + 'undefined' | number() is not compatible with number() + because + 'undefined' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:221:27 │ @@ -229,6 +274,14 @@ Because in the expression's type: However the following candidate: 'c_v' Differs from the expected type: 'a_v' | 'b_v' +------------------------------ Detailed message ------------------------------ + + 'a_v' | 'c_v' is not compatible with 'a_v' | 'b_v' + because + 'c_v' is not compatible with 'a_v' | 'b_v' + because + 'c_v' is not compatible with 'a_v' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:233:27 │ @@ -245,6 +298,14 @@ Because in the expression's type: However the following candidate: 'c_v' Differs from the expected type: 'a_v' | 'b_v' | 'undefined' +------------------------------ Detailed message ------------------------------ + + 'undefined' | 'a_v' | 'c_v' is not compatible with 'a_v' | 'b_v' | 'undefined' + because + 'c_v' is not compatible with 'a_v' | 'b_v' | 'undefined' + because + 'c_v' is not compatible with 'a_v' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:309:5 │ @@ -301,13 +362,28 @@ Because in the expression's type: However the following candidate: 'a' Differs from the expected type: #{term() => term()} | maps:iterator() +------------------------------ Detailed message ------------------------------ + + #{K => V} | 'a' is not compatible with #{term() => term()} | maps:iterator() + because + 'a' is not compatible with #{term() => term()} | maps:iterator() + because + 'a' is not compatible with #{term() => term()} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:425:20 │ 425 │ maps:filter(F, non_kv), - │ ^^^^^^ 'non_kv'. + │ ^^^^^^ + │ │ + │ 'non_kv'. Expression has type: 'non_kv' Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:454:5 @@ -327,6 +403,13 @@ Because in the expression's type: Context expects type: boolean() , ... } +------------------------------ Detailed message ------------------------------ + + #{number() => pid()} is not compatible with #{number() => boolean()} + the default associations are not compatible + because + pid() is not compatible with boolean() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:474:14 │ @@ -368,13 +451,29 @@ Because in the expression's type: Context expects type: 'a' , ... } +------------------------------ Detailed message ------------------------------ + + #{a := boolean(), b := boolean()} is not compatible with #{a => 'a', b => 'b'} + because + at key `a`: + #{a := boolean(), b := boolean()} is not compatible with #{a => 'a', b => 'b'} + because + boolean() is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:503:17 │ 503 │ maps:map(F, non_kv), - │ ^^^^^^ 'non_kv'. + │ ^^^^^^ + │ │ + │ 'non_kv'. Expression has type: 'non_kv' Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) ┌─ check/src/custom.erl:538:9 @@ -403,6 +502,14 @@ Because in the expression's type: No candidate matches in the expected union. ] +------------------------------ Detailed message ------------------------------ + + [[[]]] is not compatible with [number() | 'a' | 'b'] + because + [[]] is not compatible with number() | 'a' | 'b' + because + [[]] is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:545:28 │ @@ -424,6 +531,14 @@ Because in the expression's type: ] ] +------------------------------ Detailed message ------------------------------ + + [[[[]]]] is not compatible with [[[]]] + because + [[[]]] is not compatible with [[]] + because + [[]] is not compatible with [] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:552:5 │ @@ -440,9 +555,16 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ check/src/custom.erl:555:9 │ 555 │ non_kv - │ ^^^^^^ 'non_kv'. + │ ^^^^^^ + │ │ + │ 'non_kv'. Expression has type: 'non_kv' Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/custom.erl:560:1 @@ -484,6 +606,12 @@ Because in the expression's type: However the following candidate: [] Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + [] | atom() is not compatible with atom() + because + [] is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:601:9 │ @@ -554,13 +682,30 @@ Because in the expression's type: Differs from the expected type: binary() ] +------------------------------ Detailed message ------------------------------ + + [number() | binary() | atom()] is not compatible with [binary()] | [number()] | [atom()] + because + [number() | binary() | atom()] is not compatible with [binary()] + because + number() | binary() | atom() is not compatible with binary() + because + number() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:671:41 │ 671 │ maps_to_list_7_neg(Num) -> maps:to_list(Num). - │ ^^^ Num. + │ ^^^ + │ │ + │ Num. Expression has type: number() Context expected type: #{term() => term()} | maps:iterator() + │ + + number() is not compatible with #{term() => term()} | maps:iterator() + because + number() is not compatible with #{term() => term()} error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:675:25 @@ -578,6 +723,13 @@ Because in the expression's type: Context expects type: #{...} (no default association) The expected map has no default association while the type of the expression has one. +------------------------------ Detailed message ------------------------------ + + #{'b' | 'a' | 'c' => number() | string() | atom()} is not compatible with #{a => string(), b => number(), c => atom()} + key a is not present in the former map but is incompatible with its default association + because + number() | string() | atom() is not compatible with string() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:679:25 │ @@ -594,6 +746,13 @@ Because in the expression's type: Context expects type: #{...} (no default association) The expected map has no default association while the type of the expression has one. +------------------------------ Detailed message ------------------------------ + + #{'b' | 'a' | 'c' => number() | string() | atom()} is not compatible with #{a => string(), b => number() | boolean(), c => atom()} + key a is not present in the former map but is incompatible with its default association + because + number() | string() | atom() is not compatible with string() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:683:25 │ @@ -610,6 +769,10 @@ Because in the expression's type: Context expects type: #{a := ..., b := ..., ...} The type of the expression is missing the following required keys: a, b. +------------------------------ Detailed message ------------------------------ + +keys `a`, `b` are declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:697:44 │ @@ -634,6 +797,13 @@ Because in the expression's type: Context expects type: #{a := ..., b := ..., ...} The type of the expression is missing the following required keys: a, b. +------------------------------ Detailed message ------------------------------ + + #{'a' | 'b' => atom() | number()} is not compatible with #{a := atom(), b := number()} | #{a := atom()} + because + #{'a' | 'b' => atom() | number()} is not compatible with #{a := atom(), b := number()} + keys `a`, `b` are declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:721:9 │ @@ -652,6 +822,14 @@ Because in the expression's type: No candidate matches in the expected union. ) +------------------------------ Detailed message ------------------------------ + + fun((binary()) -> [number()]) is not compatible with fun((number()) -> boolean() | {'true', term()}) + because + [number()] is not compatible with boolean() | {'true', term()} + because + [number()] is not compatible with 'false' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:739:20 │ @@ -668,6 +846,12 @@ Because in the expression's type: Context expects type: 'false' | 'true' | {'true', term()} No candidate matches in the expected union. +------------------------------ Detailed message ------------------------------ + + 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with 'false' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:749:9 │ @@ -692,6 +876,14 @@ Because in the expression's type: However the following candidate: 'wrong_ret' Differs from the expected type: 'false' | 'true' | {'true', term()} +------------------------------ Detailed message ------------------------------ + + {'true', 'a'} | 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with 'false' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:827:9 │ @@ -710,6 +902,16 @@ Because in the expression's type: Differs from the expected type: 'false' | 'true' | ['a' | 'b'] ) +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'true' | 'wrong_ret') is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'true' | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:829:20 │ @@ -726,6 +928,12 @@ Because in the expression's type: Context expects type: 'false' | 'true' | ['a' | 'b'] No candidate matches in the expected union. +------------------------------ Detailed message ------------------------------ + + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:837:9 │ @@ -743,6 +951,15 @@ Because in the expression's type: Differs from the expected type: 'false' | 'true' | [Item] ) +------------------------------ Detailed message ------------------------------ + + fun((dynamic()) -> {'true', 'a'} | 'true') is not compatible with fun((Item) -> boolean() | [Item]) + because + {'true', 'a'} | 'true' is not compatible with boolean() | [Item] + because + {'true', 'a'} is not compatible with boolean() | [Item] + expected union does not contain any tuple type of size 2 + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:837:20 │ @@ -759,6 +976,10 @@ Because in the expression's type: Context expects type: 'false' | 'true' | [dynamic()] No candidate matches in the expected union. +------------------------------ Detailed message ------------------------------ + +expected union does not contain any tuple type of size 2 + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:839:9 │ @@ -774,6 +995,12 @@ Because in the expression's type: Here the type is: 'not_a_queue' Context expects type: {[Item], [Item]} +------------------------------ Detailed message ------------------------------ + + 'not_a_queue' is not compatible with queue:queue(Item) + because + 'not_a_queue' is not compatible with {[Item], [Item]} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:839:9 │ @@ -789,6 +1016,12 @@ Because in the expression's type: Here the type is: 'not_a_queue' Context expects type: {[dynamic()], [dynamic()]} +------------------------------ Detailed message ------------------------------ + + 'not_a_queue' is not compatible with queue:queue(dynamic()) + because + 'not_a_queue' is not compatible with {[dynamic()], [dynamic()]} + error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) ┌─ check/src/custom.erl:846:9 │ @@ -820,6 +1053,15 @@ Because in the expression's type: Differs from the expected type: 'false' | 'true' | ['a' | 'b'] ) +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'false' | {'true', 'a'}) is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'false' | {'true', 'a'} is not compatible with boolean() | ['a' | 'b'] + because + {'true', 'a'} is not compatible with boolean() | ['a' | 'b'] + expected union does not contain any tuple type of size 2 + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:857:20 │ @@ -836,6 +1078,10 @@ Because in the expression's type: Context expects type: 'false' | 'true' | ['a' | 'b'] No candidate matches in the expected union. +------------------------------ Detailed message ------------------------------ + +expected union does not contain any tuple type of size 2 + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:873:9 │ @@ -858,6 +1104,16 @@ Because in the expression's type: Differs from the expected type: 'false' | 'true' | ['a' | 'b'] ) +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'wrong_ret') is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:881:17 │ @@ -874,6 +1130,14 @@ Because in the expression's type: However the following candidate: 'wrong_ret' Differs from the expected type: 'false' | 'true' | ['a' | 'b'] +------------------------------ Detailed message ------------------------------ + + ['a'] | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:891:9 │ @@ -892,6 +1156,14 @@ Because in the expression's type: No candidate matches in the expected union. ) +------------------------------ Detailed message ------------------------------ + + fun((string()) -> atom()) is not compatible with fun((dynamic()) -> boolean() | [dynamic()]) + because + atom() is not compatible with boolean() | [dynamic()] + because + atom() is not compatible with 'false' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:891:9 │ @@ -910,6 +1182,14 @@ Because in the expression's type: No candidate matches in the expected union. ) +------------------------------ Detailed message ------------------------------ + + fun((string()) -> atom()) is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + atom() is not compatible with boolean() | ['a' | 'b'] + because + atom() is not compatible with 'false' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:900:9 │ @@ -927,6 +1207,12 @@ Because in the expression's type: Context expects type: boolean() | [atom()] ) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:900:9 │ @@ -944,6 +1230,12 @@ Because in the expression's type: Context expects type: boolean() | [dynamic(atom())] ) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:909:9 │ @@ -961,6 +1253,12 @@ Because in the expression's type: Context expects type: boolean() | [atom()] ) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:909:9 │ @@ -978,6 +1276,12 @@ Because in the expression's type: Context expects type: boolean() | [dynamic(atom())] ) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:919:9 │ @@ -995,6 +1299,12 @@ Because in the expression's type: Context expects type: boolean() | [atom()] ) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:919:9 │ @@ -1012,6 +1322,12 @@ Because in the expression's type: Context expects type: boolean() | [dynamic(atom())] ) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/custom.erl:925:1 │ @@ -1040,6 +1356,12 @@ Because in the expression's type: Context expects type: boolean() | [atom()] ) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:927:9 │ @@ -1057,6 +1379,12 @@ Because in the expression's type: Context expects type: boolean() | [dynamic(atom())] ) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:955:5 │ @@ -1106,6 +1434,12 @@ Because in the expression's type: Context expects type: tuple() ] +------------------------------ Detailed message ------------------------------ + + ['non_tuple'] is not compatible with [tuple()] + because + 'non_tuple' is not compatible with tuple() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:975:5 │ @@ -1206,6 +1540,14 @@ Because in the expression's type: Differs from the expected type: number() ] +------------------------------ Detailed message ------------------------------ + + ['a' | number()] is not compatible with [number()] + because + 'a' | number() is not compatible with number() + because + 'a' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1042:15 │ @@ -1250,17 +1592,31 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ check/src/custom.erl:1100:5 │ 1100 │ proplists:get_value(k, L). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). Expression has type: term() Context expected type: pid() | 'undefined' + │ + + term() is not compatible with pid() | 'undefined' + because + term() is not compatible with pid() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1106:5 │ 1106 │ proplists:get_value(k, L). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). Expression has type: term() Context expected type: pid() | 'undefined' | 'v' + │ + + term() is not compatible with pid() | 'undefined' | 'v' + because + term() is not compatible with pid() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1111:5 @@ -1274,17 +1630,31 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ check/src/custom.erl:1117:5 │ 1117 │ proplists:get_value(k, L, 3). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', L, 3). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L, 3). Expression has type: term() Context expected type: pid() | number() + │ + + term() is not compatible with pid() | number() + because + term() is not compatible with pid() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1123:5 │ 1123 │ proplists:get_value(k, L, my_default). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', L, 'my_default'). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L, 'my_default'). Expression has type: term() Context expected type: 'v1' | 'v2' | 'my_default' + │ + + term() is not compatible with 'v1' | 'v2' | 'my_default' + because + term() is not compatible with 'v1' error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1129:5 @@ -1352,6 +1722,14 @@ Because in the expression's type: No candidate matches in the expected union. ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid() | 'default'] + because + term() is not compatible with pid() | 'default' + because + term() is not compatible with pid() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1166:5 │ @@ -1370,6 +1748,14 @@ Because in the expression's type: No candidate matches in the expected union. ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid() | 'default' | 'v'] + because + term() is not compatible with pid() | 'default' | 'v' + because + term() is not compatible with pid() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1171:5 │ @@ -1387,6 +1773,12 @@ Because in the expression's type: Context expects type: pid() ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid()] + because + term() is not compatible with pid() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1176:5 │ @@ -1454,6 +1846,12 @@ Because in the expression's type: Context expects type: 'c' ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['c'] + because + term() is not compatible with 'c' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1197:5 │ @@ -1472,6 +1870,14 @@ Because in the expression's type: No candidate matches in the expected union. ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['a' | 'b' | 'c'] + because + term() is not compatible with 'a' | 'b' | 'c' + because + term() is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1202:24 │ @@ -1497,21 +1903,41 @@ Because in the expression's type: Context expects type: 'a' ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['a'] + because + term() is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1215:5 │ 1215 │ proplists:get_value(k, L). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). Expression has type: term() Context expected type: 'a' | pid() + │ + + term() is not compatible with 'a' | pid() + because + term() is not compatible with 'a' error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1220:5 │ 1220 │ proplists:get_value(k, b). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', 'b'). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', 'b'). Expression has type: term() Context expected type: 'a' | pid() + │ + + term() is not compatible with 'a' | pid() + because + term() is not compatible with 'a' error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1220:28 @@ -1561,6 +1987,12 @@ Because in the expression's type: However the following candidate: tuple() Differs from the expected type: 'none' +------------------------------ Detailed message ------------------------------ + + 'none' | tuple() is not compatible with 'none' + because + tuple() is not compatible with 'none' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1252:29 │ @@ -1633,6 +2065,17 @@ Because in the expression's type: ] , [term()]} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[[term()]], [term()]} is not compatible with {[plist('a', 'b')], plist('a', 'b')} + because + [[term()]] is not compatible with [plist('a', 'b')] + because + [term()] is not compatible with plist('a', 'b') + because + [term()] is not compatible with ['a' | {'a', 'b'}] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1315:21 │ @@ -1677,25 +2120,46 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ check/src/custom.erl:1363:5 │ 1363 │ proplists:get_value(a, [a]). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('a', ['a']). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('a', ['a']). Expression has type: term() Context expected type: 'true' | 'undefined' + │ + + term() is not compatible with 'true' | 'undefined' + because + term() is not compatible with 'true' error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1368:5 │ 1368 │ proplists:get_value(X, [a]). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value(X, ['a']). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value(X, ['a']). Expression has type: term() Context expected type: 'true' | 'undefined' + │ + + term() is not compatible with 'true' | 'undefined' + because + term() is not compatible with 'true' error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1373:5 │ 1373 │ proplists:get_value(a, [a], b). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('a', ['a'], 'b'). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('a', ['a'], 'b'). Expression has type: term() Context expected type: 'true' | 'b' + │ + + term() is not compatible with 'true' | 'b' + because + term() is not compatible with 'true' error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1416:5 @@ -1730,6 +2194,12 @@ Because in the expression's type: Context expects type: tuple() ] +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [tuple()] + because + number() is not compatible with tuple() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1448:5 │ @@ -1752,6 +2222,14 @@ Because in the expression's type: Differs from the expected type: number() ] +------------------------------ Detailed message ------------------------------ + + [string() | number()] is not compatible with [number()] + because + string() | number() is not compatible with number() + because + string() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1482:5 │ @@ -1895,6 +2373,17 @@ Because in the expression's type: , A} ] +------------------------------ Detailed message ------------------------------ + + [{A, B} | {B, A}] is not compatible with [{A, B}] + because + {A, B} | {B, A} is not compatible with {A, B} + because + at tuple index 1: + {B, A} is not compatible with {A, B} + because + B is not compatible with A + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1757:5 │ @@ -1915,6 +2404,10 @@ Because in the expression's type: Context expects type: #{...} The expected map has no corresponding key for: a. +------------------------------ Detailed message ------------------------------ + +key `a` is declared in the former but not in the latter and the latter map has no default association + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1769:18 │ @@ -1958,6 +2451,10 @@ Because in the expression's type: Context expects type: #{b := ..., ...} The type of the expression is missing the following required keys: b. +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1826:5 │ @@ -1975,6 +2472,10 @@ Because in the expression's type: Context expects type: #{b := ..., ...} The type of the expression is missing the following required keys: b. +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1827:12 │ @@ -2000,6 +2501,10 @@ Because in the expression's type: Context expects type: #{b := ..., ...} The type of the expression is missing the following required keys: b. +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1854:5 │ @@ -2020,9 +2525,16 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ check/src/custom.erl:1916:23 │ 1916 │ custom_overloaded(X). - │ ^ X. + │ ^ + │ │ + │ X. Expression has type: term() Context expected type: atom() | binary() + │ + + term() is not compatible with atom() | binary() + because + term() is not compatible with atom() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:1939:5 @@ -2042,6 +2554,15 @@ Because in the expression's type: Differs from the expected type: number() } +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {atom(), number() | pid()} is not compatible with {atom(), number()} + because + number() | pid() is not compatible with number() + because + pid() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2041:5 │ @@ -2057,6 +2578,14 @@ Because in the expression's type: Here the type is: string() | binary() Context expects type: string() +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2046:5 │ @@ -2072,6 +2601,14 @@ Because in the expression's type: Here the type is: string() | binary() Context expects type: string() +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2051:5 │ @@ -2087,6 +2624,14 @@ Because in the expression's type: Here the type is: string() | binary() Context expects type: string() +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2066:5 │ @@ -2103,6 +2648,14 @@ Because in the expression's type: However the following candidate: string() Differs from the expected type: binary() +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with binary() + because + string() | binary() is not compatible with binary() + because + string() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2081:19 │ @@ -2121,6 +2674,16 @@ Because in the expression's type: Differs from the expected type: string() | atom() | file:deep_list() | binary() ] +------------------------------ Detailed message ------------------------------ + + [binary() | pid()] is not compatible with [file:name_all()] + because + binary() | pid() is not compatible with file:name_all() + because + binary() | pid() is not compatible with string() | atom() | file:deep_list() | binary() + because + pid() is not compatible with string() | atom() | file:deep_list() | binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2086:5 │ @@ -2136,6 +2699,14 @@ Because in the expression's type: Here the type is: string() | binary() Context expects type: string() +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2091:5 │ @@ -2151,6 +2722,14 @@ Because in the expression's type: Here the type is: string() | binary() Context expects type: string() +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2096:5 │ @@ -2166,6 +2745,14 @@ Because in the expression's type: Here the type is: string() | binary() Context expects type: string() +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2111:5 │ @@ -2182,6 +2769,14 @@ Because in the expression's type: However the following candidate: string() Differs from the expected type: binary() +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with binary() + because + string() | binary() is not compatible with binary() + because + string() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2121:25 │ @@ -2198,6 +2793,14 @@ Because in the expression's type: Context expects type: string() | atom() | file:deep_list() | binary() No candidate matches in the expected union. +------------------------------ Detailed message ------------------------------ + + pid() is not compatible with file:name_all() + because + pid() is not compatible with string() | atom() | file:deep_list() | binary() + because + pid() is not compatible with string() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2150:5 │ @@ -2219,6 +2822,17 @@ Because in the expression's type: ] , [atom() | number()]} +------------------------------ Detailed message ------------------------------ + + queue:queue(atom() | number()) is not compatible with queue:queue(number()) + because + {[atom() | number()], [atom() | number()]} is not compatible with queue:queue(number()) + because + at tuple index 1: + {[atom() | number()], [atom() | number()]} is not compatible with {[number()], [number()]} + because + [atom() | number()] is not compatible with [number()] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2191:5 │ @@ -2237,6 +2851,15 @@ Because in the expression's type: Context expects type: #{count := ..., ...} The type of the expression is missing the following required keys: count. +------------------------------ Detailed message ------------------------------ + + #{count := number(), module := 'foo'} | #{module := 'foo'} is not compatible with state1() + because + #{count := number(), module := 'foo'} | #{module := 'foo'} is not compatible with #{count := number(), module := atom()} + because + #{module := 'foo'} is not compatible with #{count := number(), module := atom()} + key `count` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2223:13 │ @@ -2261,6 +2884,10 @@ Because in the expression's type: Context expects type: #{a := ..., ...} The type of the expression is missing the following required keys: a. +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2320:5 │ @@ -2281,6 +2908,10 @@ Because in the expression's type: Context expects type: #{a := ..., b := ..., ...} The type of the expression is missing the following required keys: a, b. +------------------------------ Detailed message ------------------------------ + +keys `a`, `b` are declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2342:5 │ @@ -2301,6 +2932,13 @@ Because in the expression's type: Context expects type: atom() , ... } +------------------------------ Detailed message ------------------------------ + + #{atom() => binary()} is not compatible with #{atom() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2354:23 │ @@ -2317,6 +2955,12 @@ Because in the expression's type: Context expects type: 'false' | 'true' | {'true', term()} No candidate matches in the expected union. +------------------------------ Detailed message ------------------------------ + + 'err' is not compatible with boolean() | {'true', term()} + because + 'err' is not compatible with 'false' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2362:5 │ @@ -2335,6 +2979,13 @@ Because in the expression's type: Context expects type: atom() , ... } +------------------------------ Detailed message ------------------------------ + + #{atom() => binary()} is not compatible with #{atom() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2363:45 │ @@ -2375,6 +3026,12 @@ Because in the expression's type: Context expects type: iolist() | binary() No candidate matches in the expected union. +------------------------------ Detailed message ------------------------------ + + atom() is not compatible with iodata() | unicode:charlist() + because + atom() is not compatible with iolist() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2386:5 │ @@ -2403,6 +3060,17 @@ Because in the expression's type: } ] +------------------------------ Detailed message ------------------------------ + + [{'return', 'something'}] is not compatible with [{'newline', 'cr' | 'lf' | 'any' | 'crlf' | 'anycrlf'} | 'notempty_atstart' | 'noteol' | 'bsr_unicode' | 'notbol' | 'global' | {'match_limit_recursion', number()} | 'bsr_anycrlf' | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored'] + because + {'return', 'something'} is not compatible with {'newline', 'cr' | 'lf' | 'any' | 'crlf' | 'anycrlf'} | 'notempty_atstart' | 'noteol' | 'bsr_unicode' | 'notbol' | 'global' | {'match_limit_recursion', number()} | 'bsr_anycrlf' | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored' + because + at tuple index 2: + {'return', 'something'} is not compatible with {'return', 'iodata' | 'list' | 'binary'} + because + 'something' is not compatible with 'iodata' | 'list' | 'binary' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2506:5 │ @@ -2422,6 +3090,15 @@ Because in the expression's type: ] , [atom()]} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[number()], [atom()]} is not compatible with {[atom()], [number()]} + because + [number()] is not compatible with [atom()] + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2518:5 │ @@ -2443,6 +3120,18 @@ Because in the expression's type: ] , [{term(), atom()}]} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[{term(), number()}], [{term(), atom()}]} is not compatible with {[{term(), atom()}], [{term(), number()}]} + because + [{term(), number()}] is not compatible with [{term(), atom()}] + because + at tuple index 2: + {term(), number()} is not compatible with {term(), atom()} + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2536:5 │ @@ -2464,6 +3153,18 @@ Because in the expression's type: ] } +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {[{'ok', atom()}], [{'ok', atom()} | {'error', term()}]} is not compatible with {[{'ok', atom()}], [{'error', term()}]} + because + [{'ok', atom()} | {'error', term()}] is not compatible with [{'error', term()}] + because + {'ok', atom()} | {'error', term()} is not compatible with {'error', term()} + because + at tuple index 1: + {'ok', atom()} is not compatible with {'error', term()} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2576:33 │ @@ -2480,6 +3181,10 @@ Because in the expression's type: Context expects type: #{a := ..., ...} The type of the expression is missing the following required keys: a. +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2586:33 │ @@ -2497,6 +3202,15 @@ Because in the expression's type: Context expects type: 'true' , ... } +------------------------------ Detailed message ------------------------------ + + #{a => number()} is not compatible with #{a => 'true'} + because + at key `a`: + #{a => number()} is not compatible with #{a => 'true'} + because + number() is not compatible with 'true' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2596:33 │ @@ -2513,6 +3227,10 @@ Because in the expression's type: Context expects type: #{a := ..., ...} The type of the expression is missing the following required keys: a. +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2709:40 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-27.pretty new file mode 100644 index 0000000000..370f7689e9 --- /dev/null +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-27.pretty @@ -0,0 +1,3258 @@ +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:26:5 + │ +26 │ element(4, Tup). + │ ^^^^^^^^^^^^^^^ erlang:element(4, Tup). +Expression has type: #{dynamic() => dynamic()} +Context expected type: atom() + +error: index_out_of_bounds (See https://fb.me/eqwalizer_errors#index_out_of_bounds) + ┌─ check/src/custom.erl:30:5 + │ +30 │ element(42, Tup). + │ ^^^^^^^^^^^^^^^^ 42. +Tried to access element 42 of a tuple with 3 elements + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:40:5 + │ +40 │ element(2, Tup). + │ ^^^^^^^^^^^^^^^ erlang:element(2, Tup). +Expression has type: number() | string() | atom() +Context expected type: #{dynamic() => dynamic()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:44:16 + │ +44 │ element(2, Tup). + │ ^^^ + │ │ + │ Tup. +Expression has type: {atom(), string()} | [dynamic()] +Context expected type: tuple() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: {atom(), string()} + However the following candidate: [dynamic()] + Differs from the expected type: tuple() + +------------------------------ Detailed message ------------------------------ + + {atom(), string()} | [dynamic()] is not compatible with tuple() + because + [dynamic()] is not compatible with tuple() + +error: index_out_of_bounds (See https://fb.me/eqwalizer_errors#index_out_of_bounds) + ┌─ check/src/custom.erl:48:5 + │ +48 │ element(42, Tup). + │ ^^^^^^^^^^^^^^^^ 42. +Tried to access element 42 of a tuple with 2 elements + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:54:5 + │ +54 │ element(N, Tup). + │ ^^^^^^^^^^^^^^^ erlang:element(N, Tup). +Expression has type: atom() | number() | string() +Context expected type: #{dynamic() => dynamic()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:58:5 + │ +58 │ element(N, Tup). + │ ^^^^^^^^^^^^^^^ + │ │ + │ erlang:element(N, Tup). +Expression has type: atom() | number() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + atom() | number() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:68:5 + │ +68 │ element(1, Tup). + │ ^^^^^^^^^^^^^^^ + │ │ + │ erlang:element(1, Tup). +Expression has type: dynamic() | number() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: dynamic() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + dynamic() | number() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:86:5 + │ +86 │ element(N, Rec). + │ ^^^^^^^^^^^^^^^ + │ │ + │ erlang:element(N, Rec). +Expression has type: 'foo' | 'ok' | 'error' | number() | string() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'error' | 'foo' | 'ok' + However the following candidate: string() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + 'foo' | 'ok' | 'error' | number() | string() is not compatible with atom() + because + string() is not compatible with atom() + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:91:1 + │ +91 │ ╭ element_2_none_1(Tup) -> +92 │ │ element(42, Tup). + │ ╰────────────────────^ Clause is not covered by spec + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:95:1 + │ +95 │ ╭ element_2_none_2(N, Tup) -> +96 │ │ element(N, Tup). + │ ╰───────────────────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:108:5 + │ +108 │ maps:get(K, M). + │ ^^^^^^^^^^^^^^ maps:get(K, M). +Expression has type: number() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:128:5 + │ +128 │ Res. + │ ^^^ Res. +Expression has type: number() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:154:12 + │ +154 │ get(a, M). + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:160:23 + │ +160 │ Res = maps:get(a, M), + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:167:17 + │ +167 │ maps:get(a, M, false). + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:173:23 + │ +173 │ Res = maps:get(a, M, false), + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:193:5 + │ +193 │ maps:get(K, M, 0). + │ ^^^^^^^^^^^^^^^^^ + │ │ + │ maps:get(K, M, 0). +Expression has type: number() | atom() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:200:5 + │ +200 │ Res. + │ ^^^ + │ │ + │ Res. +Expression has type: number() | atom() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:206:5 + │ +206 │ ╭ ╭ { +207 │ │ │ maps:get(a, M, undefined), +208 │ │ │ maps:get(n, M, undefined) +209 │ │ │ }. + │ ╰─│─────^ {maps:get('a', M, 'undefined'), maps:get('n', M, 'undefined')}. +Expression has type: {atom(), 'undefined' | number()} +Context expected type: {atom(), number()} + │ ╰─────' + +Because in the expression's type: + { atom(), + Here the type is a union type with some valid candidates: number() + However the following candidate: 'undefined' + Differs from the expected type: number() + } + +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {atom(), 'undefined' | number()} is not compatible with {atom(), number()} + because + 'undefined' | number() is not compatible with number() + because + 'undefined' is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:221:27 + │ +221 │ map_get_2_17_neg(V, M) -> maps:get(V, M). + │ ^^^^^^^^^^^^^^ + │ │ + │ maps:get(V, M). +Expression has type: 'a_v' | 'c_v' +Context expected type: 'a_v' | 'b_v' + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'a_v' + However the following candidate: 'c_v' + Differs from the expected type: 'a_v' | 'b_v' + +------------------------------ Detailed message ------------------------------ + + 'a_v' | 'c_v' is not compatible with 'a_v' | 'b_v' + because + 'c_v' is not compatible with 'a_v' | 'b_v' + because + 'c_v' is not compatible with 'a_v' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:233:27 + │ +233 │ map_get_3_19_neg(V, M) -> maps:get(V, M, undefined). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:get(V, M, 'undefined'). +Expression has type: 'undefined' | 'a_v' | 'c_v' +Context expected type: 'a_v' | 'b_v' | 'undefined' + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'undefined' | 'a_v' + However the following candidate: 'c_v' + Differs from the expected type: 'a_v' | 'b_v' | 'undefined' + +------------------------------ Detailed message ------------------------------ + + 'undefined' | 'a_v' | 'c_v' is not compatible with 'a_v' | 'b_v' | 'undefined' + because + 'c_v' is not compatible with 'a_v' | 'b_v' | 'undefined' + because + 'c_v' is not compatible with 'a_v' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:309:5 + │ +309 │ Res. + │ ^^^ Res. +Expression has type: {'value', #{}} | 'false' +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:363:23 + │ +363 │ fun (_, _) -> self() end, + │ ^^^^^^ erlang:self(). +Expression has type: pid() +Context expected type: boolean() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:382:17 + │ +382 │ maps:filter(F, M). + │ ^ F. +Expression has type: fun(() -> pid()) +Context expected type: fun((number(), 'a' | 'b') -> boolean()) + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:389:17 + │ +389 │ maps:filter(F, M). + │ ^ + │ │ + │ F. +Expression has type: fun((fun((T) -> boolean()), [T]) -> [T]) with 1 type parameter +Context expected type: fun((number(), 'a' | 'b') -> boolean()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun()/2 with 1 type parameter + Context expects type: fun((number(), 'a' | 'b') -> boolean()) with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:413:37 + │ +413 │ maps:filter(fun erlang:'=:='/2, X). + │ ^ + │ │ + │ X. +Expression has type: #{K => V} | 'a' +Context expected type: #{term() => term()} | maps:iterator() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: #{K => V} + However the following candidate: 'a' + Differs from the expected type: #{term() => term()} | maps:iterator() + +------------------------------ Detailed message ------------------------------ + + #{K => V} | 'a' is not compatible with #{term() => term()} | maps:iterator() + because + 'a' is not compatible with #{term() => term()} | maps:iterator() + because + 'a' is not compatible with #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:425:20 + │ +425 │ maps:filter(F, non_kv), + │ ^^^^^^ + │ │ + │ 'non_kv'. +Expression has type: 'non_kv' +Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:454:5 + │ +454 │ ╭ ╭ maps:map( +455 │ │ │ fun (_, _) -> self() end, +456 │ │ │ M +457 │ │ │ ). + │ ╰─│─────^ maps:map(fun, M). +Expression has type: #{number() => pid()} +Context expected type: #{number() => boolean()} + │ ╰─────' + +Because in the expression's type: + #{ number() => + Here the type is: pid() + Context expects type: boolean() + , ... } + +------------------------------ Detailed message ------------------------------ + + #{number() => pid()} is not compatible with #{number() => boolean()} + the default associations are not compatible + because + pid() is not compatible with boolean() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:474:14 + │ +474 │ maps:map(F, M). + │ ^ F. +Expression has type: fun(() -> pid()) +Context expected type: fun((number(), 'a' | 'b') -> term()) + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:481:14 + │ +481 │ maps:map(F, M). + │ ^ + │ │ + │ F. +Expression has type: fun((fun((A) -> B), [A]) -> [B]) with 2 type parameters +Context expected type: fun((number(), 'a' | 'b') -> term()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((fun((A) -> B), [A]) -> [B]) with 2 type parameters + Context expects type: fun((number(), 'a' | 'b') -> term()) with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:497:5 + │ +497 │ maps:map(F, M). + │ ^^^^^^^^^^^^^^ + │ │ + │ maps:map(F, M). +Expression has type: #{a := boolean(), b := boolean()} +Context expected type: #{a => 'a', b => 'b'} + │ + +Because in the expression's type: + #{ a => + Here the type is: boolean() + Context expects type: 'a' + , ... } + +------------------------------ Detailed message ------------------------------ + + #{a := boolean(), b := boolean()} is not compatible with #{a => 'a', b => 'b'} + because + at key `a`: + #{a := boolean(), b := boolean()} is not compatible with #{a => 'a', b => 'b'} + because + boolean() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:503:17 + │ +503 │ maps:map(F, non_kv), + │ ^^^^^^ + │ │ + │ 'non_kv'. +Expression has type: 'non_kv' +Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} + +error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) + ┌─ check/src/custom.erl:538:9 + │ +538 │ fun (K, V) -> [K, V] end, [], M). + │ ^^^^^^^^^^^^^^^^^^^^^^^^ fun. +fun with arity 2 used as fun with 3 arguments + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:544:5 + │ +544 │ ╭ ╭ maps:fold( +545 │ │ │ fun (_, _, Acc) -> [Acc] end, +546 │ │ │ [], +547 │ │ │ M +548 │ │ │ ). + │ ╰─│─────^ maps:fold(fun, [], M). +Expression has type: [[[]]] +Context expected type: [number() | 'a' | 'b'] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is: [[]] + Context expects type: number() | 'a' | 'b' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [[[]]] is not compatible with [number() | 'a' | 'b'] + because + [[]] is not compatible with number() | 'a' | 'b' + because + [[]] is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:545:28 + │ +545 │ fun (_, _, Acc) -> [Acc] end, + │ ^^^^^ + │ │ + │ [Acc]. +Expression has type: [[[[]]]] +Context expected type: [[[]]] + │ + +Because in the expression's type: + [ + [ + [ + Here the type is: [] + Context expects type: none() + ] + ] + ] + +------------------------------ Detailed message ------------------------------ + + [[[[]]]] is not compatible with [[[]]] + because + [[[]]] is not compatible with [[]] + because + [[]] is not compatible with [] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:552:5 + │ +552 │ ╭ maps:fold( +553 │ │ fun (_, _, Acc) -> Acc end, +554 │ │ [], +555 │ │ non_kv +556 │ │ ). + │ ╰─────^ maps:fold(fun, [], 'non_kv'). +Expression has type: [] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:555:9 + │ +555 │ non_kv + │ ^^^^^^ + │ │ + │ 'non_kv'. +Expression has type: 'non_kv' +Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:560:1 + │ +560 │ ╭ maps_fold_3_6(None) -> +561 │ │ maps:fold( +562 │ │ None, +563 │ │ #{}, +564 │ │ #{1 => 1} +565 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:568:1 + │ +568 │ ╭ maps_fold_3_7(None) -> +569 │ │ maps:fold( +570 │ │ None, +571 │ │ None, +572 │ │ None +573 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:578:5 + │ +578 │ ╭ ╭ maps:fold( +579 │ │ │ fun (_K, A, _Acc) -> A end, +580 │ │ │ [], +581 │ │ │ M +582 │ │ │ ). + │ ╰─│─────^ maps:fold(fun, [], M). +Expression has type: [] | atom() +Context expected type: atom() + │ ╰─────' + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: [] + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + [] | atom() is not compatible with atom() + because + [] is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:601:9 + │ +601 │ fun folder_bad/3, + │ ^^^^^^^^^^^^^^^^ + │ │ + │ folder_bad/3. +Expression has type: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter +Context expected type: fun((number(), 'a', []) -> term()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter + Context expects type: fun((number(), 'a', []) -> term()) with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:601:9 + │ +601 │ fun folder_bad/3, + │ ^^^^^^^^^^^^^^^^ + │ │ + │ folder_bad/3. +Expression has type: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter +Context expected type: fun((number(), 'a', [] | dynamic()) -> term()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter + Context expects type: fun()/3 with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:601:9 + │ +601 │ fun folder_bad/3, + │ ^^^^^^^^^^^^^^^^ + │ │ + │ folder_bad/3. +Expression has type: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter +Context expected type: fun((number(), 'a', [] | dynamic()) -> [] | dynamic()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter + Context expects type: fun()/3 with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:636:5 + │ +636 │ ╭ ╭ maps:fold( +637 │ │ │ fun +638 │ │ │ (_K, {i, I}, Acc) -> +639 │ │ │ [I | Acc]; + · │ │ +646 │ │ │ M +647 │ │ │ ). + │ ╰─│─────^ maps:fold(fun, [], M). +Expression has type: [number() | binary() | atom()] +Context expected type: [binary()] | [number()] | [atom()] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: binary() + However the following candidate: number() + Differs from the expected type: binary() + ] + +------------------------------ Detailed message ------------------------------ + + [number() | binary() | atom()] is not compatible with [binary()] | [number()] | [atom()] + because + [number() | binary() | atom()] is not compatible with [binary()] + because + number() | binary() | atom() is not compatible with binary() + because + number() is not compatible with binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:671:41 + │ +671 │ maps_to_list_7_neg(Num) -> maps:to_list(Num). + │ ^^^ + │ │ + │ Num. +Expression has type: number() +Context expected type: #{term() => term()} | maps:iterator() + │ + + number() is not compatible with #{term() => term()} | maps:iterator() + because + number() is not compatible with #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:675:25 + │ +675 │ maps_merge_1(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'b' | 'a' | 'c' => number() | string() | atom()} +Context expected type: #{a => string(), b => number(), c => atom()} + │ + +Because in the expression's type: + Here the type is: #{'b' | 'a' | 'c' => number() | string() | atom()} + Context expects type: #{...} (no default association) + The expected map has no default association while the type of the expression has one. + +------------------------------ Detailed message ------------------------------ + + #{'b' | 'a' | 'c' => number() | string() | atom()} is not compatible with #{a => string(), b => number(), c => atom()} + key a is not present in the former map but is incompatible with its default association + because + number() | string() | atom() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:679:25 + │ +679 │ maps_merge_2(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'b' | 'a' | 'c' => number() | string() | atom()} +Context expected type: #{a => string(), b => number() | boolean(), c => atom()} + │ + +Because in the expression's type: + Here the type is: #{'b' | 'a' | 'c' => number() | string() | atom()} + Context expects type: #{...} (no default association) + The expected map has no default association while the type of the expression has one. + +------------------------------ Detailed message ------------------------------ + + #{'b' | 'a' | 'c' => number() | string() | atom()} is not compatible with #{a => string(), b => number() | boolean(), c => atom()} + key a is not present in the former map but is incompatible with its default association + because + number() | string() | atom() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:683:25 + │ +683 │ maps_merge_3(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'b' | 'a' | 'c' => number() | string() | atom()} +Context expected type: #{a := string(), b := boolean(), c => atom()} + │ + +Because in the expression's type: + Here the type is: #{...} + Context expects type: #{a := ..., b := ..., ...} + The type of the expression is missing the following required keys: a, b. + +------------------------------ Detailed message ------------------------------ + +keys `a`, `b` are declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:697:44 + │ +697 │ maps_merge_7_neg(M1, M2) -> maps:merge(M1, M2). + │ ^^ M2. +Expression has type: number() +Context expected type: #{a => binary()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:701:25 + │ +701 │ maps_merge_8(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'a' | 'b' => atom() | number()} +Context expected type: #{a := atom(), b := number()} | #{a := atom()} + │ + +Because in the expression's type: + Here the type is: #{...} + Context expects type: #{a := ..., b := ..., ...} + The type of the expression is missing the following required keys: a, b. + +------------------------------ Detailed message ------------------------------ + + #{'a' | 'b' => atom() | number()} is not compatible with #{a := atom(), b := number()} | #{a := atom()} + because + #{'a' | 'b' => atom() | number()} is not compatible with #{a := atom(), b := number()} + keys `a`, `b` are declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:721:9 + │ +721 │ fun erlang:binary_to_list/1, + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:binary_to_list/1. +Expression has type: fun((binary()) -> [number()]) +Context expected type: fun((number()) -> boolean() | {'true', term()}) + │ + +Because in the expression's type: + fun((binary()) -> + Here the type is: [number()] + Context expects type: 'false' | 'true' | {'true', term()} + No candidate matches in the expected union. + ) + +------------------------------ Detailed message ------------------------------ + + fun((binary()) -> [number()]) is not compatible with fun((number()) -> boolean() | {'true', term()}) + because + [number()] is not compatible with boolean() | {'true', term()} + because + [number()] is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:739:20 + │ +739 │ (3) -> wrong_ret end, + │ ^^^^^^^^^ + │ │ + │ 'wrong_ret'. +Expression has type: 'wrong_ret' +Context expected type: boolean() | {'true', term()} + │ + +Because in the expression's type: + Here the type is: 'wrong_ret' + Context expects type: 'false' | 'true' | {'true', term()} + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:749:9 + │ +749 │ not_a_list + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:791:17 + │ +791 │ Res + │ ^^^ + │ │ + │ Res. +Expression has type: {'true', 'a'} | 'wrong_ret' +Context expected type: boolean() | {'true', term()} + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: {'true', 'a'} + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | {'true', term()} + +------------------------------ Detailed message ------------------------------ + + {'true', 'a'} | 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:827:9 + │ +827 │ ╭ ╭ fun (a) -> [a]; +828 │ │ │ (b) -> true; +829 │ │ │ (c) -> wrong_ret end, + │ ╰─│────────────────────────────────^ fun. +Expression has type: fun(('a' | 'b') -> ['a'] | 'true' | 'wrong_ret') +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ ╰────────────────────────────────' + +Because in the expression's type: + fun(('a' | 'b') -> + Here the type is a union type with some valid candidates: ['a'] | 'true' + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + ) + +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'true' | 'wrong_ret') is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'true' | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:829:20 + │ +829 │ (c) -> wrong_ret end, + │ ^^^^^^^^^ + │ │ + │ 'wrong_ret'. +Expression has type: 'wrong_ret' +Context expected type: boolean() | ['a' | 'b'] + │ + +Because in the expression's type: + Here the type is: 'wrong_ret' + Context expects type: 'false' | 'true' | ['a' | 'b'] + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:837:9 + │ +837 │ ╭ ╭ fun (1) -> {true, a}; +838 │ │ │ (2) -> true end, + │ ╰─│───────────────────────────^ fun. +Expression has type: fun((dynamic()) -> {'true', 'a'} | 'true') +Context expected type: fun((Item) -> boolean() | [Item]) + │ ╰───────────────────────────' + +Because in the expression's type: + fun((dynamic()) -> + Here the type is a union type with some valid candidates: 'true' + However the following candidate: {'true', 'a'} + Differs from the expected type: 'false' | 'true' | [Item] + ) + +------------------------------ Detailed message ------------------------------ + + fun((dynamic()) -> {'true', 'a'} | 'true') is not compatible with fun((Item) -> boolean() | [Item]) + because + {'true', 'a'} | 'true' is not compatible with boolean() | [Item] + because + {'true', 'a'} is not compatible with boolean() | [Item] + expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:837:20 + │ +837 │ fun (1) -> {true, a}; + │ ^^^^^^^^^ + │ │ + │ {'true', 'a'}. +Expression has type: {'true', 'a'} +Context expected type: boolean() | [dynamic()] + │ + +Because in the expression's type: + Here the type is: {'true', 'a'} + Context expects type: 'false' | 'true' | [dynamic()] + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + +expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:839:9 + │ +839 │ not_a_queue + │ ^^^^^^^^^^^ + │ │ + │ 'not_a_queue'. +Expression has type: 'not_a_queue' +Context expected type: queue:queue(Item) + │ + +Because in the expression's type: + Here the type is: 'not_a_queue' + Context expects type: {[Item], [Item]} + +------------------------------ Detailed message ------------------------------ + + 'not_a_queue' is not compatible with queue:queue(Item) + because + 'not_a_queue' is not compatible with {[Item], [Item]} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:839:9 + │ +839 │ not_a_queue + │ ^^^^^^^^^^^ + │ │ + │ 'not_a_queue'. +Expression has type: 'not_a_queue' +Context expected type: queue:queue(dynamic()) + │ + +Because in the expression's type: + Here the type is: 'not_a_queue' + Context expects type: {[dynamic()], [dynamic()]} + +------------------------------ Detailed message ------------------------------ + + 'not_a_queue' is not compatible with queue:queue(dynamic()) + because + 'not_a_queue' is not compatible with {[dynamic()], [dynamic()]} + +error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) + ┌─ check/src/custom.erl:846:9 + │ +846 │ ╭ fun (wrong, arity) -> +847 │ │ [a] +848 │ │ end, + │ ╰───────────^ fun. +fun with arity 2 used as fun with 1 arguments + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:857:9 + │ +857 │ ╭ ╭ fun (1) -> {true, a}; +858 │ │ │ (X) -> case X of +859 │ │ │ true -> +860 │ │ │ [a]; + · │ │ +863 │ │ │ end +864 │ │ │ end, + │ ╰─│───────────^ fun. +Expression has type: fun(('a' | 'b') -> ['a'] | 'false' | {'true', 'a'}) +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ ╰───────────' + +Because in the expression's type: + fun(('a' | 'b') -> + Here the type is a union type with some valid candidates: ['a'] | 'false' + However the following candidate: {'true', 'a'} + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + ) + +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'false' | {'true', 'a'}) is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'false' | {'true', 'a'} is not compatible with boolean() | ['a' | 'b'] + because + {'true', 'a'} is not compatible with boolean() | ['a' | 'b'] + expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:857:20 + │ +857 │ fun (1) -> {true, a}; + │ ^^^^^^^^^ + │ │ + │ {'true', 'a'}. +Expression has type: {'true', 'a'} +Context expected type: boolean() | ['a' | 'b'] + │ + +Because in the expression's type: + Here the type is: {'true', 'a'} + Context expects type: 'false' | 'true' | ['a' | 'b'] + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + +expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:873:9 + │ +873 │ ╭ ╭ fun (a) -> [a]; +874 │ │ │ (X) -> +875 │ │ │ Res = case X of +876 │ │ │ true -> + · │ │ +881 │ │ │ Res +882 │ │ │ end, + │ ╰─│───────────^ fun. +Expression has type: fun(('a' | 'b') -> ['a'] | 'wrong_ret') +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ ╰───────────' + +Because in the expression's type: + fun(('a' | 'b') -> + Here the type is a union type with some valid candidates: ['a'] + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + ) + +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'wrong_ret') is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:881:17 + │ +881 │ Res + │ ^^^ + │ │ + │ Res. +Expression has type: ['a'] | 'wrong_ret' +Context expected type: boolean() | ['a' | 'b'] + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: ['a'] + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + +------------------------------ Detailed message ------------------------------ + + ['a'] | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:891:9 + │ +891 │ fun list_to_atom/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:list_to_atom/1. +Expression has type: fun((string()) -> atom()) +Context expected type: fun((dynamic()) -> boolean() | [dynamic()]) + │ + +Because in the expression's type: + fun((string()) -> + Here the type is: atom() + Context expects type: 'false' | 'true' | [dynamic()] + No candidate matches in the expected union. + ) + +------------------------------ Detailed message ------------------------------ + + fun((string()) -> atom()) is not compatible with fun((dynamic()) -> boolean() | [dynamic()]) + because + atom() is not compatible with boolean() | [dynamic()] + because + atom() is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:891:9 + │ +891 │ fun list_to_atom/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:list_to_atom/1. +Expression has type: fun((string()) -> atom()) +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ + +Because in the expression's type: + fun((string()) -> + Here the type is: atom() + Context expects type: 'false' | 'true' | ['a' | 'b'] + No candidate matches in the expected union. + ) + +------------------------------ Detailed message ------------------------------ + + fun((string()) -> atom()) is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + atom() is not compatible with boolean() | ['a' | 'b'] + because + atom() is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:900:9 + │ +900 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:900:9 + │ +900 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:909:9 + │ +909 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:909:9 + │ +909 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:919:9 + │ +919 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:919:9 + │ +919 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:925:1 + │ +925 │ ╭ queue_filter_13_neg(Q) -> +926 │ │ queue:filter( +927 │ │ fun atom_to_list/1, +928 │ │ Q +929 │ │ ), +930 │ │ ok. + │ ╰──────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:927:9 + │ +927 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:927:9 + │ +927 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:955:5 + │ +955 │ ╭ lists:keystore( +956 │ │ a, 1, +957 │ │ [{foo, b}, {c, d}], +958 │ │ non_tuple +959 │ │ ). + │ ╰─────^ lists:keystore('a', 1, [{'foo', 'b'}, {'c', 'd'}], 'non_tuple'). +Expression has type: [{'foo', 'b'} | {'c', 'd'} | dynamic()] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:958:9 + │ +958 │ non_tuple + │ ^^^^^^^^^ 'non_tuple'. +Expression has type: 'non_tuple' +Context expected type: tuple() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:966:5 + │ +966 │ ╭ lists:keystore( +967 │ │ a, 1, +968 │ │ [non_tuple], +969 │ │ {replacement} +970 │ │ ). + │ ╰─────^ lists:keystore('a', 1, ['non_tuple'], {'replacement'}). +Expression has type: [dynamic() | {'replacement'}] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:968:9 + │ +968 │ [non_tuple], + │ ^^^^^^^^^^^ + │ │ + │ ['non_tuple']. +Expression has type: ['non_tuple'] +Context expected type: [tuple()] + │ + +Because in the expression's type: + [ + Here the type is: 'non_tuple' + Context expects type: tuple() + ] + +------------------------------ Detailed message ------------------------------ + + ['non_tuple'] is not compatible with [tuple()] + because + 'non_tuple' is not compatible with tuple() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:975:5 + │ +975 │ ╭ lists:keystore( +976 │ │ a, 1, +977 │ │ non_list, +978 │ │ {replacement} +979 │ │ ). + │ ╰─────^ lists:keystore('a', 1, 'non_list', {'replacement'}). +Expression has type: [dynamic() | {'replacement'}] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:977:9 + │ +977 │ non_list, + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [tuple()] + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:983:1 + │ +983 │ ╭ keystore_7(None) -> +984 │ │ lists:keystore( +985 │ │ a, 1, +986 │ │ None, +987 │ │ {replacement} +988 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:991:1 + │ +991 │ ╭ keystore_8(None) -> +992 │ │ lists:keystore( +993 │ │ a, 1, +994 │ │ None, +995 │ │ None +996 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1011:25 + │ +1011 │ lists:keytake(a, 1, non_tup), + │ ^^^^^^^ 'non_tup'. +Expression has type: 'non_tup' +Context expected type: [Tuple] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1011:25 + │ +1011 │ lists:keytake(a, 1, non_tup), + │ ^^^^^^^ 'non_tup'. +Expression has type: 'non_tup' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1016:25 + │ +1016 │ lists:keytake(a, 1, non_list), + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [Tuple] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1016:25 + │ +1016 │ lists:keytake(a, 1, non_list), + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1021:22 + │ +1021 │ lists:keytake(a, non_num, []), + │ ^^^^^^^ 'non_num'. +Expression has type: 'non_num' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1038:15 + │ +1038 │ lists:sum([a, 1]). + │ ^^^^^^ + │ │ + │ ['a', 1]. +Expression has type: ['a' | number()] +Context expected type: [number()] + │ + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: number() + However the following candidate: 'a' + Differs from the expected type: number() + ] + +------------------------------ Detailed message ------------------------------ + + ['a' | number()] is not compatible with [number()] + because + 'a' | number() is not compatible with number() + because + 'a' is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1042:15 + │ +1042 │ lists:sum(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [number()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1062:15 + │ +1062 │ lists:max(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [T] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1062:15 + │ +1062 │ lists:max(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1082:15 + │ +1082 │ lists:min(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [T] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1082:15 + │ +1082 │ lists:min(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1100:5 + │ +1100 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). +Expression has type: term() +Context expected type: pid() | 'undefined' + │ + + term() is not compatible with pid() | 'undefined' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1106:5 + │ +1106 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). +Expression has type: term() +Context expected type: pid() | 'undefined' | 'v' + │ + + term() is not compatible with pid() | 'undefined' | 'v' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1111:5 + │ +1111 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', L). +Expression has type: term() +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1117:5 + │ +1117 │ proplists:get_value(k, L, 3). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L, 3). +Expression has type: term() +Context expected type: pid() | number() + │ + + term() is not compatible with pid() | number() + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1123:5 + │ +1123 │ proplists:get_value(k, L, my_default). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L, 'my_default'). +Expression has type: term() +Context expected type: 'v1' | 'v2' | 'my_default' + │ + + term() is not compatible with 'v1' | 'v2' | 'my_default' + because + term() is not compatible with 'v1' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1129:5 + │ +1129 │ proplists:get_value(k, L, my_default). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', L, 'my_default'). +Expression has type: term() +Context expected type: 'v' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1134:28 + │ +1134 │ proplists:get_value(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1139:5 + │ +1139 │ proplists:get_value(k, []). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', []). +Expression has type: term() +Context expected type: 'default' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1144:1 + │ +1144 │ proplists:get_value(k, [], my_default). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', [], 'my_default'). +Expression has type: term() +Context expected type: 'my_default' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1149:28 + │ +1149 │ proplists:get_value(k, b, my_default). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1154:5 + │ +1154 │ proplists:get_bool(b, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_bool('b', L). +Expression has type: boolean() +Context expected type: 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1160:5 + │ +1160 │ proplists:get_all_values(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', L). +Expression has type: [term()] +Context expected type: [pid() | 'default'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: pid() | 'default' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid() | 'default'] + because + term() is not compatible with pid() | 'default' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1166:5 + │ +1166 │ proplists:get_all_values(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', L). +Expression has type: [term()] +Context expected type: [pid() | 'default' | 'v'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: pid() | 'default' | 'v' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid() | 'default' | 'v'] + because + term() is not compatible with pid() | 'default' | 'v' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1171:5 + │ +1171 │ proplists:get_all_values(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', L). +Expression has type: [term()] +Context expected type: [pid()] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: pid() + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid()] + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1176:5 + │ +1176 │ proplists:get_all_values(k, []). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', []). +Expression has type: [term()] +Context expected type: [] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: none() + ] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1181:5 + │ +1181 │ proplists:get_all_values(k, b). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', 'b'). +Expression has type: [term()] +Context expected type: [] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: none() + ] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1181:33 + │ +1181 │ proplists:get_all_values(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1186:27 + │ +1186 │ proplists:get_bool(b, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1191:5 + │ +1191 │ proplists:get_keys(L). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_keys(L). +Expression has type: [term()] +Context expected type: ['c'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: 'c' + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['c'] + because + term() is not compatible with 'c' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1197:5 + │ +1197 │ proplists:get_keys(L). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_keys(L). +Expression has type: [term()] +Context expected type: ['a' | 'b' | 'c'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: 'a' | 'b' | 'c' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['a' | 'b' | 'c'] + because + term() is not compatible with 'a' | 'b' | 'c' + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1202:24 + │ +1202 │ proplists:get_keys(a). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1207:5 + │ +1207 │ ╭ ╭ proplists:get_keys( +1208 │ │ │ [{a, b, c}] +1209 │ │ │ ). + │ ╰─│─────^ proplists:get_keys([{'a', 'b', 'c'}]). +Expression has type: [term()] +Context expected type: ['a'] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: 'a' + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['a'] + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1215:5 + │ +1215 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). +Expression has type: term() +Context expected type: 'a' | pid() + │ + + term() is not compatible with 'a' | pid() + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1220:5 + │ +1220 │ proplists:get_value(k, b). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', 'b'). +Expression has type: term() +Context expected type: 'a' | pid() + │ + + term() is not compatible with 'a' | pid() + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1220:28 + │ +1220 │ proplists:get_value(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1225:1 + │ +1225 │ proplists:lookup(self(), [a, {b, true}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:lookup(erlang:self(), ['a', {'b', 'true'}]). +Expression has type: 'none' | tuple() +Context expected type: {'b', 'true'} + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: tuple() + However the following candidate: 'none' + Differs from the expected type: {'b', 'true'} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1229:25 + │ +1229 │ proplists:lookup(a, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1239:5 + │ +1239 │ proplists:lookup(k, []). + │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:lookup('k', []). +Expression has type: 'none' | tuple() +Context expected type: 'none' + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'none' + However the following candidate: tuple() + Differs from the expected type: 'none' + +------------------------------ Detailed message ------------------------------ + + 'none' | tuple() is not compatible with 'none' + because + tuple() is not compatible with 'none' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1252:29 + │ +1252 │ proplists:lookup_all(a, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1265:5 + │ +1265 │ ╭ ╭ proplists:lookup_all( +1266 │ │ │ self(), +1267 │ │ │ [] +1268 │ │ │ ). + │ ╰─│─────^ proplists:lookup_all(erlang:self(), []). +Expression has type: [tuple()] +Context expected type: [] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is: tuple() + Context expects type: none() + ] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1291:34 + │ +1291 │ proplists:is_defined(self(), b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1295:25 + │ +1295 │ proplists:delete(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [A] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1295:25 + │ +1295 │ proplists:delete(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1311:5 + │ +1311 │ proplists:split(L, Ks). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:split(L, Ks). +Expression has type: {[[term()]], [term()]} +Context expected type: {[plist('a', 'b')], plist('a', 'b')} + │ + +Because in the expression's type: + { + [ + [ + Here the type is: term() + Context expects type: 'a' | {'a', 'b'} + No candidate matches in the expected union. + ] + ] + , [term()]} + +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[[term()]], [term()]} is not compatible with {[plist('a', 'b')], plist('a', 'b')} + because + [[term()]] is not compatible with [plist('a', 'b')] + because + [term()] is not compatible with plist('a', 'b') + because + [term()] is not compatible with ['a' | {'a', 'b'}] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1315:21 + │ +1315 │ proplists:split(b, []). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1319:25 + │ +1319 │ proplists:split([], b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1324:22 + │ +1324 │ proplists:to_map(b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [atom() | {term(), term()} | term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1358:24 + │ +1358 │ proplists:from_map(b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: #{K => V} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1358:24 + │ +1358 │ proplists:from_map(b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: #{dynamic() => dynamic()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1363:5 + │ +1363 │ proplists:get_value(a, [a]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('a', ['a']). +Expression has type: term() +Context expected type: 'true' | 'undefined' + │ + + term() is not compatible with 'true' | 'undefined' + because + term() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1368:5 + │ +1368 │ proplists:get_value(X, [a]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value(X, ['a']). +Expression has type: term() +Context expected type: 'true' | 'undefined' + │ + + term() is not compatible with 'true' | 'undefined' + because + term() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1373:5 + │ +1373 │ proplists:get_value(a, [a], b). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('a', ['a'], 'b'). +Expression has type: term() +Context expected type: 'true' | 'b' + │ + + term() is not compatible with 'true' | 'b' + because + term() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1416:5 + │ +1416 │ file:consult(some_file). + │ ^^^^^^^^^^^^^^^^^^^^^^^ file:consult('some_file'). +Expression has type: {'ok', [dynamic()]} | {'error', {number(), atom(), term()} | 'terminated' | 'badarg' | file:posix() | 'system_limit'} +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1428:5 + │ +1428 │ lists:keysort(2, [{a, c}, {b, d}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lists:keysort(2, [{'a', 'c'}, {'b', 'd'}]). +Expression has type: [{'a', 'c'} | {'b', 'd'}] +Context expected type: none() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1432:22 + │ +1432 │ lists:keysort(1, [3]). + │ ^^^ + │ │ + │ [3]. +Expression has type: [number()] +Context expected type: [tuple()] + │ + +Because in the expression's type: + [ + Here the type is: number() + Context expects type: tuple() + ] + +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [tuple()] + because + number() is not compatible with tuple() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1448:5 + │ +1448 │ ╭ ╭ lists:filtermap( +1449 │ │ │ fun(X) when X div 2 =:= 0 -> +1450 │ │ │ {true, integer_to_list(X)}; +1451 │ │ │ (X) -> + · │ │ +1454 │ │ │ [1, 2, 3, 4] +1455 │ │ │ ). + │ ╰─│─────^ lists:filtermap(fun, [1, 2, 3, 4]). +Expression has type: [string() | number()] +Context expected type: [number()] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: number() + However the following candidate: string() + Differs from the expected type: number() + ] + +------------------------------ Detailed message ------------------------------ + + [string() | number()] is not compatible with [number()] + because + string() | number() is not compatible with number() + because + string() is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1482:5 + │ +1482 │ erlang:min(X, Y). + │ ^^^^^^^^^^^^^^^^ erlang:min(X, Y). +Expression has type: number() +Context expected type: none() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1497:5 + │ +1497 │ erlang:max(X, Y). + │ ^^^^^^^^^^^^^^^^ erlang:max(X, Y). +Expression has type: atom() | number() +Context expected type: none() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1523:9 + │ +1523 │ abs(Atom). + │ ^^^^ Atom. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1536:31 + │ +1536 │ seq3_4_wip_neg() -> lists:seq(a, 2, 1). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1539:30 + │ +1539 │ seq3_5_neg() -> lists:seq(1, a, 1). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1542:33 + │ +1542 │ seq3_6_neg() -> lists:seq(1, 2, a). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1570:31 + │ +1570 │ seq2_4_wip_neg() -> lists:seq(a, 2). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1573:30 + │ +1573 │ seq2_5_neg() -> lists:seq(1, a). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1622:5 + │ +1622 │ ╭ timer:tc( +1623 │ │ fun() -> +1624 │ │ err +1625 │ │ end +1626 │ │ ). + │ ╰─────^ timer:tc(fun). +Expression has type: {number(), 'err'} +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1635:5 + │ +1635 │ ets:lookup(tab, Any). + │ ^^^^^^^^^^^^^^^^^^^^ ets:lookup('tab', Any). +Expression has type: [dynamic()] +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1639:5 + │ +1639 │ ets:lookup("not atom", Any). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ets:lookup(string_lit, Any). +Expression has type: [dynamic()] +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1639:16 + │ +1639 │ ets:lookup("not atom", Any). + │ ^^^^^^^^^^ string_lit. +Expression has type: string() +Context expected type: ets:tab() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1663:18 + │ +1663 │ ets:tab2list("not atom"). + │ ^^^^^^^^^^ string_lit. +Expression has type: string() +Context expected type: ets:tab() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1702:23 + │ +1702 │ lists:flatten([], 1). + │ ^ 1. +Expression has type: number() +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1711:19 + │ +1711 │ lists:flatten(3). + │ ^ 3. +Expression has type: number() +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1724:8 + │ +1724 │ -> lists:flatten(X). + │ ^^^^^^^^^^^^^^^^ + │ │ + │ lists:flatten(X). +Expression has type: [{A, B} | {B, A}] +Context expected type: [{A, B}] + │ + +Because in the expression's type: + [ + { + Here the type is: B + Context expects type: A + , A} + ] + +------------------------------ Detailed message ------------------------------ + + [{A, B} | {B, A}] is not compatible with [{A, B}] + because + {A, B} | {B, A} is not compatible with {A, B} + because + at tuple index 1: + {B, A} is not compatible with {A, B} + because + B is not compatible with A + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1757:5 + │ +1757 │ ╭ ╭ maps:without( +1758 │ │ │ [a, c, DOrE], +1759 │ │ │ #{ +1760 │ │ │ a => ka, + · │ │ +1764 │ │ │ } +1765 │ │ │ ). + │ ╰─│─────^ maps:without(['a', 'c', DOrE], #{..}). +Expression has type: #{a => 'ka', b => atom(), c => pid(), d => 'kd'} +Context expected type: #{b => atom()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{a => ...} + Context expects type: #{...} + The expected map has no corresponding key for: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared in the former but not in the latter and the latter map has no default association + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1769:18 + │ +1769 │ maps:without(non_list, #{}). + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1773:22 + │ +1773 │ maps:without([], non_map). + │ ^^^^^^^ 'non_map'. +Expression has type: 'non_map' +Context expected type: #{term() => term()} + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:1808:1 + │ +1808 │ ╭ maps_without_12_neg(None) -> +1809 │ │ maps:without( +1810 │ │ [a, b], +1811 │ │ None +1812 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1818:5 + │ +1818 │ ╭ ╭ maps:without( +1819 │ │ │ Keys, +1820 │ │ │ #{a => self(), b => self()} +1821 │ │ │ ). + │ ╰─│─────^ maps:without(Keys, #{..}). +Expression has type: #{a => pid(), b => pid()} +Context expected type: #{b := pid()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{b => ..., ...} + Context expects type: #{b := ..., ...} + The type of the expression is missing the following required keys: b. + +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1826:5 + │ +1826 │ ╭ ╭ maps:without( +1827 │ │ │ [a | improper_tail], +1828 │ │ │ #{a => self(), b => self()} +1829 │ │ │ ). + │ ╰─│─────^ maps:without(['a' | 'improper_tail'], #{..}). +Expression has type: #{a => pid(), b => pid()} +Context expected type: #{b := pid()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{b => ..., ...} + Context expects type: #{b := ..., ...} + The type of the expression is missing the following required keys: b. + +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1827:12 + │ +1827 │ [a | improper_tail], + │ ^^^^^^^^^^^^^^^^ 'improper_tail'. +Expression has type: 'improper_tail' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1837:5 + │ +1837 │ ╭ ╭ maps:without( +1838 │ │ │ Keys, +1839 │ │ │ #{a => ka, b => self()} +1840 │ │ │ ). + │ ╰─│─────^ maps:without(Keys, #{..}). +Expression has type: #{a => 'ka', b => pid()} +Context expected type: #{b := pid()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{b => ..., ...} + Context expects type: #{b := ..., ...} + The type of the expression is missing the following required keys: b. + +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1854:5 + │ +1854 │ maps:without([a, b], M). + │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:without(['a', 'b'], M). +Expression has type: #{c := 'cv', d := 'dv'} | #{c := 'cv', e => 'ev'} +Context expected type: #{c := atom()} + │ + +Because in the expression's type: + Here the type is: #{d := ...} + Context expects type: #{...} + The expected map has no corresponding key for: d. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1916:23 + │ +1916 │ custom_overloaded(X). + │ ^ + │ │ + │ X. +Expression has type: term() +Context expected type: atom() | binary() + │ + + term() is not compatible with atom() | binary() + because + term() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1939:5 + │ +1939 │ {A, N}. + │ ^^^^^^ + │ │ + │ {A, N}. +Expression has type: {atom(), number() | pid()} +Context expected type: {atom(), number()} + │ + +Because in the expression's type: + { atom(), + Here the type is a union type with some valid candidates: number() + However the following candidate: pid() + Differs from the expected type: number() + } + +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {atom(), number() | pid()} is not compatible with {atom(), number()} + because + number() | pid() is not compatible with number() + because + pid() is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2041:5 + │ +2041 │ filename:join(["server", "erl"]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([string_lit, string_lit]). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2046:5 + │ +2046 │ filename:join(["server", <<>>]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([string_lit, <<..>>]). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2051:5 + │ +2051 │ filename:join([<<>>, ""]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([<<..>>, string_lit]). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2066:5 + │ +2066 │ filename:join([<<>>, <<>>]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([<<..>>, <<..>>]). +Expression has type: file:filename_all() +Context expected type: binary() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: binary() + However the following candidate: string() + Differs from the expected type: binary() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with binary() + because + string() | binary() is not compatible with binary() + because + string() is not compatible with binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2081:19 + │ +2081 │ filename:join([<<>>, self()]). + │ ^^^^^^^^^^^^^^ + │ │ + │ [<<..>>, erlang:self()]. +Expression has type: [binary() | pid()] +Context expected type: [file:name_all()] + │ + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: binary() + However the following candidate: pid() + Differs from the expected type: string() | atom() | file:deep_list() | binary() + ] + +------------------------------ Detailed message ------------------------------ + + [binary() | pid()] is not compatible with [file:name_all()] + because + binary() | pid() is not compatible with file:name_all() + because + binary() | pid() is not compatible with string() | atom() | file:deep_list() | binary() + because + pid() is not compatible with string() | atom() | file:deep_list() | binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2086:5 + │ +2086 │ filename:join("server", "erl"). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join(string_lit, string_lit). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2091:5 + │ +2091 │ filename:join("server", <<>>). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join(string_lit, <<..>>). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2096:5 + │ +2096 │ filename:join(<<>>, ""). + │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join(<<..>>, string_lit). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2111:5 + │ +2111 │ filename:join(atom, <<>>). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join('atom', <<..>>). +Expression has type: file:filename_all() +Context expected type: binary() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: binary() + However the following candidate: string() + Differs from the expected type: binary() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with binary() + because + string() | binary() is not compatible with binary() + because + string() is not compatible with binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2121:25 + │ +2121 │ filename:join(<<>>, self()). + │ ^^^^^^ + │ │ + │ erlang:self(). +Expression has type: pid() +Context expected type: file:name_all() + │ + +Because in the expression's type: + Here the type is: pid() + Context expects type: string() | atom() | file:deep_list() | binary() + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + pid() is not compatible with file:name_all() + because + pid() is not compatible with string() | atom() | file:deep_list() | binary() + because + pid() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2150:5 + │ +2150 │ ╭ ╭ queue:filter( +2151 │ │ │ fun my_filter1/1, +2152 │ │ │ Q +2153 │ │ │ ). + │ ╰─│─────^ queue:filter(my_filter1/1, Q). +Expression has type: queue:queue(atom() | number()) +Context expected type: queue:queue(number()) + │ ╰─────' + +Because in the expression's type: + { + [ + Here the type is a union type with some valid candidates: number() + However the following candidate: atom() + Differs from the expected type: number() + ] + , [atom() | number()]} + +------------------------------ Detailed message ------------------------------ + + queue:queue(atom() | number()) is not compatible with queue:queue(number()) + because + {[atom() | number()], [atom() | number()]} is not compatible with queue:queue(number()) + because + at tuple index 1: + {[atom() | number()], [atom() | number()]} is not compatible with {[number()], [number()]} + because + [atom() | number()] is not compatible with [number()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2191:5 + │ +2191 │ M3. + │ ^^ + │ │ + │ M3. +Expression has type: #{count := number(), module := 'foo'} | #{module := 'foo'} +Context expected type: state1() + │ + +Because in the expression's type: + The type is a union type with some valid candidates: #{count := number(), module := 'foo'} + However, the following candidate doesn't match: + Here the type is: #{...} + Context expects type: #{count := ..., ...} + The type of the expression is missing the following required keys: count. + +------------------------------ Detailed message ------------------------------ + + #{count := number(), module := 'foo'} | #{module := 'foo'} is not compatible with state1() + because + #{count := number(), module := 'foo'} | #{module := 'foo'} is not compatible with #{count := number(), module := atom()} + because + #{module := 'foo'} is not compatible with #{count := number(), module := atom()} + key `count` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2223:13 + │ +2223 │ Atom + Sum + │ ^^^^ Atom. +Expression has type: atom() +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2279:5 + │ +2279 │ maps:remove(A, M). + │ ^^^^^^^^^^^^^^^^^ + │ │ + │ maps:remove(A, M). +Expression has type: #{a => number()} +Context expected type: #{a := number()} + │ + +Because in the expression's type: + Here the type is: #{a => ..., ...} + Context expects type: #{a := ..., ...} + The type of the expression is missing the following required keys: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2320:5 + │ +2320 │ ╭ ╭ maps:filtermap( +2321 │ │ │ fun +2322 │ │ │ (a, V) -> true; +2323 │ │ │ (b, V) -> {true, atom_to_binary(V)}; + · │ │ +2326 │ │ │ M +2327 │ │ │ ). + │ ╰─│─────^ maps:filtermap(fun, M). +Expression has type: #{a => atom() | binary(), b => atom() | binary(), c => atom() | binary()} +Context expected type: #{a := atom(), b := binary()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{a => ..., b => ..., ...} + Context expects type: #{a := ..., b := ..., ...} + The type of the expression is missing the following required keys: a, b. + +------------------------------ Detailed message ------------------------------ + +keys `a`, `b` are declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2342:5 + │ +2342 │ ╭ ╭ maps:filtermap( +2343 │ │ │ fun (_, V) -> +2344 │ │ │ {true, atom_to_binary(V)} +2345 │ │ │ end, +2346 │ │ │ M +2347 │ │ │ ). + │ ╰─│─────^ maps:filtermap(fun, M). +Expression has type: #{atom() => binary()} +Context expected type: #{atom() => atom()} + │ ╰─────' + +Because in the expression's type: + #{ atom() => + Here the type is: binary() + Context expects type: atom() + , ... } + +------------------------------ Detailed message ------------------------------ + + #{atom() => binary()} is not compatible with #{atom() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2354:23 + │ +2354 │ fun (_, _) -> err end, + │ ^^^ + │ │ + │ 'err'. +Expression has type: 'err' +Context expected type: boolean() | {'true', term()} + │ + +Because in the expression's type: + Here the type is: 'err' + Context expects type: 'false' | 'true' | {'true', term()} + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + 'err' is not compatible with boolean() | {'true', term()} + because + 'err' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2362:5 + │ +2362 │ ╭ ╭ maps:filtermap( +2363 │ │ │ fun (_, V) -> {true, atom_to_binary(V)} end, +2364 │ │ │ M +2365 │ │ │ ). + │ ╰─│─────^ maps:filtermap(fun, M). +Expression has type: #{atom() => binary()} +Context expected type: #{atom() => atom()} + │ ╰─────' + +Because in the expression's type: + #{ atom() => + Here the type is: binary() + Context expects type: atom() + , ... } + +------------------------------ Detailed message ------------------------------ + + #{atom() => binary()} is not compatible with #{atom() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2363:45 + │ +2363 │ fun (_, V) -> {true, atom_to_binary(V)} end, + │ ^ V. +Expression has type: binary() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2377:5 + │ +2377 │ re:replace(Subj, "+", "-", [{return, binary}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re:replace(Subj, string_lit, string_lit, [{'return', 'binary'}]). +Expression has type: binary() +Context expected type: string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2381:5 + │ +2381 │ re:replace(Subj, "+", "-", [{return, list}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re:replace(Subj, string_lit, string_lit, [{'return', 'list'}]). +Expression has type: string() +Context expected type: binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2385:22 + │ +2385 │ Res = re:replace(Subj, "+", "-", [{return, list}]), + │ ^^^^ + │ │ + │ Subj. +Expression has type: atom() +Context expected type: iodata() | unicode:charlist() + │ + +Because in the expression's type: + Here the type is: atom() + Context expects type: iolist() | binary() + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + atom() is not compatible with iodata() | unicode:charlist() + because + atom() is not compatible with iolist() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2386:5 + │ +2386 │ Res. + │ ^^^ Res. +Expression has type: string() +Context expected type: binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2390:38 + │ +2390 │ Res = re:replace(Subj, "+", "-", [{return, something}]), + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ [{'return', 'something'}]. +Expression has type: [{'return', 'something'}] +Context expected type: [{'newline', 'cr' | 'lf' | 'any' | 'crlf' | 'anycrlf'} | 'notempty_atstart' | 'noteol' | 'bsr_unicode' | 'notbol' | 'global' | {'match_limit_recursion', number()} | 'bsr_anycrlf' | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored'] + │ + +Because in the expression's type: + [ + { 'return', + Here the type is: 'something' + Context expects type: 'iodata' | 'list' | 'binary' + No candidate matches in the expected union. + } + ] + +------------------------------ Detailed message ------------------------------ + + [{'return', 'something'}] is not compatible with [{'newline', 'cr' | 'lf' | 'any' | 'crlf' | 'anycrlf'} | 'notempty_atstart' | 'noteol' | 'bsr_unicode' | 'notbol' | 'global' | {'match_limit_recursion', number()} | 'bsr_anycrlf' | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored'] + because + {'return', 'something'} is not compatible with {'newline', 'cr' | 'lf' | 'any' | 'crlf' | 'anycrlf'} | 'notempty_atstart' | 'noteol' | 'bsr_unicode' | 'notbol' | 'global' | {'match_limit_recursion', number()} | 'bsr_anycrlf' | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored' + because + at tuple index 2: + {'return', 'something'} is not compatible with {'return', 'iodata' | 'list' | 'binary'} + because + 'something' is not compatible with 'iodata' | 'list' | 'binary' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2506:5 + │ +2506 │ lists:partition(fun is_number/1, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ lists:partition(fun, L). +Expression has type: {[number()], [atom()]} +Context expected type: {[atom()], [number()]} + │ + +Because in the expression's type: + { + [ + Here the type is: number() + Context expects type: atom() + ] + , [atom()]} + +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[number()], [atom()]} is not compatible with {[atom()], [number()]} + because + [number()] is not compatible with [atom()] + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2518:5 + │ +2518 │ lists:partition(fun({_Term, V}) -> is_number(V) end, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ lists:partition(fun, L). +Expression has type: {[{term(), number()}], [{term(), atom()}]} +Context expected type: {[{term(), atom()}], [{term(), number()}]} + │ + +Because in the expression's type: + { + [ + { term(), + Here the type is: number() + Context expects type: atom() + } + ] + , [{term(), atom()}]} + +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[{term(), number()}], [{term(), atom()}]} is not compatible with {[{term(), atom()}], [{term(), number()}]} + because + [{term(), number()}] is not compatible with [{term(), atom()}] + because + at tuple index 2: + {term(), number()} is not compatible with {term(), atom()} + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2536:5 + │ +2536 │ lists:partition(fun({ok, _}) -> true; (_) -> false end, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ lists:partition(fun, L). +Expression has type: {[{'ok', atom()}], [{'ok', atom()} | {'error', term()}]} +Context expected type: {[{'ok', atom()}], [{'error', term()}]} + │ + +Because in the expression's type: + { [{'ok', atom()}], + [ + { + Here the type is: 'ok' + Context expects type: 'error' + , atom()} + ] + } + +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {[{'ok', atom()}], [{'ok', atom()} | {'error', term()}]} is not compatible with {[{'ok', atom()}], [{'error', term()}]} + because + [{'ok', atom()} | {'error', term()}] is not compatible with [{'error', term()}] + because + {'ok', atom()} | {'error', term()} is not compatible with {'error', term()} + because + at tuple index 1: + {'ok', atom()} is not compatible with {'error', term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2576:33 + │ +2576 │ maps_intersect_2_neg(M1, M2) -> maps:intersect(M1, M2). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:intersect(M1, M2). +Expression has type: #{a => number()} +Context expected type: #{a := number()} + │ + +Because in the expression's type: + Here the type is: #{a => ..., ...} + Context expects type: #{a := ..., ...} + The type of the expression is missing the following required keys: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2586:33 + │ +2586 │ maps_intersect_4_neg(M1, M2) -> maps:intersect(M1, M2). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:intersect(M1, M2). +Expression has type: #{a => number()} +Context expected type: #{a => 'true'} + │ + +Because in the expression's type: + #{ a => + Here the type is: number() + Context expects type: 'true' + , ... } + +------------------------------ Detailed message ------------------------------ + + #{a => number()} is not compatible with #{a => 'true'} + because + at key `a`: + #{a => number()} is not compatible with #{a => 'true'} + because + number() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2596:33 + │ +2596 │ maps_intersect_6_neg(M1, M2) -> maps:intersect(M1, M2). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:intersect(M1, M2). +Expression has type: #{a => number()} +Context expected type: #{a := number()} + │ + +Because in the expression's type: + Here the type is: #{a => ..., ...} + Context expects type: #{a := ..., ...} + The type of the expression is missing the following required keys: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2709:40 + │ +2709 │ (foo, A) -> binary_to_atom(A); + │ ^ A. +Expression has type: atom() +Context expected type: binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2710:40 + │ +2710 │ (bar, B) -> atom_to_binary(B); + │ ^ B. +Expression has type: binary() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2711:50 + │ +2711 │ ({foo, bar}, I) -> binary_to_integer(I); + │ ^ I. +Expression has type: number() +Context expected type: binary() + +202 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-28.pretty new file mode 100644 index 0000000000..ec107b3c14 --- /dev/null +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-28.pretty @@ -0,0 +1,3258 @@ +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:26:5 + │ +26 │ element(4, Tup). + │ ^^^^^^^^^^^^^^^ erlang:element(4, Tup). +Expression has type: #{dynamic() => dynamic()} +Context expected type: atom() + +error: index_out_of_bounds (See https://fb.me/eqwalizer_errors#index_out_of_bounds) + ┌─ check/src/custom.erl:30:5 + │ +30 │ element(42, Tup). + │ ^^^^^^^^^^^^^^^^ 42. +Tried to access element 42 of a tuple with 3 elements + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:40:5 + │ +40 │ element(2, Tup). + │ ^^^^^^^^^^^^^^^ erlang:element(2, Tup). +Expression has type: number() | string() | atom() +Context expected type: #{dynamic() => dynamic()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:44:16 + │ +44 │ element(2, Tup). + │ ^^^ + │ │ + │ Tup. +Expression has type: {atom(), string()} | [dynamic()] +Context expected type: tuple() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: {atom(), string()} + However the following candidate: [dynamic()] + Differs from the expected type: tuple() + +------------------------------ Detailed message ------------------------------ + + {atom(), string()} | [dynamic()] is not compatible with tuple() + because + [dynamic()] is not compatible with tuple() + +error: index_out_of_bounds (See https://fb.me/eqwalizer_errors#index_out_of_bounds) + ┌─ check/src/custom.erl:48:5 + │ +48 │ element(42, Tup). + │ ^^^^^^^^^^^^^^^^ 42. +Tried to access element 42 of a tuple with 2 elements + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:54:5 + │ +54 │ element(N, Tup). + │ ^^^^^^^^^^^^^^^ erlang:element(N, Tup). +Expression has type: atom() | number() | string() +Context expected type: #{dynamic() => dynamic()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:58:5 + │ +58 │ element(N, Tup). + │ ^^^^^^^^^^^^^^^ + │ │ + │ erlang:element(N, Tup). +Expression has type: atom() | number() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + atom() | number() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:68:5 + │ +68 │ element(1, Tup). + │ ^^^^^^^^^^^^^^^ + │ │ + │ erlang:element(1, Tup). +Expression has type: dynamic() | number() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: dynamic() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + dynamic() | number() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:86:5 + │ +86 │ element(N, Rec). + │ ^^^^^^^^^^^^^^^ + │ │ + │ erlang:element(N, Rec). +Expression has type: 'foo' | 'ok' | 'error' | number() | string() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'error' | 'foo' | 'ok' + However the following candidate: string() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + 'foo' | 'ok' | 'error' | number() | string() is not compatible with atom() + because + string() is not compatible with atom() + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:91:1 + │ +91 │ ╭ element_2_none_1(Tup) -> +92 │ │ element(42, Tup). + │ ╰────────────────────^ Clause is not covered by spec + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:95:1 + │ +95 │ ╭ element_2_none_2(N, Tup) -> +96 │ │ element(N, Tup). + │ ╰───────────────────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:108:5 + │ +108 │ maps:get(K, M). + │ ^^^^^^^^^^^^^^ maps:get(K, M). +Expression has type: number() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:128:5 + │ +128 │ Res. + │ ^^^ Res. +Expression has type: number() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:154:12 + │ +154 │ get(a, M). + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:160:23 + │ +160 │ Res = maps:get(a, M), + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:167:17 + │ +167 │ maps:get(a, M, false). + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:173:23 + │ +173 │ Res = maps:get(a, M, false), + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:193:5 + │ +193 │ maps:get(K, M, 0). + │ ^^^^^^^^^^^^^^^^^ + │ │ + │ maps:get(K, M, 0). +Expression has type: number() | atom() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:200:5 + │ +200 │ Res. + │ ^^^ + │ │ + │ Res. +Expression has type: number() | atom() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:206:5 + │ +206 │ ╭ ╭ { +207 │ │ │ maps:get(a, M, undefined), +208 │ │ │ maps:get(n, M, undefined) +209 │ │ │ }. + │ ╰─│─────^ {maps:get('a', M, 'undefined'), maps:get('n', M, 'undefined')}. +Expression has type: {atom(), 'undefined' | number()} +Context expected type: {atom(), number()} + │ ╰─────' + +Because in the expression's type: + { atom(), + Here the type is a union type with some valid candidates: number() + However the following candidate: 'undefined' + Differs from the expected type: number() + } + +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {atom(), 'undefined' | number()} is not compatible with {atom(), number()} + because + 'undefined' | number() is not compatible with number() + because + 'undefined' is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:221:27 + │ +221 │ map_get_2_17_neg(V, M) -> maps:get(V, M). + │ ^^^^^^^^^^^^^^ + │ │ + │ maps:get(V, M). +Expression has type: 'a_v' | 'c_v' +Context expected type: 'a_v' | 'b_v' + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'a_v' + However the following candidate: 'c_v' + Differs from the expected type: 'a_v' | 'b_v' + +------------------------------ Detailed message ------------------------------ + + 'a_v' | 'c_v' is not compatible with 'a_v' | 'b_v' + because + 'c_v' is not compatible with 'a_v' | 'b_v' + because + 'c_v' is not compatible with 'a_v' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:233:27 + │ +233 │ map_get_3_19_neg(V, M) -> maps:get(V, M, undefined). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:get(V, M, 'undefined'). +Expression has type: 'undefined' | 'a_v' | 'c_v' +Context expected type: 'a_v' | 'b_v' | 'undefined' + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'undefined' | 'a_v' + However the following candidate: 'c_v' + Differs from the expected type: 'a_v' | 'b_v' | 'undefined' + +------------------------------ Detailed message ------------------------------ + + 'undefined' | 'a_v' | 'c_v' is not compatible with 'a_v' | 'b_v' | 'undefined' + because + 'c_v' is not compatible with 'a_v' | 'b_v' | 'undefined' + because + 'c_v' is not compatible with 'a_v' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:309:5 + │ +309 │ Res. + │ ^^^ Res. +Expression has type: {'value', #{}} | 'false' +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:363:23 + │ +363 │ fun (_, _) -> self() end, + │ ^^^^^^ erlang:self(). +Expression has type: pid() +Context expected type: boolean() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:382:17 + │ +382 │ maps:filter(F, M). + │ ^ F. +Expression has type: fun(() -> pid()) +Context expected type: fun((number(), 'a' | 'b') -> boolean()) + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:389:17 + │ +389 │ maps:filter(F, M). + │ ^ + │ │ + │ F. +Expression has type: fun((fun((T) -> boolean()), [T]) -> [T]) with 1 type parameter +Context expected type: fun((number(), 'a' | 'b') -> boolean()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun()/2 with 1 type parameter + Context expects type: fun((number(), 'a' | 'b') -> boolean()) with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:413:37 + │ +413 │ maps:filter(fun erlang:'=:='/2, X). + │ ^ + │ │ + │ X. +Expression has type: #{K => V} | 'a' +Context expected type: #{term() => term()} | maps:iterator() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: #{K => V} + However the following candidate: 'a' + Differs from the expected type: #{term() => term()} | maps:iterator() + +------------------------------ Detailed message ------------------------------ + + #{K => V} | 'a' is not compatible with #{term() => term()} | maps:iterator() + because + 'a' is not compatible with #{term() => term()} | maps:iterator() + because + 'a' is not compatible with #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:425:20 + │ +425 │ maps:filter(F, non_kv), + │ ^^^^^^ + │ │ + │ 'non_kv'. +Expression has type: 'non_kv' +Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:454:5 + │ +454 │ ╭ ╭ maps:map( +455 │ │ │ fun (_, _) -> self() end, +456 │ │ │ M +457 │ │ │ ). + │ ╰─│─────^ maps:map(fun, M). +Expression has type: #{number() => pid()} +Context expected type: #{number() => boolean()} + │ ╰─────' + +Because in the expression's type: + #{ number() => + Here the type is: pid() + Context expects type: boolean() + , ... } + +------------------------------ Detailed message ------------------------------ + + #{number() => pid()} is not compatible with #{number() => boolean()} + the default associations are not compatible + because + pid() is not compatible with boolean() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:474:14 + │ +474 │ maps:map(F, M). + │ ^ F. +Expression has type: fun(() -> pid()) +Context expected type: fun((number(), 'a' | 'b') -> term()) + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:481:14 + │ +481 │ maps:map(F, M). + │ ^ + │ │ + │ F. +Expression has type: fun((fun((A) -> B), [A]) -> [B]) with 2 type parameters +Context expected type: fun((number(), 'a' | 'b') -> term()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((fun((A) -> B), [A]) -> [B]) with 2 type parameters + Context expects type: fun((number(), 'a' | 'b') -> term()) with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:497:5 + │ +497 │ maps:map(F, M). + │ ^^^^^^^^^^^^^^ + │ │ + │ maps:map(F, M). +Expression has type: #{a := boolean(), b := boolean()} +Context expected type: #{a => 'a', b => 'b'} + │ + +Because in the expression's type: + #{ a => + Here the type is: boolean() + Context expects type: 'a' + , ... } + +------------------------------ Detailed message ------------------------------ + + #{a := boolean(), b := boolean()} is not compatible with #{a => 'a', b => 'b'} + because + at key `a`: + #{a := boolean(), b := boolean()} is not compatible with #{a => 'a', b => 'b'} + because + boolean() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:503:17 + │ +503 │ maps:map(F, non_kv), + │ ^^^^^^ + │ │ + │ 'non_kv'. +Expression has type: 'non_kv' +Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} + +error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) + ┌─ check/src/custom.erl:538:9 + │ +538 │ fun (K, V) -> [K, V] end, [], M). + │ ^^^^^^^^^^^^^^^^^^^^^^^^ fun. +fun with arity 2 used as fun with 3 arguments + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:544:5 + │ +544 │ ╭ ╭ maps:fold( +545 │ │ │ fun (_, _, Acc) -> [Acc] end, +546 │ │ │ [], +547 │ │ │ M +548 │ │ │ ). + │ ╰─│─────^ maps:fold(fun, [], M). +Expression has type: [[[]]] +Context expected type: [number() | 'a' | 'b'] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is: [[]] + Context expects type: number() | 'a' | 'b' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [[[]]] is not compatible with [number() | 'a' | 'b'] + because + [[]] is not compatible with number() | 'a' | 'b' + because + [[]] is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:545:28 + │ +545 │ fun (_, _, Acc) -> [Acc] end, + │ ^^^^^ + │ │ + │ [Acc]. +Expression has type: [[[[]]]] +Context expected type: [[[]]] + │ + +Because in the expression's type: + [ + [ + [ + Here the type is: [] + Context expects type: none() + ] + ] + ] + +------------------------------ Detailed message ------------------------------ + + [[[[]]]] is not compatible with [[[]]] + because + [[[]]] is not compatible with [[]] + because + [[]] is not compatible with [] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:552:5 + │ +552 │ ╭ maps:fold( +553 │ │ fun (_, _, Acc) -> Acc end, +554 │ │ [], +555 │ │ non_kv +556 │ │ ). + │ ╰─────^ maps:fold(fun, [], 'non_kv'). +Expression has type: [] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:555:9 + │ +555 │ non_kv + │ ^^^^^^ + │ │ + │ 'non_kv'. +Expression has type: 'non_kv' +Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:560:1 + │ +560 │ ╭ maps_fold_3_6(None) -> +561 │ │ maps:fold( +562 │ │ None, +563 │ │ #{}, +564 │ │ #{1 => 1} +565 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:568:1 + │ +568 │ ╭ maps_fold_3_7(None) -> +569 │ │ maps:fold( +570 │ │ None, +571 │ │ None, +572 │ │ None +573 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:578:5 + │ +578 │ ╭ ╭ maps:fold( +579 │ │ │ fun (_K, A, _Acc) -> A end, +580 │ │ │ [], +581 │ │ │ M +582 │ │ │ ). + │ ╰─│─────^ maps:fold(fun, [], M). +Expression has type: [] | atom() +Context expected type: atom() + │ ╰─────' + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: [] + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + [] | atom() is not compatible with atom() + because + [] is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:601:9 + │ +601 │ fun folder_bad/3, + │ ^^^^^^^^^^^^^^^^ + │ │ + │ folder_bad/3. +Expression has type: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter +Context expected type: fun((number(), 'a', []) -> term()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter + Context expects type: fun((number(), 'a', []) -> term()) with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:601:9 + │ +601 │ fun folder_bad/3, + │ ^^^^^^^^^^^^^^^^ + │ │ + │ folder_bad/3. +Expression has type: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter +Context expected type: fun((number(), 'a', [] | dynamic()) -> term()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter + Context expects type: fun()/3 with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:601:9 + │ +601 │ fun folder_bad/3, + │ ^^^^^^^^^^^^^^^^ + │ │ + │ folder_bad/3. +Expression has type: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter +Context expected type: fun((number(), 'a', [] | dynamic()) -> [] | dynamic()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter + Context expects type: fun()/3 with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:636:5 + │ +636 │ ╭ ╭ maps:fold( +637 │ │ │ fun +638 │ │ │ (_K, {i, I}, Acc) -> +639 │ │ │ [I | Acc]; + · │ │ +646 │ │ │ M +647 │ │ │ ). + │ ╰─│─────^ maps:fold(fun, [], M). +Expression has type: [number() | binary() | atom()] +Context expected type: [binary()] | [number()] | [atom()] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: binary() + However the following candidate: number() + Differs from the expected type: binary() + ] + +------------------------------ Detailed message ------------------------------ + + [number() | binary() | atom()] is not compatible with [binary()] | [number()] | [atom()] + because + [number() | binary() | atom()] is not compatible with [binary()] + because + number() | binary() | atom() is not compatible with binary() + because + number() is not compatible with binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:671:41 + │ +671 │ maps_to_list_7_neg(Num) -> maps:to_list(Num). + │ ^^^ + │ │ + │ Num. +Expression has type: number() +Context expected type: #{term() => term()} | maps:iterator() + │ + + number() is not compatible with #{term() => term()} | maps:iterator() + because + number() is not compatible with #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:675:25 + │ +675 │ maps_merge_1(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'b' | 'a' | 'c' => number() | string() | atom()} +Context expected type: #{a => string(), b => number(), c => atom()} + │ + +Because in the expression's type: + Here the type is: #{'b' | 'a' | 'c' => number() | string() | atom()} + Context expects type: #{...} (no default association) + The expected map has no default association while the type of the expression has one. + +------------------------------ Detailed message ------------------------------ + + #{'b' | 'a' | 'c' => number() | string() | atom()} is not compatible with #{a => string(), b => number(), c => atom()} + key a is not present in the former map but is incompatible with its default association + because + number() | string() | atom() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:679:25 + │ +679 │ maps_merge_2(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'b' | 'a' | 'c' => number() | string() | atom()} +Context expected type: #{a => string(), b => number() | boolean(), c => atom()} + │ + +Because in the expression's type: + Here the type is: #{'b' | 'a' | 'c' => number() | string() | atom()} + Context expects type: #{...} (no default association) + The expected map has no default association while the type of the expression has one. + +------------------------------ Detailed message ------------------------------ + + #{'b' | 'a' | 'c' => number() | string() | atom()} is not compatible with #{a => string(), b => number() | boolean(), c => atom()} + key a is not present in the former map but is incompatible with its default association + because + number() | string() | atom() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:683:25 + │ +683 │ maps_merge_3(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'b' | 'a' | 'c' => number() | string() | atom()} +Context expected type: #{a := string(), b := boolean(), c => atom()} + │ + +Because in the expression's type: + Here the type is: #{...} + Context expects type: #{a := ..., b := ..., ...} + The type of the expression is missing the following required keys: a, b. + +------------------------------ Detailed message ------------------------------ + +keys `a`, `b` are declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:697:44 + │ +697 │ maps_merge_7_neg(M1, M2) -> maps:merge(M1, M2). + │ ^^ M2. +Expression has type: number() +Context expected type: #{a => binary()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:701:25 + │ +701 │ maps_merge_8(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'a' | 'b' => atom() | number()} +Context expected type: #{a := atom(), b := number()} | #{a := atom()} + │ + +Because in the expression's type: + Here the type is: #{...} + Context expects type: #{a := ..., b := ..., ...} + The type of the expression is missing the following required keys: a, b. + +------------------------------ Detailed message ------------------------------ + + #{'a' | 'b' => atom() | number()} is not compatible with #{a := atom(), b := number()} | #{a := atom()} + because + #{'a' | 'b' => atom() | number()} is not compatible with #{a := atom(), b := number()} + keys `a`, `b` are declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:721:9 + │ +721 │ fun erlang:binary_to_list/1, + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:binary_to_list/1. +Expression has type: fun((binary()) -> [number()]) +Context expected type: fun((number()) -> boolean() | {'true', term()}) + │ + +Because in the expression's type: + fun((binary()) -> + Here the type is: [number()] + Context expects type: 'false' | 'true' | {'true', term()} + No candidate matches in the expected union. + ) + +------------------------------ Detailed message ------------------------------ + + fun((binary()) -> [number()]) is not compatible with fun((number()) -> boolean() | {'true', term()}) + because + [number()] is not compatible with boolean() | {'true', term()} + because + [number()] is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:739:20 + │ +739 │ (3) -> wrong_ret end, + │ ^^^^^^^^^ + │ │ + │ 'wrong_ret'. +Expression has type: 'wrong_ret' +Context expected type: boolean() | {'true', term()} + │ + +Because in the expression's type: + Here the type is: 'wrong_ret' + Context expects type: 'false' | 'true' | {'true', term()} + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:749:9 + │ +749 │ not_a_list + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:791:17 + │ +791 │ Res + │ ^^^ + │ │ + │ Res. +Expression has type: {'true', 'a'} | 'wrong_ret' +Context expected type: boolean() | {'true', term()} + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: {'true', 'a'} + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | {'true', term()} + +------------------------------ Detailed message ------------------------------ + + {'true', 'a'} | 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:827:9 + │ +827 │ ╭ ╭ fun (a) -> [a]; +828 │ │ │ (b) -> true; +829 │ │ │ (c) -> wrong_ret end, + │ ╰─│────────────────────────────────^ fun. +Expression has type: fun(('a' | 'b') -> ['a'] | 'true' | 'wrong_ret') +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ ╰────────────────────────────────' + +Because in the expression's type: + fun(('a' | 'b') -> + Here the type is a union type with some valid candidates: ['a'] | 'true' + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + ) + +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'true' | 'wrong_ret') is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'true' | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:829:20 + │ +829 │ (c) -> wrong_ret end, + │ ^^^^^^^^^ + │ │ + │ 'wrong_ret'. +Expression has type: 'wrong_ret' +Context expected type: boolean() | ['a' | 'b'] + │ + +Because in the expression's type: + Here the type is: 'wrong_ret' + Context expects type: 'false' | 'true' | ['a' | 'b'] + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:837:9 + │ +837 │ ╭ ╭ fun (1) -> {true, a}; +838 │ │ │ (2) -> true end, + │ ╰─│───────────────────────────^ fun. +Expression has type: fun((dynamic()) -> {'true', 'a'} | 'true') +Context expected type: fun((Item) -> boolean() | [Item]) + │ ╰───────────────────────────' + +Because in the expression's type: + fun((dynamic()) -> + Here the type is a union type with some valid candidates: 'true' + However the following candidate: {'true', 'a'} + Differs from the expected type: 'false' | 'true' | [Item] + ) + +------------------------------ Detailed message ------------------------------ + + fun((dynamic()) -> {'true', 'a'} | 'true') is not compatible with fun((Item) -> boolean() | [Item]) + because + {'true', 'a'} | 'true' is not compatible with boolean() | [Item] + because + {'true', 'a'} is not compatible with boolean() | [Item] + expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:837:20 + │ +837 │ fun (1) -> {true, a}; + │ ^^^^^^^^^ + │ │ + │ {'true', 'a'}. +Expression has type: {'true', 'a'} +Context expected type: boolean() | [dynamic()] + │ + +Because in the expression's type: + Here the type is: {'true', 'a'} + Context expects type: 'false' | 'true' | [dynamic()] + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + +expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:839:9 + │ +839 │ not_a_queue + │ ^^^^^^^^^^^ + │ │ + │ 'not_a_queue'. +Expression has type: 'not_a_queue' +Context expected type: queue:queue(Item) + │ + +Because in the expression's type: + Here the type is: 'not_a_queue' + Context expects type: {[Item], [Item]} + +------------------------------ Detailed message ------------------------------ + + 'not_a_queue' is not compatible with queue:queue(Item) + because + 'not_a_queue' is not compatible with {[Item], [Item]} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:839:9 + │ +839 │ not_a_queue + │ ^^^^^^^^^^^ + │ │ + │ 'not_a_queue'. +Expression has type: 'not_a_queue' +Context expected type: queue:queue(dynamic()) + │ + +Because in the expression's type: + Here the type is: 'not_a_queue' + Context expects type: {[dynamic()], [dynamic()]} + +------------------------------ Detailed message ------------------------------ + + 'not_a_queue' is not compatible with queue:queue(dynamic()) + because + 'not_a_queue' is not compatible with {[dynamic()], [dynamic()]} + +error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) + ┌─ check/src/custom.erl:846:9 + │ +846 │ ╭ fun (wrong, arity) -> +847 │ │ [a] +848 │ │ end, + │ ╰───────────^ fun. +fun with arity 2 used as fun with 1 arguments + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:857:9 + │ +857 │ ╭ ╭ fun (1) -> {true, a}; +858 │ │ │ (X) -> case X of +859 │ │ │ true -> +860 │ │ │ [a]; + · │ │ +863 │ │ │ end +864 │ │ │ end, + │ ╰─│───────────^ fun. +Expression has type: fun(('a' | 'b') -> ['a'] | 'false' | {'true', 'a'}) +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ ╰───────────' + +Because in the expression's type: + fun(('a' | 'b') -> + Here the type is a union type with some valid candidates: ['a'] | 'false' + However the following candidate: {'true', 'a'} + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + ) + +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'false' | {'true', 'a'}) is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'false' | {'true', 'a'} is not compatible with boolean() | ['a' | 'b'] + because + {'true', 'a'} is not compatible with boolean() | ['a' | 'b'] + expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:857:20 + │ +857 │ fun (1) -> {true, a}; + │ ^^^^^^^^^ + │ │ + │ {'true', 'a'}. +Expression has type: {'true', 'a'} +Context expected type: boolean() | ['a' | 'b'] + │ + +Because in the expression's type: + Here the type is: {'true', 'a'} + Context expects type: 'false' | 'true' | ['a' | 'b'] + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + +expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:873:9 + │ +873 │ ╭ ╭ fun (a) -> [a]; +874 │ │ │ (X) -> +875 │ │ │ Res = case X of +876 │ │ │ true -> + · │ │ +881 │ │ │ Res +882 │ │ │ end, + │ ╰─│───────────^ fun. +Expression has type: fun(('a' | 'b') -> ['a'] | 'wrong_ret') +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ ╰───────────' + +Because in the expression's type: + fun(('a' | 'b') -> + Here the type is a union type with some valid candidates: ['a'] + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + ) + +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'wrong_ret') is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:881:17 + │ +881 │ Res + │ ^^^ + │ │ + │ Res. +Expression has type: ['a'] | 'wrong_ret' +Context expected type: boolean() | ['a' | 'b'] + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: ['a'] + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + +------------------------------ Detailed message ------------------------------ + + ['a'] | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:891:9 + │ +891 │ fun list_to_atom/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:list_to_atom/1. +Expression has type: fun((string()) -> atom()) +Context expected type: fun((dynamic()) -> boolean() | [dynamic()]) + │ + +Because in the expression's type: + fun((string()) -> + Here the type is: atom() + Context expects type: 'false' | 'true' | [dynamic()] + No candidate matches in the expected union. + ) + +------------------------------ Detailed message ------------------------------ + + fun((string()) -> atom()) is not compatible with fun((dynamic()) -> boolean() | [dynamic()]) + because + atom() is not compatible with boolean() | [dynamic()] + because + atom() is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:891:9 + │ +891 │ fun list_to_atom/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:list_to_atom/1. +Expression has type: fun((string()) -> atom()) +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ + +Because in the expression's type: + fun((string()) -> + Here the type is: atom() + Context expects type: 'false' | 'true' | ['a' | 'b'] + No candidate matches in the expected union. + ) + +------------------------------ Detailed message ------------------------------ + + fun((string()) -> atom()) is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + atom() is not compatible with boolean() | ['a' | 'b'] + because + atom() is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:900:9 + │ +900 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:900:9 + │ +900 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:909:9 + │ +909 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:909:9 + │ +909 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:919:9 + │ +919 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:919:9 + │ +919 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:925:1 + │ +925 │ ╭ queue_filter_13_neg(Q) -> +926 │ │ queue:filter( +927 │ │ fun atom_to_list/1, +928 │ │ Q +929 │ │ ), +930 │ │ ok. + │ ╰──────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:927:9 + │ +927 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:927:9 + │ +927 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:955:5 + │ +955 │ ╭ lists:keystore( +956 │ │ a, 1, +957 │ │ [{foo, b}, {c, d}], +958 │ │ non_tuple +959 │ │ ). + │ ╰─────^ lists:keystore('a', 1, [{'foo', 'b'}, {'c', 'd'}], 'non_tuple'). +Expression has type: [{'foo', 'b'} | {'c', 'd'} | dynamic()] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:958:9 + │ +958 │ non_tuple + │ ^^^^^^^^^ 'non_tuple'. +Expression has type: 'non_tuple' +Context expected type: tuple() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:966:5 + │ +966 │ ╭ lists:keystore( +967 │ │ a, 1, +968 │ │ [non_tuple], +969 │ │ {replacement} +970 │ │ ). + │ ╰─────^ lists:keystore('a', 1, ['non_tuple'], {'replacement'}). +Expression has type: [dynamic() | {'replacement'}] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:968:9 + │ +968 │ [non_tuple], + │ ^^^^^^^^^^^ + │ │ + │ ['non_tuple']. +Expression has type: ['non_tuple'] +Context expected type: [tuple()] + │ + +Because in the expression's type: + [ + Here the type is: 'non_tuple' + Context expects type: tuple() + ] + +------------------------------ Detailed message ------------------------------ + + ['non_tuple'] is not compatible with [tuple()] + because + 'non_tuple' is not compatible with tuple() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:975:5 + │ +975 │ ╭ lists:keystore( +976 │ │ a, 1, +977 │ │ non_list, +978 │ │ {replacement} +979 │ │ ). + │ ╰─────^ lists:keystore('a', 1, 'non_list', {'replacement'}). +Expression has type: [dynamic() | {'replacement'}] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:977:9 + │ +977 │ non_list, + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [tuple()] + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:983:1 + │ +983 │ ╭ keystore_7(None) -> +984 │ │ lists:keystore( +985 │ │ a, 1, +986 │ │ None, +987 │ │ {replacement} +988 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:991:1 + │ +991 │ ╭ keystore_8(None) -> +992 │ │ lists:keystore( +993 │ │ a, 1, +994 │ │ None, +995 │ │ None +996 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1011:25 + │ +1011 │ lists:keytake(a, 1, non_tup), + │ ^^^^^^^ 'non_tup'. +Expression has type: 'non_tup' +Context expected type: [Tuple] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1011:25 + │ +1011 │ lists:keytake(a, 1, non_tup), + │ ^^^^^^^ 'non_tup'. +Expression has type: 'non_tup' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1016:25 + │ +1016 │ lists:keytake(a, 1, non_list), + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [Tuple] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1016:25 + │ +1016 │ lists:keytake(a, 1, non_list), + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1021:22 + │ +1021 │ lists:keytake(a, non_num, []), + │ ^^^^^^^ 'non_num'. +Expression has type: 'non_num' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1038:15 + │ +1038 │ lists:sum([a, 1]). + │ ^^^^^^ + │ │ + │ ['a', 1]. +Expression has type: ['a' | number()] +Context expected type: [number()] + │ + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: number() + However the following candidate: 'a' + Differs from the expected type: number() + ] + +------------------------------ Detailed message ------------------------------ + + ['a' | number()] is not compatible with [number()] + because + 'a' | number() is not compatible with number() + because + 'a' is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1042:15 + │ +1042 │ lists:sum(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [number()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1062:15 + │ +1062 │ lists:max(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [T] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1062:15 + │ +1062 │ lists:max(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1082:15 + │ +1082 │ lists:min(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [T] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1082:15 + │ +1082 │ lists:min(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1100:5 + │ +1100 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). +Expression has type: term() +Context expected type: pid() | 'undefined' + │ + + term() is not compatible with pid() | 'undefined' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1106:5 + │ +1106 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). +Expression has type: term() +Context expected type: pid() | 'undefined' | 'v' + │ + + term() is not compatible with pid() | 'undefined' | 'v' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1111:5 + │ +1111 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', L). +Expression has type: term() +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1117:5 + │ +1117 │ proplists:get_value(k, L, 3). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L, 3). +Expression has type: term() +Context expected type: pid() | number() + │ + + term() is not compatible with pid() | number() + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1123:5 + │ +1123 │ proplists:get_value(k, L, my_default). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L, 'my_default'). +Expression has type: term() +Context expected type: 'v1' | 'v2' | 'my_default' + │ + + term() is not compatible with 'v1' | 'v2' | 'my_default' + because + term() is not compatible with 'v1' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1129:5 + │ +1129 │ proplists:get_value(k, L, my_default). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', L, 'my_default'). +Expression has type: term() +Context expected type: 'v' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1134:28 + │ +1134 │ proplists:get_value(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1139:5 + │ +1139 │ proplists:get_value(k, []). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', []). +Expression has type: term() +Context expected type: 'default' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1144:1 + │ +1144 │ proplists:get_value(k, [], my_default). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', [], 'my_default'). +Expression has type: term() +Context expected type: 'my_default' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1149:28 + │ +1149 │ proplists:get_value(k, b, my_default). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1154:5 + │ +1154 │ proplists:get_bool(b, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_bool('b', L). +Expression has type: boolean() +Context expected type: 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1160:5 + │ +1160 │ proplists:get_all_values(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', L). +Expression has type: [term()] +Context expected type: [pid() | 'default'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: pid() | 'default' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid() | 'default'] + because + term() is not compatible with pid() | 'default' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1166:5 + │ +1166 │ proplists:get_all_values(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', L). +Expression has type: [term()] +Context expected type: [pid() | 'default' | 'v'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: pid() | 'default' | 'v' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid() | 'default' | 'v'] + because + term() is not compatible with pid() | 'default' | 'v' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1171:5 + │ +1171 │ proplists:get_all_values(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', L). +Expression has type: [term()] +Context expected type: [pid()] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: pid() + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid()] + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1176:5 + │ +1176 │ proplists:get_all_values(k, []). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', []). +Expression has type: [term()] +Context expected type: [] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: none() + ] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1181:5 + │ +1181 │ proplists:get_all_values(k, b). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', 'b'). +Expression has type: [term()] +Context expected type: [] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: none() + ] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1181:33 + │ +1181 │ proplists:get_all_values(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1186:27 + │ +1186 │ proplists:get_bool(b, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1191:5 + │ +1191 │ proplists:get_keys(L). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_keys(L). +Expression has type: [term()] +Context expected type: ['c'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: 'c' + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['c'] + because + term() is not compatible with 'c' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1197:5 + │ +1197 │ proplists:get_keys(L). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_keys(L). +Expression has type: [term()] +Context expected type: ['a' | 'b' | 'c'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: 'a' | 'b' | 'c' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['a' | 'b' | 'c'] + because + term() is not compatible with 'a' | 'b' | 'c' + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1202:24 + │ +1202 │ proplists:get_keys(a). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1207:5 + │ +1207 │ ╭ ╭ proplists:get_keys( +1208 │ │ │ [{a, b, c}] +1209 │ │ │ ). + │ ╰─│─────^ proplists:get_keys([{'a', 'b', 'c'}]). +Expression has type: [term()] +Context expected type: ['a'] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: 'a' + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['a'] + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1215:5 + │ +1215 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). +Expression has type: term() +Context expected type: 'a' | pid() + │ + + term() is not compatible with 'a' | pid() + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1220:5 + │ +1220 │ proplists:get_value(k, b). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', 'b'). +Expression has type: term() +Context expected type: 'a' | pid() + │ + + term() is not compatible with 'a' | pid() + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1220:28 + │ +1220 │ proplists:get_value(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1225:1 + │ +1225 │ proplists:lookup(self(), [a, {b, true}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:lookup(erlang:self(), ['a', {'b', 'true'}]). +Expression has type: 'none' | tuple() +Context expected type: {'b', 'true'} + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: tuple() + However the following candidate: 'none' + Differs from the expected type: {'b', 'true'} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1229:25 + │ +1229 │ proplists:lookup(a, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1239:5 + │ +1239 │ proplists:lookup(k, []). + │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:lookup('k', []). +Expression has type: 'none' | tuple() +Context expected type: 'none' + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'none' + However the following candidate: tuple() + Differs from the expected type: 'none' + +------------------------------ Detailed message ------------------------------ + + 'none' | tuple() is not compatible with 'none' + because + tuple() is not compatible with 'none' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1252:29 + │ +1252 │ proplists:lookup_all(a, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1265:5 + │ +1265 │ ╭ ╭ proplists:lookup_all( +1266 │ │ │ self(), +1267 │ │ │ [] +1268 │ │ │ ). + │ ╰─│─────^ proplists:lookup_all(erlang:self(), []). +Expression has type: [tuple()] +Context expected type: [] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is: tuple() + Context expects type: none() + ] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1291:34 + │ +1291 │ proplists:is_defined(self(), b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1295:25 + │ +1295 │ proplists:delete(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [A] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1295:25 + │ +1295 │ proplists:delete(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1311:5 + │ +1311 │ proplists:split(L, Ks). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:split(L, Ks). +Expression has type: {[[term()]], [term()]} +Context expected type: {[plist('a', 'b')], plist('a', 'b')} + │ + +Because in the expression's type: + { + [ + [ + Here the type is: term() + Context expects type: 'a' | {'a', 'b'} + No candidate matches in the expected union. + ] + ] + , [term()]} + +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[[term()]], [term()]} is not compatible with {[plist('a', 'b')], plist('a', 'b')} + because + [[term()]] is not compatible with [plist('a', 'b')] + because + [term()] is not compatible with plist('a', 'b') + because + [term()] is not compatible with ['a' | {'a', 'b'}] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1315:21 + │ +1315 │ proplists:split(b, []). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1319:25 + │ +1319 │ proplists:split([], b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1324:22 + │ +1324 │ proplists:to_map(b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [atom() | {term(), term()} | term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1358:24 + │ +1358 │ proplists:from_map(b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: #{K => V} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1358:24 + │ +1358 │ proplists:from_map(b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: #{dynamic() => dynamic()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1363:5 + │ +1363 │ proplists:get_value(a, [a]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('a', ['a']). +Expression has type: term() +Context expected type: 'true' | 'undefined' + │ + + term() is not compatible with 'true' | 'undefined' + because + term() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1368:5 + │ +1368 │ proplists:get_value(X, [a]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value(X, ['a']). +Expression has type: term() +Context expected type: 'true' | 'undefined' + │ + + term() is not compatible with 'true' | 'undefined' + because + term() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1373:5 + │ +1373 │ proplists:get_value(a, [a], b). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('a', ['a'], 'b'). +Expression has type: term() +Context expected type: 'true' | 'b' + │ + + term() is not compatible with 'true' | 'b' + because + term() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1416:5 + │ +1416 │ file:consult(some_file). + │ ^^^^^^^^^^^^^^^^^^^^^^^ file:consult('some_file'). +Expression has type: {'ok', [dynamic()]} | {'error', {number(), atom(), term()} | 'terminated' | 'badarg' | file:posix() | 'system_limit'} +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1428:5 + │ +1428 │ lists:keysort(2, [{a, c}, {b, d}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lists:keysort(2, [{'a', 'c'}, {'b', 'd'}]). +Expression has type: [{'a', 'c'} | {'b', 'd'}] +Context expected type: none() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1432:22 + │ +1432 │ lists:keysort(1, [3]). + │ ^^^ + │ │ + │ [3]. +Expression has type: [number()] +Context expected type: [tuple()] + │ + +Because in the expression's type: + [ + Here the type is: number() + Context expects type: tuple() + ] + +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [tuple()] + because + number() is not compatible with tuple() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1448:5 + │ +1448 │ ╭ ╭ lists:filtermap( +1449 │ │ │ fun(X) when X div 2 =:= 0 -> +1450 │ │ │ {true, integer_to_list(X)}; +1451 │ │ │ (X) -> + · │ │ +1454 │ │ │ [1, 2, 3, 4] +1455 │ │ │ ). + │ ╰─│─────^ lists:filtermap(fun, [1, 2, 3, 4]). +Expression has type: [string() | number()] +Context expected type: [number()] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: number() + However the following candidate: string() + Differs from the expected type: number() + ] + +------------------------------ Detailed message ------------------------------ + + [string() | number()] is not compatible with [number()] + because + string() | number() is not compatible with number() + because + string() is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1482:5 + │ +1482 │ erlang:min(X, Y). + │ ^^^^^^^^^^^^^^^^ erlang:min(X, Y). +Expression has type: number() +Context expected type: none() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1497:5 + │ +1497 │ erlang:max(X, Y). + │ ^^^^^^^^^^^^^^^^ erlang:max(X, Y). +Expression has type: atom() | number() +Context expected type: none() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1523:9 + │ +1523 │ abs(Atom). + │ ^^^^ Atom. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1536:31 + │ +1536 │ seq3_4_wip_neg() -> lists:seq(a, 2, 1). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1539:30 + │ +1539 │ seq3_5_neg() -> lists:seq(1, a, 1). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1542:33 + │ +1542 │ seq3_6_neg() -> lists:seq(1, 2, a). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1570:31 + │ +1570 │ seq2_4_wip_neg() -> lists:seq(a, 2). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1573:30 + │ +1573 │ seq2_5_neg() -> lists:seq(1, a). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1622:5 + │ +1622 │ ╭ timer:tc( +1623 │ │ fun() -> +1624 │ │ err +1625 │ │ end +1626 │ │ ). + │ ╰─────^ timer:tc(fun). +Expression has type: {number(), 'err'} +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1635:5 + │ +1635 │ ets:lookup(tab, Any). + │ ^^^^^^^^^^^^^^^^^^^^ ets:lookup('tab', Any). +Expression has type: [dynamic()] +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1639:5 + │ +1639 │ ets:lookup("not atom", Any). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ets:lookup(string_lit, Any). +Expression has type: [dynamic()] +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1639:16 + │ +1639 │ ets:lookup("not atom", Any). + │ ^^^^^^^^^^ string_lit. +Expression has type: string() +Context expected type: ets:tab() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1663:18 + │ +1663 │ ets:tab2list("not atom"). + │ ^^^^^^^^^^ string_lit. +Expression has type: string() +Context expected type: ets:tab() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1702:23 + │ +1702 │ lists:flatten([], 1). + │ ^ 1. +Expression has type: number() +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1711:19 + │ +1711 │ lists:flatten(3). + │ ^ 3. +Expression has type: number() +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1724:8 + │ +1724 │ -> lists:flatten(X). + │ ^^^^^^^^^^^^^^^^ + │ │ + │ lists:flatten(X). +Expression has type: [{A, B} | {B, A}] +Context expected type: [{A, B}] + │ + +Because in the expression's type: + [ + { + Here the type is: B + Context expects type: A + , A} + ] + +------------------------------ Detailed message ------------------------------ + + [{A, B} | {B, A}] is not compatible with [{A, B}] + because + {A, B} | {B, A} is not compatible with {A, B} + because + at tuple index 1: + {B, A} is not compatible with {A, B} + because + B is not compatible with A + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1757:5 + │ +1757 │ ╭ ╭ maps:without( +1758 │ │ │ [a, c, DOrE], +1759 │ │ │ #{ +1760 │ │ │ a => ka, + · │ │ +1764 │ │ │ } +1765 │ │ │ ). + │ ╰─│─────^ maps:without(['a', 'c', DOrE], #{..}). +Expression has type: #{a => 'ka', b => atom(), c => pid(), d => 'kd'} +Context expected type: #{b => atom()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{a => ...} + Context expects type: #{...} + The expected map has no corresponding key for: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared in the former but not in the latter and the latter map has no default association + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1769:18 + │ +1769 │ maps:without(non_list, #{}). + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1773:22 + │ +1773 │ maps:without([], non_map). + │ ^^^^^^^ 'non_map'. +Expression has type: 'non_map' +Context expected type: #{term() => term()} + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:1808:1 + │ +1808 │ ╭ maps_without_12_neg(None) -> +1809 │ │ maps:without( +1810 │ │ [a, b], +1811 │ │ None +1812 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1818:5 + │ +1818 │ ╭ ╭ maps:without( +1819 │ │ │ Keys, +1820 │ │ │ #{a => self(), b => self()} +1821 │ │ │ ). + │ ╰─│─────^ maps:without(Keys, #{..}). +Expression has type: #{a => pid(), b => pid()} +Context expected type: #{b := pid()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{b => ..., ...} + Context expects type: #{b := ..., ...} + The type of the expression is missing the following required keys: b. + +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1826:5 + │ +1826 │ ╭ ╭ maps:without( +1827 │ │ │ [a | improper_tail], +1828 │ │ │ #{a => self(), b => self()} +1829 │ │ │ ). + │ ╰─│─────^ maps:without(['a' | 'improper_tail'], #{..}). +Expression has type: #{a => pid(), b => pid()} +Context expected type: #{b := pid()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{b => ..., ...} + Context expects type: #{b := ..., ...} + The type of the expression is missing the following required keys: b. + +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1827:12 + │ +1827 │ [a | improper_tail], + │ ^^^^^^^^^^^^^^^^ 'improper_tail'. +Expression has type: 'improper_tail' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1837:5 + │ +1837 │ ╭ ╭ maps:without( +1838 │ │ │ Keys, +1839 │ │ │ #{a => ka, b => self()} +1840 │ │ │ ). + │ ╰─│─────^ maps:without(Keys, #{..}). +Expression has type: #{a => 'ka', b => pid()} +Context expected type: #{b := pid()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{b => ..., ...} + Context expects type: #{b := ..., ...} + The type of the expression is missing the following required keys: b. + +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1854:5 + │ +1854 │ maps:without([a, b], M). + │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:without(['a', 'b'], M). +Expression has type: #{c := 'cv', d := 'dv'} | #{c := 'cv', e => 'ev'} +Context expected type: #{c := atom()} + │ + +Because in the expression's type: + Here the type is: #{d := ...} + Context expects type: #{...} + The expected map has no corresponding key for: d. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1916:23 + │ +1916 │ custom_overloaded(X). + │ ^ + │ │ + │ X. +Expression has type: term() +Context expected type: atom() | binary() + │ + + term() is not compatible with atom() | binary() + because + term() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1939:5 + │ +1939 │ {A, N}. + │ ^^^^^^ + │ │ + │ {A, N}. +Expression has type: {atom(), number() | pid()} +Context expected type: {atom(), number()} + │ + +Because in the expression's type: + { atom(), + Here the type is a union type with some valid candidates: number() + However the following candidate: pid() + Differs from the expected type: number() + } + +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {atom(), number() | pid()} is not compatible with {atom(), number()} + because + number() | pid() is not compatible with number() + because + pid() is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2041:5 + │ +2041 │ filename:join(["server", "erl"]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([string_lit, string_lit]). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2046:5 + │ +2046 │ filename:join(["server", <<>>]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([string_lit, <<..>>]). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2051:5 + │ +2051 │ filename:join([<<>>, ""]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([<<..>>, string_lit]). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2066:5 + │ +2066 │ filename:join([<<>>, <<>>]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([<<..>>, <<..>>]). +Expression has type: file:filename_all() +Context expected type: binary() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: binary() + However the following candidate: string() + Differs from the expected type: binary() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with binary() + because + string() | binary() is not compatible with binary() + because + string() is not compatible with binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2081:19 + │ +2081 │ filename:join([<<>>, self()]). + │ ^^^^^^^^^^^^^^ + │ │ + │ [<<..>>, erlang:self()]. +Expression has type: [binary() | pid()] +Context expected type: [file:name_all()] + │ + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: binary() + However the following candidate: pid() + Differs from the expected type: string() | atom() | file:deep_list() | binary() + ] + +------------------------------ Detailed message ------------------------------ + + [binary() | pid()] is not compatible with [file:name_all()] + because + binary() | pid() is not compatible with file:name_all() + because + binary() | pid() is not compatible with string() | atom() | file:deep_list() | binary() + because + pid() is not compatible with string() | atom() | file:deep_list() | binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2086:5 + │ +2086 │ filename:join("server", "erl"). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join(string_lit, string_lit). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2091:5 + │ +2091 │ filename:join("server", <<>>). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join(string_lit, <<..>>). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2096:5 + │ +2096 │ filename:join(<<>>, ""). + │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join(<<..>>, string_lit). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2111:5 + │ +2111 │ filename:join(atom, <<>>). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join('atom', <<..>>). +Expression has type: file:filename_all() +Context expected type: binary() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: binary() + However the following candidate: string() + Differs from the expected type: binary() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with binary() + because + string() | binary() is not compatible with binary() + because + string() is not compatible with binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2121:25 + │ +2121 │ filename:join(<<>>, self()). + │ ^^^^^^ + │ │ + │ erlang:self(). +Expression has type: pid() +Context expected type: file:name_all() + │ + +Because in the expression's type: + Here the type is: pid() + Context expects type: string() | atom() | file:deep_list() | binary() + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + pid() is not compatible with file:name_all() + because + pid() is not compatible with string() | atom() | file:deep_list() | binary() + because + pid() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2150:5 + │ +2150 │ ╭ ╭ queue:filter( +2151 │ │ │ fun my_filter1/1, +2152 │ │ │ Q +2153 │ │ │ ). + │ ╰─│─────^ queue:filter(my_filter1/1, Q). +Expression has type: queue:queue(atom() | number()) +Context expected type: queue:queue(number()) + │ ╰─────' + +Because in the expression's type: + { + [ + Here the type is a union type with some valid candidates: number() + However the following candidate: atom() + Differs from the expected type: number() + ] + , [atom() | number()]} + +------------------------------ Detailed message ------------------------------ + + queue:queue(atom() | number()) is not compatible with queue:queue(number()) + because + {[atom() | number()], [atom() | number()]} is not compatible with queue:queue(number()) + because + at tuple index 1: + {[atom() | number()], [atom() | number()]} is not compatible with {[number()], [number()]} + because + [atom() | number()] is not compatible with [number()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2191:5 + │ +2191 │ M3. + │ ^^ + │ │ + │ M3. +Expression has type: #{count := number(), module := 'foo'} | #{module := 'foo'} +Context expected type: state1() + │ + +Because in the expression's type: + The type is a union type with some valid candidates: #{count := number(), module := 'foo'} + However, the following candidate doesn't match: + Here the type is: #{...} + Context expects type: #{count := ..., ...} + The type of the expression is missing the following required keys: count. + +------------------------------ Detailed message ------------------------------ + + #{count := number(), module := 'foo'} | #{module := 'foo'} is not compatible with state1() + because + #{count := number(), module := 'foo'} | #{module := 'foo'} is not compatible with #{count := number(), module := atom()} + because + #{module := 'foo'} is not compatible with #{count := number(), module := atom()} + key `count` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2223:13 + │ +2223 │ Atom + Sum + │ ^^^^ Atom. +Expression has type: atom() +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2279:5 + │ +2279 │ maps:remove(A, M). + │ ^^^^^^^^^^^^^^^^^ + │ │ + │ maps:remove(A, M). +Expression has type: #{a => number()} +Context expected type: #{a := number()} + │ + +Because in the expression's type: + Here the type is: #{a => ..., ...} + Context expects type: #{a := ..., ...} + The type of the expression is missing the following required keys: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2320:5 + │ +2320 │ ╭ ╭ maps:filtermap( +2321 │ │ │ fun +2322 │ │ │ (a, V) -> true; +2323 │ │ │ (b, V) -> {true, atom_to_binary(V)}; + · │ │ +2326 │ │ │ M +2327 │ │ │ ). + │ ╰─│─────^ maps:filtermap(fun, M). +Expression has type: #{a => atom() | binary(), b => atom() | binary(), c => atom() | binary()} +Context expected type: #{a := atom(), b := binary()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{a => ..., b => ..., ...} + Context expects type: #{a := ..., b := ..., ...} + The type of the expression is missing the following required keys: a, b. + +------------------------------ Detailed message ------------------------------ + +keys `a`, `b` are declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2342:5 + │ +2342 │ ╭ ╭ maps:filtermap( +2343 │ │ │ fun (_, V) -> +2344 │ │ │ {true, atom_to_binary(V)} +2345 │ │ │ end, +2346 │ │ │ M +2347 │ │ │ ). + │ ╰─│─────^ maps:filtermap(fun, M). +Expression has type: #{atom() => binary()} +Context expected type: #{atom() => atom()} + │ ╰─────' + +Because in the expression's type: + #{ atom() => + Here the type is: binary() + Context expects type: atom() + , ... } + +------------------------------ Detailed message ------------------------------ + + #{atom() => binary()} is not compatible with #{atom() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2354:23 + │ +2354 │ fun (_, _) -> err end, + │ ^^^ + │ │ + │ 'err'. +Expression has type: 'err' +Context expected type: boolean() | {'true', term()} + │ + +Because in the expression's type: + Here the type is: 'err' + Context expects type: 'false' | 'true' | {'true', term()} + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + 'err' is not compatible with boolean() | {'true', term()} + because + 'err' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2362:5 + │ +2362 │ ╭ ╭ maps:filtermap( +2363 │ │ │ fun (_, V) -> {true, atom_to_binary(V)} end, +2364 │ │ │ M +2365 │ │ │ ). + │ ╰─│─────^ maps:filtermap(fun, M). +Expression has type: #{atom() => binary()} +Context expected type: #{atom() => atom()} + │ ╰─────' + +Because in the expression's type: + #{ atom() => + Here the type is: binary() + Context expects type: atom() + , ... } + +------------------------------ Detailed message ------------------------------ + + #{atom() => binary()} is not compatible with #{atom() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2363:45 + │ +2363 │ fun (_, V) -> {true, atom_to_binary(V)} end, + │ ^ V. +Expression has type: binary() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2377:5 + │ +2377 │ re:replace(Subj, "+", "-", [{return, binary}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re:replace(Subj, string_lit, string_lit, [{'return', 'binary'}]). +Expression has type: binary() +Context expected type: string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2381:5 + │ +2381 │ re:replace(Subj, "+", "-", [{return, list}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re:replace(Subj, string_lit, string_lit, [{'return', 'list'}]). +Expression has type: string() +Context expected type: binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2385:22 + │ +2385 │ Res = re:replace(Subj, "+", "-", [{return, list}]), + │ ^^^^ + │ │ + │ Subj. +Expression has type: atom() +Context expected type: iodata() | unicode:charlist() + │ + +Because in the expression's type: + Here the type is: atom() + Context expects type: iolist() | binary() + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + atom() is not compatible with iodata() | unicode:charlist() + because + atom() is not compatible with iolist() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2386:5 + │ +2386 │ Res. + │ ^^^ Res. +Expression has type: string() +Context expected type: binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2390:38 + │ +2390 │ Res = re:replace(Subj, "+", "-", [{return, something}]), + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ [{'return', 'something'}]. +Expression has type: [{'return', 'something'}] +Context expected type: ['notempty_atstart' | 'noteol' | 'notbol' | 'global' | {'match_limit_recursion', number()} | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored'] + │ + +Because in the expression's type: + [ + { 'return', + Here the type is: 'something' + Context expects type: 'iodata' | 'list' | 'binary' + No candidate matches in the expected union. + } + ] + +------------------------------ Detailed message ------------------------------ + + [{'return', 'something'}] is not compatible with ['notempty_atstart' | 'noteol' | 'notbol' | 'global' | {'match_limit_recursion', number()} | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored'] + because + {'return', 'something'} is not compatible with 'notempty_atstart' | 'noteol' | 'notbol' | 'global' | {'match_limit_recursion', number()} | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored' + because + at tuple index 2: + {'return', 'something'} is not compatible with {'return', 'iodata' | 'list' | 'binary'} + because + 'something' is not compatible with 'iodata' | 'list' | 'binary' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2506:5 + │ +2506 │ lists:partition(fun is_number/1, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ lists:partition(fun, L). +Expression has type: {[number()], [atom()]} +Context expected type: {[atom()], [number()]} + │ + +Because in the expression's type: + { + [ + Here the type is: number() + Context expects type: atom() + ] + , [atom()]} + +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[number()], [atom()]} is not compatible with {[atom()], [number()]} + because + [number()] is not compatible with [atom()] + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2518:5 + │ +2518 │ lists:partition(fun({_Term, V}) -> is_number(V) end, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ lists:partition(fun, L). +Expression has type: {[{term(), number()}], [{term(), atom()}]} +Context expected type: {[{term(), atom()}], [{term(), number()}]} + │ + +Because in the expression's type: + { + [ + { term(), + Here the type is: number() + Context expects type: atom() + } + ] + , [{term(), atom()}]} + +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[{term(), number()}], [{term(), atom()}]} is not compatible with {[{term(), atom()}], [{term(), number()}]} + because + [{term(), number()}] is not compatible with [{term(), atom()}] + because + at tuple index 2: + {term(), number()} is not compatible with {term(), atom()} + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2536:5 + │ +2536 │ lists:partition(fun({ok, _}) -> true; (_) -> false end, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ lists:partition(fun, L). +Expression has type: {[{'ok', atom()}], [{'ok', atom()} | {'error', term()}]} +Context expected type: {[{'ok', atom()}], [{'error', term()}]} + │ + +Because in the expression's type: + { [{'ok', atom()}], + [ + { + Here the type is: 'ok' + Context expects type: 'error' + , atom()} + ] + } + +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {[{'ok', atom()}], [{'ok', atom()} | {'error', term()}]} is not compatible with {[{'ok', atom()}], [{'error', term()}]} + because + [{'ok', atom()} | {'error', term()}] is not compatible with [{'error', term()}] + because + {'ok', atom()} | {'error', term()} is not compatible with {'error', term()} + because + at tuple index 1: + {'ok', atom()} is not compatible with {'error', term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2576:33 + │ +2576 │ maps_intersect_2_neg(M1, M2) -> maps:intersect(M1, M2). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:intersect(M1, M2). +Expression has type: #{a => number()} +Context expected type: #{a := number()} + │ + +Because in the expression's type: + Here the type is: #{a => ..., ...} + Context expects type: #{a := ..., ...} + The type of the expression is missing the following required keys: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2586:33 + │ +2586 │ maps_intersect_4_neg(M1, M2) -> maps:intersect(M1, M2). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:intersect(M1, M2). +Expression has type: #{a => number()} +Context expected type: #{a => 'true'} + │ + +Because in the expression's type: + #{ a => + Here the type is: number() + Context expects type: 'true' + , ... } + +------------------------------ Detailed message ------------------------------ + + #{a => number()} is not compatible with #{a => 'true'} + because + at key `a`: + #{a => number()} is not compatible with #{a => 'true'} + because + number() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2596:33 + │ +2596 │ maps_intersect_6_neg(M1, M2) -> maps:intersect(M1, M2). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:intersect(M1, M2). +Expression has type: #{a => number()} +Context expected type: #{a := number()} + │ + +Because in the expression's type: + Here the type is: #{a => ..., ...} + Context expects type: #{a := ..., ...} + The type of the expression is missing the following required keys: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2709:40 + │ +2709 │ (foo, A) -> binary_to_atom(A); + │ ^ A. +Expression has type: atom() +Context expected type: binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2710:40 + │ +2710 │ (bar, B) -> atom_to_binary(B); + │ ^ B. +Expression has type: binary() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2711:50 + │ +2711 │ ({foo, bar}, I) -> binary_to_integer(I); + │ ^ I. +Expression has type: number() +Context expected type: binary() + +202 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls.pretty index bc6265b8c1..a8dc692a9b 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls.pretty @@ -66,33 +66,61 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ check/src/dynamic_calls.erl:78:14 │ 78 │ (FUnion)(false). - │ ^^^^^ 'false'. + │ ^^^^^ + │ │ + │ 'false'. Expression has type: 'false' Context expected type: 'a1' | 'a2' + │ + + 'false' is not compatible with 'a1' | 'a2' + because + 'false' is not compatible with 'a1' error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_calls.erl:78:14 │ 78 │ (FUnion)(false). - │ ^^^^^ 'false'. + │ ^^^^^ + │ │ + │ 'false'. Expression has type: 'false' Context expected type: 'a2' | 'a3' + │ + + 'false' is not compatible with 'a2' | 'a3' + because + 'false' is not compatible with 'a2' error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_calls.erl:86:20 │ 86 │ Res = (FUnion)(false), - │ ^^^^^ 'false'. + │ ^^^^^ + │ │ + │ 'false'. Expression has type: 'false' Context expected type: 'a1' | 'a2' + │ + + 'false' is not compatible with 'a1' | 'a2' + because + 'false' is not compatible with 'a1' error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_calls.erl:86:20 │ 86 │ Res = (FUnion)(false), - │ ^^^^^ 'false'. + │ ^^^^^ + │ │ + │ 'false'. Expression has type: 'false' Context expected type: 'a2' | 'a3' + │ + + 'false' is not compatible with 'a2' | 'a3' + because + 'false' is not compatible with 'a2' error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_calls.erl:87:5 @@ -118,6 +146,12 @@ Because in the expression's type: However the following candidate: 'r2' Differs from the expected type: 'r1' +------------------------------ Detailed message ------------------------------ + + 'r1' | 'r2' is not compatible with 'r1' + because + 'r2' is not compatible with 'r1' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_calls.erl:94:5 │ @@ -142,6 +176,12 @@ Because in the expression's type: However the following candidate: 'r2' Differs from the expected type: 'r1' +------------------------------ Detailed message ------------------------------ + + 'r1' | 'r2' | 'r3' is not compatible with 'r1' + because + 'r2' is not compatible with 'r1' + error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) ┌─ check/src/dynamic_calls.erl:108:5 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_catch.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_catch.pretty index 78fd9f16f2..a8135429d1 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_catch.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_catch.pretty @@ -14,4 +14,10 @@ Because in the expression's type: However the following candidate: atom() Differs from the expected type: binary() +------------------------------ Detailed message ------------------------------ + + atom() | dynamic() is not compatible with binary() + because + atom() is not compatible with binary() + 1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun.pretty index 7f7add29a8..1f55b0f88a 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun.pretty @@ -72,6 +72,16 @@ Because in the expression's type: Differs from the expected type: 'a' ) +------------------------------ Detailed message ------------------------------ + + f5('a' | 'b') is not compatible with f4('a') + because + fun((term()) -> 'a' | 'b') is not compatible with f4('a') + because + fun((term()) -> 'a' | 'b') is not compatible with fun((...) -> 'a') + because + 'a' | 'b' is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_fun.erl:155:20 │ @@ -98,6 +108,16 @@ Because in the expression's type: Differs from the expected type: 'a' ) +------------------------------ Detailed message ------------------------------ + + fun((term()) -> 'a' | 'b') is not compatible with f4('a') + because + fun((term()) -> 'a' | 'b') is not compatible with fun((...) -> 'a') + because + 'a' | 'b' is not compatible with 'a' + because + 'b' is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_fun.erl:176:21 │ @@ -116,6 +136,16 @@ Because in the expression's type: Differs from the expected type: 'a' ) +------------------------------ Detailed message ------------------------------ + + f4('a' | 'b') is not compatible with fun((term()) -> 'a') + because + fun((...) -> 'a' | 'b') is not compatible with fun((term()) -> 'a') + because + 'a' | 'b' is not compatible with 'a' + because + 'b' is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_fun.erl:208:34 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics.pretty index 78c9a41f3f..cd54f2d176 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics.pretty @@ -38,6 +38,12 @@ Because in the expression's type: However the following candidate: number() Differs from the expected type: none() +------------------------------ Detailed message ------------------------------ + + number() | dynamic() is not compatible with none() + because + number() is not compatible with none() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_generics.erl:72:3 │ @@ -62,6 +68,12 @@ Because in the expression's type: However the following candidate: string() Differs from the expected type: 'ok' +------------------------------ Detailed message ------------------------------ + + dynamic() | string() is not compatible with 'ok' + because + string() is not compatible with 'ok' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_generics.erl:87:3 │ @@ -100,6 +112,14 @@ Because in the expression's type: Differs from the expected type: number() ] +------------------------------ Detailed message ------------------------------ + + [number() | 'three'] is not compatible with [number()] + because + number() | 'three' is not compatible with number() + because + 'three' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_generics.erl:115:9 │ @@ -116,6 +136,12 @@ Because in the expression's type: However the following candidate: 'three' Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | 'three' is not compatible with number() + because + 'three' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_generics.erl:115:22 │ @@ -132,6 +158,12 @@ Because in the expression's type: However the following candidate: 'three' Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | 'three' is not compatible with number() + because + 'three' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_generics.erl:127:13 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs.pretty index 6e82aa3702..3ca5a136e6 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs.pretty @@ -14,6 +14,12 @@ Because in the expression's type: However the following candidate: number() Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + dynamic() | number() is not compatible with atom() + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_local_funs.erl:36:15 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine.pretty index ce03971816..9d7187f610 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine.pretty @@ -100,6 +100,12 @@ Because in the expression's type: However the following candidate: 'error' Differs from the expected type: 'ok' +------------------------------ Detailed message ------------------------------ + + dynamic() | 'error' is not compatible with 'ok' + because + 'error' is not compatible with 'ok' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_refine.erl:236:3 │ @@ -132,6 +138,12 @@ Because in the expression's type: However the following candidate: 'err' Differs from the expected type: 'ok' +------------------------------ Detailed message ------------------------------ + + dyn_alias() | 'err' is not compatible with 'ok' + because + 'err' is not compatible with 'ok' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/dynamic_refine.erl:260:27 │ @@ -150,4 +162,15 @@ Because in the expression's type: Differs from the expected type: 'ok' } +------------------------------ Detailed message ------------------------------ + + union() is not compatible with {'ok'} + because + at tuple index 1: + {dyn_alias() | 'err'} is not compatible with {'ok'} + because + dyn_alias() | 'err' is not compatible with 'ok' + because + 'err' is not compatible with 'ok' + 16 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause.pretty index e02928cc14..b9fdc2fbce 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause.pretty @@ -38,6 +38,12 @@ Because in the expression's type: However the following candidate: 'error' Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + 'error' | 'exit' | 'throw' | number() is not compatible with number() + because + 'error' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/elab_clause.erl:86:5 │ @@ -54,6 +60,12 @@ Because in the expression's type: However the following candidate: [dynamic()] Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | [dynamic()] is not compatible with number() + because + [dynamic()] is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/elab_clause.erl:93:17 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/error_messages.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/error_messages.pretty index fab550d5e6..ab48c38337 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/error_messages.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/error_messages.pretty @@ -15,6 +15,17 @@ Because in the expression's type: Context expects type: number() , ... } +------------------------------ Detailed message ------------------------------ + + #{bar := atom(), baz := atom()} is not compatible with foo_map() | #{foo => atom()} + because + #{bar := atom(), baz := atom()} is not compatible with foo_map() + because + #{bar := atom(), baz := atom()} is not compatible with #{bar => atom(), baz => number(), other => atom(), other2 => atom(), other3 => atom(), other4 => atom(), other5 => atom()} + because + at key `baz`: + #{bar := atom(), baz := atom()} is not compatible with #{bar => atom(), baz => number(), other => atom(), other2 => atom(), other3 => atom(), other4 => atom(), other5 => atom()} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/error_messages.erl:19:24 │ @@ -33,6 +44,12 @@ Because in the expression's type: The expected map has no corresponding key for: baz. ] +------------------------------ Detailed message ------------------------------ + + [#{bar => 'a' | 'b'} | #{baz => 'a' | 'b'}] is not compatible with [#{bar => 'a'}] + because + #{bar => 'a' | 'b'} | #{baz => 'a' | 'b'} is not compatible with #{bar => 'a'} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/error_messages.erl:22:22 │ @@ -51,6 +68,15 @@ Because in the expression's type: Differs from the expected type: binary() , ... } +------------------------------ Detailed message ------------------------------ + + #{'undefined' | binary() => atom()} is not compatible with #{binary() => atom()} + the default associations are not compatible + because + 'undefined' | binary() is not compatible with binary() + because + 'undefined' is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/error_messages.erl:27:32 │ @@ -63,9 +89,17 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ check/src/error_messages.erl:30:32 │ 30 │ no_record_conversion_2(Foo) -> Foo. - │ ^^^ Foo. + │ ^^^ + │ │ + │ Foo. Expression has type: #foo{} Context expected type: {binary(), atom(), atom()} + │ + + at tuple index 1: + {'foo', atom(), atom()} is not compatible with {binary(), atom(), atom()} + because + 'foo' is not compatible with binary() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/error_messages.erl:33:27 @@ -84,6 +118,13 @@ Because in the expression's type: Context expects type: binary() , atom()} +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {'foo', atom(), atom()} is not compatible with {'foo', binary(), atom()} + because + atom() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/error_messages.erl:37:31 │ @@ -102,6 +143,18 @@ Because in the expression's type: The expected map has no corresponding key for: large_map_key_a. , ... } +------------------------------ Detailed message ------------------------------ + + #{foo => #{large_map_key_a => 'large_map_val_a', large_map_key_b => 'large_map_val_b'}} is not compatible with #{foo => #{large_map_key_c => 'large_map_val_c'} | #{large_map_key_d => 'large_map_val_d'}} + because + at key `foo`: + #{foo => #{large_map_key_a => 'large_map_val_a', large_map_key_b => 'large_map_val_b'}} is not compatible with #{foo => #{large_map_key_c => 'large_map_val_c'} | #{large_map_key_d => 'large_map_val_d'}} + because + #{large_map_key_a => 'large_map_val_a', large_map_key_b => 'large_map_val_b'} is not compatible with #{large_map_key_c => 'large_map_val_c'} | #{large_map_key_d => 'large_map_val_d'} + because + #{large_map_key_a => 'large_map_val_a', large_map_key_b => 'large_map_val_b'} is not compatible with #{large_map_key_c => 'large_map_val_c'} + key `large_map_key_a` is declared in the former but not in the latter and the latter map has no default association + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/error_messages.erl:41:31 │ @@ -120,4 +173,16 @@ Because in the expression's type: The expected map has no corresponding key for: large_map_key_a. , ... } +------------------------------ Detailed message ------------------------------ + + #{foo => #{large_map_key_a => 'large_map_val_a', large_map_key_b => 'large_map_val_b'}} is not compatible with #{foo => #{large_map_key_c => 'large_map_val_c', large_map_key_d => 'large_map_val_d'} | 'any'} + because + at key `foo`: + #{foo => #{large_map_key_a => 'large_map_val_a', large_map_key_b => 'large_map_val_b'}} is not compatible with #{foo => #{large_map_key_c => 'large_map_val_c', large_map_key_d => 'large_map_val_d'} | 'any'} + because + #{large_map_key_a => 'large_map_val_a', large_map_key_b => 'large_map_val_b'} is not compatible with #{large_map_key_c => 'large_map_val_c', large_map_key_d => 'large_map_val_d'} | 'any' + because + #{large_map_key_a => 'large_map_val_a', large_map_key_b => 'large_map_val_b'} is not compatible with #{large_map_key_c => 'large_map_val_c', large_map_key_d => 'large_map_val_d'} + key `large_map_key_a` is declared in the former but not in the latter and the latter map has no default association + 8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/format.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/format.pretty index 1a6ae465e8..f6d7701c2e 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/format.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/format.pretty @@ -13,4 +13,10 @@ Because in the expression's type: Here the type is: [number() | io_lib:chars()] Context expects type: string() +------------------------------ Detailed message ------------------------------ + + io_lib:chars() is not compatible with string() + because + [number() | io_lib:chars()] is not compatible with string() + 1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/funs.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/funs.pretty index 1e2c339ecc..589448836f 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/funs.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/funs.pretty @@ -29,6 +29,12 @@ Because in the expression's type: Here the type is: number() Context expects type: [term()] +------------------------------ Detailed message ------------------------------ + + n() is not compatible with [term()] + because + number() is not compatible with [term()] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs.erl:63:9 │ @@ -44,6 +50,12 @@ Because in the expression's type: Here the type is: [dynamic()] Context expects type: number() +------------------------------ Detailed message ------------------------------ + + [dynamic()] is not compatible with n() + because + [dynamic()] is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs.erl:70:13 │ @@ -59,6 +71,12 @@ Because in the expression's type: Here the type is: binary() Context expects type: number() +------------------------------ Detailed message ------------------------------ + + binary() is not compatible with n() + because + binary() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs.erl:70:35 │ @@ -74,6 +92,12 @@ Because in the expression's type: Here the type is: number() Context expects type: atom() +------------------------------ Detailed message ------------------------------ + + n() is not compatible with atom() + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs.erl:77:5 │ @@ -92,6 +116,14 @@ Because in the expression's type: Context expects type: 'a' ] +------------------------------ Detailed message ------------------------------ + + [n()] is not compatible with ['a'] + because + n() is not compatible with 'a' + because + number() is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs.erl:90:18 │ @@ -107,6 +139,12 @@ Because in the expression's type: Here the type is: number() Context expects type: [term()] +------------------------------ Detailed message ------------------------------ + + n() is not compatible with [term()] + because + number() is not compatible with [term()] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs.erl:90:18 │ @@ -122,6 +160,12 @@ Because in the expression's type: Here the type is: [dynamic()] Context expects type: number() +------------------------------ Detailed message ------------------------------ + + [dynamic()] is not compatible with n() + because + [dynamic()] is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs.erl:90:23 │ @@ -137,6 +181,12 @@ Because in the expression's type: Here the type is: number() Context expects type: [term()] +------------------------------ Detailed message ------------------------------ + + n() is not compatible with [term()] + because + number() is not compatible with [term()] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs.erl:96:31 │ @@ -152,6 +202,12 @@ Because in the expression's type: Here the type is: number() Context expects type: atom() +------------------------------ Detailed message ------------------------------ + + n() is not compatible with atom() + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs.erl:97:9 │ @@ -167,6 +223,12 @@ Because in the expression's type: Here the type is: number() Context expects type: [term()] +------------------------------ Detailed message ------------------------------ + + n() is not compatible with [term()] + because + number() is not compatible with [term()] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs.erl:97:9 │ @@ -182,6 +244,12 @@ Because in the expression's type: Here the type is: [dynamic()] Context expects type: number() +------------------------------ Detailed message ------------------------------ + + [dynamic()] is not compatible with n() + because + [dynamic()] is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs.erl:97:14 │ @@ -197,6 +265,12 @@ Because in the expression's type: Here the type is: number() Context expects type: [term()] +------------------------------ Detailed message ------------------------------ + + n() is not compatible with [term()] + because + number() is not compatible with [term()] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs.erl:104:7 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/funs2.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/funs2.pretty index f3a82abfd6..7b20cba52c 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/funs2.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/funs2.pretty @@ -19,6 +19,14 @@ Because in the expression's type: ] ] +------------------------------ Detailed message ------------------------------ + + [[[[]]]] is not compatible with [[[]]] + because + [[[]]] is not compatible with [[]] + because + [[]] is not compatible with [] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs2.erl:54:5 │ @@ -58,6 +66,12 @@ Because in the expression's type: Context expects type: atom() ) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> atom()) + because + string() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs2.erl:101:9 │ @@ -76,6 +90,14 @@ Because in the expression's type: Differs from the expected type: atom() ) -> string()) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic() | fun((string()) -> atom())) -> dynamic() | fun((string()) -> atom())) + because + dynamic() | fun((string()) -> atom()) is not compatible with atom() + because + fun((string()) -> atom()) is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs2.erl:101:9 │ @@ -94,6 +116,14 @@ Because in the expression's type: Differs from the expected type: atom() ) -> string()) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic() | string() | fun((string()) -> atom())) -> dynamic() | string() | fun((string()) -> atom())) + because + dynamic() | string() | fun((string()) -> atom()) is not compatible with atom() + because + string() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/funs2.erl:152:27 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application.pretty index ae03bc49c8..c10af08c9d 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application.pretty @@ -31,6 +31,12 @@ Because in the expression's type: Context expects type: atom() ] +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [atom()] + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:38:29 │ @@ -48,6 +54,14 @@ Because in the expression's type: Context expects type: atom() ] +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [dynamic(atom())] + because + number() is not compatible with dynamic(atom()) + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:43:5 │ @@ -73,6 +87,12 @@ Because in the expression's type: Context expects type: B ) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> pid()) is not compatible with fun((number()) -> B) + because + pid() is not compatible with B + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:43:18 │ @@ -91,6 +111,14 @@ Because in the expression's type: Differs from the expected type: atom() ) -> pid()) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> pid()) is not compatible with fun((dynamic() | number()) -> pid()) + because + dynamic() | number() is not compatible with atom() + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:47:33 │ @@ -108,6 +136,12 @@ Because in the expression's type: Context expects type: atom() ] +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [atom()] + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:47:33 │ @@ -125,6 +159,14 @@ Because in the expression's type: Context expects type: atom() ] +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [dynamic(atom())] + because + number() is not compatible with dynamic(atom()) + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:48:5 │ @@ -150,6 +192,12 @@ Because in the expression's type: Context expects type: B ) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> pid()) is not compatible with fun((number()) -> B) + because + pid() is not compatible with B + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:52:22 │ @@ -168,6 +216,14 @@ Because in the expression's type: Differs from the expected type: atom() ) -> pid()) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> pid()) is not compatible with fun((dynamic() | number()) -> pid()) + because + dynamic() | number() is not compatible with atom() + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:53:5 │ @@ -216,6 +272,10 @@ Because in the expression's type: Context expects type: #{...} The expected map has no corresponding key for: true. +------------------------------ Detailed message ------------------------------ + +key `true` is declared in the former but not in the latter and the latter map has no default association + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:99:13 │ @@ -305,6 +365,15 @@ Because in the expression's type: Context expects type: T , ... } +------------------------------ Detailed message ------------------------------ + + #{a => number()} is not compatible with #{atom() => T} + because + #{a => number()} is not compatible with #{atom() => T} + key `a` is declared in the former but not in the latter and key `a` isn't compatible with the default association of the latter map + because + number() is not compatible with T + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:126:5 │ @@ -345,6 +414,12 @@ Because in the expression's type: However the following candidate: 'b' Differs from the expected type: 'a' +------------------------------ Detailed message ------------------------------ + + 'a' | 'b' is not compatible with 'a' + because + 'b' is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:157:5 │ @@ -369,6 +444,12 @@ Because in the expression's type: However the following candidate: 'b' Differs from the expected type: 'a' +------------------------------ Detailed message ------------------------------ + + 'a' | 'b' is not compatible with 'a' + because + 'b' is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:172:5 │ @@ -385,6 +466,12 @@ Because in the expression's type: However the following candidate: 'a' Differs from the expected type: 'b' +------------------------------ Detailed message ------------------------------ + + 'a' | 'b' is not compatible with 'b' + because + 'a' is not compatible with 'b' + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/generic_fun_application.erl:226:1 │ @@ -434,6 +521,12 @@ Because in the expression's type: Context expects type: X ) +------------------------------ Detailed message ------------------------------ + + fun(() -> A) is not compatible with fun(() -> X) + because + A is not compatible with X + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:276:5 │ @@ -474,6 +567,12 @@ Because in the expression's type: However the following candidate: Last Differs from the expected type: 'first' +------------------------------ Detailed message ------------------------------ + + 'first' | Last is not compatible with 'first' + because + Last is not compatible with 'first' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:296:5 │ @@ -490,6 +589,12 @@ Because in the expression's type: However the following candidate: T Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + atom() | T is not compatible with atom() + because + T is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:322:5 │ @@ -507,6 +612,13 @@ Because in the expression's type: Context expects type: pid() , pid()} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {number(), pid()} is not compatible with {pid(), number()} + because + number() is not compatible with pid() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:330:5 │ @@ -565,6 +677,12 @@ Because in the expression's type: Context expects type: fun((A) -> A) with 0 type parameters The number of type parameters doesn't match. +------------------------------ Detailed message ------------------------------ + + fun((Z) -> Z) | fun((dynamic()) -> dynamic()) is not compatible with fun((A) -> A) + because + fun((Z) -> Z) with 1 type parameter is not compatible with fun((A) -> A) with 0 type parameters + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:346:9 │ @@ -583,6 +701,12 @@ Because in the expression's type: Context expects type: fun((dynamic()) -> dynamic()) with 0 type parameters The number of type parameters doesn't match. +------------------------------ Detailed message ------------------------------ + + fun((Z) -> Z) | fun((dynamic()) -> dynamic()) is not compatible with fun((dynamic()) -> dynamic()) + because + fun((Z) -> Z) with 1 type parameter is not compatible with fun((dynamic()) -> dynamic()) with 0 type parameters + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:346:9 │ @@ -601,6 +725,12 @@ Because in the expression's type: Context expects type: fun((A) -> A) with 0 type parameters The number of type parameters doesn't match. +------------------------------ Detailed message ------------------------------ + + fun((Z) -> Z) | fun((dynamic()) -> dynamic()) is not compatible with fun((A) -> A) + because + fun((Z) -> Z) with 1 type parameter is not compatible with fun((A) -> A) with 0 type parameters + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:358:9 │ @@ -651,6 +781,12 @@ Because in the expression's type: Context expects type: fun((Z) -> Z) with 0 type parameters The number of type parameters doesn't match. +------------------------------ Detailed message ------------------------------ + + fun((Z) -> Z) | fun((dynamic()) -> dynamic()) is not compatible with fun((Z) -> Z) + because + fun((Z) -> Z) with 1 type parameter is not compatible with fun((Z) -> Z) with 0 type parameters + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:358:9 │ @@ -669,6 +805,12 @@ Because in the expression's type: Context expects type: fun((dynamic()) -> dynamic()) with 0 type parameters The number of type parameters doesn't match. +------------------------------ Detailed message ------------------------------ + + fun((Z) -> Z) | fun((dynamic()) -> dynamic()) is not compatible with fun((dynamic()) -> dynamic()) + because + fun((Z) -> Z) with 1 type parameter is not compatible with fun((dynamic()) -> dynamic()) with 0 type parameters + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:358:9 │ @@ -687,6 +829,12 @@ Because in the expression's type: Context expects type: fun((Z) -> Z) with 0 type parameters The number of type parameters doesn't match. +------------------------------ Detailed message ------------------------------ + + fun((Z) -> Z) | fun((dynamic()) -> dynamic()) is not compatible with fun((Z) -> Z) + because + fun((Z) -> Z) with 1 type parameter is not compatible with fun((Z) -> Z) with 0 type parameters + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:432:18 │ @@ -727,6 +875,10 @@ Because in the expression's type: Context expects type: #{a := ..., ...} The type of the expression is missing the following required keys: a. +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:441:16 │ @@ -743,6 +895,10 @@ Because in the expression's type: Context expects type: #{a := ..., ...} The type of the expression is missing the following required keys: a. +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:446:15 │ @@ -760,6 +916,12 @@ Because in the expression's type: Context expects type: T ) +------------------------------ Detailed message ------------------------------ + + fun((#{a => number()}) -> number()) is not compatible with fun((#{{T} => T}) -> T) + because + number() is not compatible with T + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:446:15 │ @@ -778,6 +940,15 @@ Because in the expression's type: The expected map has no default association while the type of the expression has one. ) -> number()) +------------------------------ Detailed message ------------------------------ + + fun((#{a => number()}) -> number()) is not compatible with fun((#{{number()} => number()}) -> number()) + because + #{{number()} => number()} is not compatible with #{a => number()} + because + #{{number()} => number()} is not compatible with #{a => number()} + the latter map has no default association while the first map has one + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:471:24 │ @@ -795,6 +966,12 @@ Because in the expression's type: Context expects type: 'c' ) +------------------------------ Detailed message ------------------------------ + + fun(('a') -> 'b') is not compatible with fun(('a') -> 'c') + because + 'b' is not compatible with 'c' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:478:17 │ @@ -811,6 +988,10 @@ Because in the expression's type: Context expects type: #{a := ..., ...} The type of the expression is missing the following required keys: a. +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:478:17 │ @@ -827,6 +1008,10 @@ Because in the expression's type: Context expects type: #{a := ..., ...} The type of the expression is missing the following required keys: a. +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:500:36 │ @@ -863,6 +1048,16 @@ Because in the expression's type: ) -> 'ok') ) -> 'ok') +------------------------------ Detailed message ------------------------------ + + contravar(contravar('a' | 'b')) is not compatible with contravar(contravar('a')) + because + fun((contravar('a' | 'b')) -> 'ok') is not compatible with contravar(contravar('a')) + because + fun((contravar('a' | 'b')) -> 'ok') is not compatible with fun((contravar('a')) -> 'ok') + because + contravar('a') is not compatible with contravar('a' | 'b') + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:563:5 │ @@ -880,6 +1075,14 @@ Because in the expression's type: Context expects type: 'a' ) -> 'a') +------------------------------ Detailed message ------------------------------ + + invar('a') is not compatible with fun((atom()) -> atom()) + because + fun(('a') -> 'a') is not compatible with fun((atom()) -> atom()) + because + atom() is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:569:5 │ @@ -897,6 +1100,16 @@ Because in the expression's type: Context expects type: 'a' ) -> 'a') +------------------------------ Detailed message ------------------------------ + + invar('a') is not compatible with invar(atom()) + because + fun(('a') -> 'a') is not compatible with invar(atom()) + because + fun(('a') -> 'a') is not compatible with fun((atom()) -> atom()) + because + atom() is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:585:5 │ @@ -912,6 +1125,12 @@ Because in the expression's type: Here the type is: 'a' Context expects type: fun(('a') -> 'a') +------------------------------ Detailed message ------------------------------ + + 'a' is not compatible with invar('a') + because + 'a' is not compatible with fun(('a') -> 'a') + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/generic_fun_application.erl:625:1 │ @@ -956,6 +1175,10 @@ Because in the expression's type: Context expects type: #{...} The expected map has no corresponding key for: extra. +------------------------------ Detailed message ------------------------------ + +key `extra` is declared in the former but not in the latter and the latter map has no default association + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:721:25 │ @@ -982,6 +1205,14 @@ Because in the expression's type: Differs from the expected type: 'a' ) -> 'a') +------------------------------ Detailed message ------------------------------ + + fun(('a') -> 'a') is not compatible with fun(('a' | 'b') -> 'a' | 'b') + because + 'a' | 'b' is not compatible with 'a' + because + 'b' is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generic_fun_application.erl:752:32 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/generics_with_unions.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/generics_with_unions.pretty index 9c03aa9a60..53cd1350ec 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/generics_with_unions.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/generics_with_unions.pretty @@ -16,6 +16,15 @@ Because in the expression's type: Differs from the expected type: T , T | U} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {T | U, T | U} is not compatible with {T, U} + because + T | U is not compatible with T + because + U is not compatible with T + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generics_with_unions.erl:70:19 │ @@ -53,6 +62,12 @@ Because in the expression's type: Here the type is: [prop('a', number())] Context expects type: 'wrong_ret' +------------------------------ Detailed message ------------------------------ + + props('a', number()) is not compatible with 'wrong_ret' + because + [prop('a', number())] is not compatible with 'wrong_ret' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generics_with_unions.erl:217:19 │ @@ -77,6 +92,12 @@ Because in the expression's type: However the following candidate: [T] Differs from the expected type: T +------------------------------ Detailed message ------------------------------ + + [T] | T is not compatible with T + because + [T] is not compatible with T + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generics_with_unions.erl:221:17 │ @@ -93,6 +114,12 @@ Because in the expression's type: However the following candidate: [T] Differs from the expected type: T +------------------------------ Detailed message ------------------------------ + + T | [T] is not compatible with T + because + [T] is not compatible with T + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generics_with_unions.erl:222:19 │ @@ -144,6 +171,14 @@ Because in the expression's type: Context expects type: K ] +------------------------------ Detailed message ------------------------------ + + [K] | [[K]] is not compatible with [K] + because + [[K]] is not compatible with [K] + because + [K] is not compatible with K + error: ambiguous_union (See https://fb.me/eqwalizer_errors#ambiguous_union) ┌─ check/src/generics_with_unions.erl:332:31 │ @@ -170,6 +205,17 @@ Because in the expression's type: } ) -> 'ok') +------------------------------ Detailed message ------------------------------ + + query() is not compatible with fun(({'i', 'atom'}) -> 'ok') + because + fun(({'a', atom()} | {'b', binary()} | {'i', number()}) -> 'ok') is not compatible with fun(({'i', 'atom'}) -> 'ok') + because + {'i', 'atom'} is not compatible with {'a', atom()} | {'b', binary()} | {'i', number()} + because + at tuple index 2: + {'i', 'atom'} is not compatible with {'i', number()} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/generics_with_unions.erl:392:17 │ @@ -189,4 +235,15 @@ Because in the expression's type: } ) -> 'ok') +------------------------------ Detailed message ------------------------------ + + query() is not compatible with fun(({'a', number()}) -> 'ok') + because + fun(({'a', atom()} | {'b', binary()} | {'i', number()}) -> 'ok') is not compatible with fun(({'a', number()}) -> 'ok') + because + {'a', number()} is not compatible with {'a', atom()} | {'b', binary()} | {'i', number()} + because + at tuple index 2: + {'a', number()} is not compatible with {'a', atom()} + 16 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_bounded.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_bounded.pretty index 1987f06692..bbd9109d68 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_bounded.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_bounded.pretty @@ -14,6 +14,12 @@ Because in the expression's type: However the following candidate: 'b' Differs from the expected type: 'c' +------------------------------ Detailed message ------------------------------ + + dyn('a') | 'b' is not compatible with 'c' + because + 'b' is not compatible with 'c' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/gradual_bounded.erl:25:26 │ @@ -29,6 +35,16 @@ Because in the expression's type: Here the type is: 'a' Context expects type: 'b' +------------------------------ Detailed message ------------------------------ + + 'a' is not compatible with dyn('b') + because + 'a' is not compatible with dynamic('b') + because + 'a' is not compatible with dynamic('b') + because + 'a' is not compatible with 'b' + error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) ┌─ check/src/gradual_bounded.erl:44:27 │ @@ -69,6 +85,12 @@ Because in the expression's type: However the following candidate: 'test' Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + 'test' | number() is not compatible with number() + because + 'test' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/gradual_bounded.erl:89:5 │ @@ -85,4 +107,10 @@ Because in the expression's type: However the following candidate: 'test' Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + 'test' | dyn(number()) is not compatible with number() + because + 'test' is not compatible with number() + 8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_complex_types.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_complex_types.pretty index a7a81c8fb4..b7111f9239 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_complex_types.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_complex_types.pretty @@ -13,6 +13,12 @@ Because in the expression's type: Here the type is: 'undefined' Context expects type: #{...} +------------------------------ Detailed message ------------------------------ + + 'undefined' is not compatible with complex_map() + because + 'undefined' is not compatible with #{id := number(), {secret, id} => number(), atom() => term()} + error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) ┌─ check/src/gradual_complex_types.erl:29:25 │ @@ -40,6 +46,12 @@ Because in the expression's type: Here the type is: #{...} Context expects type: [T] +------------------------------ Detailed message ------------------------------ + + complex_map() is not compatible with [T] + because + #{id := number(), {secret, id} => number(), atom() => term()} is not compatible with [T] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/gradual_complex_types.erl:48:16 │ @@ -55,6 +67,12 @@ Because in the expression's type: Here the type is: #{...} Context expects type: [dynamic()] +------------------------------ Detailed message ------------------------------ + + complex_map() is not compatible with [dynamic()] + because + #{id := number(), {secret, id} => number(), atom() => term()} is not compatible with [dynamic()] + error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) ┌─ check/src/gradual_complex_types.erl:55:25 │ @@ -92,4 +110,11 @@ Because in the expression's type: Context expects type: number() } +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {dyn_map(), 'ok'} is not compatible with {#{a => 'atom'}, number()} + because + 'ok' is not compatible with number() + 9 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_custom.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_custom.pretty index 065a377d0d..34e16f1479 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_custom.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_custom.pretty @@ -100,6 +100,12 @@ Because in the expression's type: However the following candidate: 'a' Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + dynamic() | 'a' is not compatible with number() + because + 'a' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/gradual_custom.erl:120:3 │ @@ -196,6 +202,12 @@ Because in the expression's type: Context expects type: 'ok' No candidate of the expression's type matches the expected type. +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with 'ok' + because + string() | binary() is not compatible with 'ok' + error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) ┌─ check/src/gradual_custom.erl:210:25 │ @@ -218,6 +230,12 @@ Because in the expression's type: Context expects type: 'ok' No candidate of the expression's type matches the expected type. +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with 'ok' + because + string() | binary() is not compatible with 'ok' + error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) ┌─ check/src/gradual_custom.erl:217:25 │ @@ -240,6 +258,12 @@ Because in the expression's type: Context expects type: 'ok' No candidate of the expression's type matches the expected type. +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with 'ok' + because + string() | binary() is not compatible with 'ok' + error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) ┌─ check/src/gradual_custom.erl:224:25 │ @@ -262,6 +286,12 @@ Because in the expression's type: Context expects type: 'ok' No candidate of the expression's type matches the expected type. +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with 'ok' + because + string() | binary() is not compatible with 'ok' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/gradual_custom.erl:245:19 │ @@ -278,6 +308,12 @@ Because in the expression's type: However the following candidate: 'undefined' Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | 'undefined' is not compatible with number() + because + 'undefined' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/gradual_custom.erl:257:19 │ @@ -294,6 +330,12 @@ Because in the expression's type: However the following candidate: atom() Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | atom() | binary() is not compatible with number() + because + atom() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/gradual_custom.erl:263:19 │ @@ -310,6 +352,12 @@ Because in the expression's type: However the following candidate: atom() Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | dynamic() | number() | atom() | dynamic() is not compatible with number() + because + atom() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/gradual_custom.erl:269:19 │ @@ -326,6 +374,12 @@ Because in the expression's type: However the following candidate: atom() Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | dynamic() | atom() | dynamic() is not compatible with number() + because + atom() is not compatible with number() + error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) ┌─ check/src/gradual_custom.erl:277:25 │ @@ -348,6 +402,12 @@ Because in the expression's type: However the following candidate: {none()} Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + dynamic() | {none()} is not compatible with number() + because + {none()} is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/gradual_custom.erl:325:13 │ @@ -364,6 +424,14 @@ Because in the expression's type: However the following candidate: 'undefined' Differs from the expected type: 'foo' | 'bar' | binary() +------------------------------ Detailed message ------------------------------ + + 'bar' | 'undefined' | 'foo' is not compatible with 'foo' | 'bar' | binary() + because + 'undefined' is not compatible with 'foo' | 'bar' | binary() + because + 'undefined' is not compatible with 'foo' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/gradual_custom.erl:343:3 │ @@ -380,4 +448,10 @@ Because in the expression's type: However the following candidate: 'bar' Differs from the expected type: 'foo' +------------------------------ Detailed message ------------------------------ + + 'foo' | 'bar' is not compatible with 'foo' + because + 'bar' is not compatible with 'foo' + 37 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe.pretty index 35a509f2f6..5587da0d7e 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe.pretty @@ -62,6 +62,14 @@ Because in the expression's type: However the following candidate: 'a' Differs from the expected type: 'b' | 'c' +------------------------------ Detailed message ------------------------------ + + 'a' | 'b' | 'c' is not compatible with 'b' | 'c' + because + 'a' is not compatible with 'b' | 'c' + because + 'a' is not compatible with 'b' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/gradual_maybe.erl:147:14 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc.pretty index 28618b5f77..107e1b6e30 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc.pretty @@ -16,6 +16,16 @@ Because in the expression's type: Differs from the expected type: 'a' ) -> 'ok') +------------------------------ Detailed message ------------------------------ + + opaque:contravariant('a') is not compatible with opaque:contravariant('a' | 'b') + because + fun(('a') -> 'ok') is not compatible with opaque:contravariant('a' | 'b') + because + fun(('a') -> 'ok') is not compatible with fun(('a' | 'b') -> 'ok') + because + 'a' | 'b' is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/gradual_misc.erl:38:5 │ @@ -35,8 +45,13 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ check/src/gradual_misc.erl:46:41 │ 46 │ refine_tuple_neg(T) when is_tuple(T) -> T; - │ ^ T. + │ ^ + │ │ + │ T. Expression has type: {'b', 'c'} Context expected type: 'a' | {none()} + │ + +expected union does not contain any tuple type of size 2 4 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections.pretty index 74cd6b4ca4..88bcfb1267 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections.pretty @@ -14,6 +14,14 @@ Because in the expression's type: However the following candidate: #r2{} Differs from the expected type: #r1{} +------------------------------ Detailed message ------------------------------ + + #r1{} | #r2{} is not compatible with r1() + because + #r1{} | #r2{} is not compatible with #r1{} + because + #r2{} is not compatible with #r1{} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/guard_b_connections.erl:27:3 │ @@ -30,6 +38,14 @@ Because in the expression's type: However the following candidate: #r2{} Differs from the expected type: #r1{} +------------------------------ Detailed message ------------------------------ + + #r1{} | #r2{} is not compatible with r1() + because + #r1{} | #r2{} is not compatible with #r1{} + because + #r2{} is not compatible with #r1{} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/guard_b_connections.erl:32:3 │ @@ -46,6 +62,14 @@ Because in the expression's type: However the following candidate: #r2{} Differs from the expected type: #r1{} +------------------------------ Detailed message ------------------------------ + + #r1{} | #r2{} is not compatible with r1() + because + #r1{} | #r2{} is not compatible with #r1{} + because + #r2{} is not compatible with #r1{} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/guard_b_connections.erl:38:3 │ @@ -62,6 +86,14 @@ Because in the expression's type: However the following candidate: #r2{} Differs from the expected type: #r1{} +------------------------------ Detailed message ------------------------------ + + #r1{} | #r2{} is not compatible with r1() + because + #r1{} | #r2{} is not compatible with #r1{} + because + #r2{} is not compatible with #r1{} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/guard_b_connections.erl:44:3 │ @@ -78,4 +110,12 @@ Because in the expression's type: However the following candidate: #r2{} Differs from the expected type: #r1{} +------------------------------ Detailed message ------------------------------ + + #r1{} | #r2{} is not compatible with r1() + because + #r1{} | #r2{} is not compatible with #r1{} + because + #r2{} is not compatible with #r1{} + 5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic.pretty index bc1b2fff4a..c287958c68 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic.pretty @@ -30,6 +30,14 @@ Because in the expression's type: However the following candidate: pid() Differs from the expected type: number() | atom() +------------------------------ Detailed message ------------------------------ + + number() | atom() | pid() is not compatible with number() | atom() + because + pid() is not compatible with number() | atom() + because + pid() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/guards_logic.erl:73:5 │ @@ -47,6 +55,13 @@ Because in the expression's type: Context expects type: number() , term()} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {term(), term()} is not compatible with {number(), number()} + because + term() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/guards_logic.erl:101:46 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/hints.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/hints.pretty index f990884695..2e9f03966d 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/hints.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/hints.pretty @@ -38,6 +38,12 @@ Because in the expression's type: However the following candidate: term() Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + term() | 'undefined' is not compatible with atom() + because + term() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/hints.erl:52:5 │ @@ -54,6 +60,12 @@ Because in the expression's type: However the following candidate: term() Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + term() | 'undefined' is not compatible with atom() + because + term() is not compatible with atom() + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/hints.erl:55:1 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/iolists.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/iolists.pretty index 00e34f9cb8..bf9d6e219b 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/iolists.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/iolists.pretty @@ -23,6 +23,14 @@ Because in the expression's type: Differs from the expected type: binary() ] +------------------------------ Detailed message ------------------------------ + + [atom() | binary()] is not compatible with [binary()] + because + atom() | binary() is not compatible with binary() + because + atom() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/iolists.erl:55:22 │ @@ -41,6 +49,14 @@ Because in the expression's type: Differs from the expected type: atom() ] +------------------------------ Detailed message ------------------------------ + + [atom() | binary()] is not compatible with [atom()] + because + atom() | binary() is not compatible with atom() + because + binary() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/iolists.erl:60:27 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests.pretty index 4b2ec521dd..d0768e5669 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests.pretty @@ -16,6 +16,16 @@ Because in the expression's type: Differs from the expected type: atom() ] +------------------------------ Detailed message ------------------------------ + + [atom() | binary()] is not compatible with [atom()] | [binary()] + because + [atom() | binary()] is not compatible with [atom()] + because + atom() | binary() is not compatible with atom() + because + binary() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/lists_tests.erl:16:28 │ @@ -34,4 +44,14 @@ Because in the expression's type: Differs from the expected type: atom() ] +------------------------------ Detailed message ------------------------------ + + [atom() | binary()] is not compatible with [atom()] | [binary()] + because + [atom() | binary()] is not compatible with [atom()] + because + atom() | binary() is not compatible with atom() + because + binary() is not compatible with atom() + 2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/misc.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/misc.pretty index ec963a6249..45a1d69e57 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/misc.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/misc.pretty @@ -127,6 +127,12 @@ Because in the expression's type: Context expects type: atom() ] +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [atom()] + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:116:21 │ @@ -144,6 +150,12 @@ Because in the expression's type: Context expects type: atom() ] +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [atom()] + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:120:18 │ @@ -195,6 +207,12 @@ Because in the expression's type: Context expects type: number() ] +------------------------------ Detailed message ------------------------------ + + [atom()] is not compatible with [number()] + because + atom() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:143:29 │ @@ -305,17 +323,31 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ check/src/misc.erl:352:22 │ 352 │ catch test69_pos(atom). - │ ^^^^ 'atom'. + │ ^^^^ + │ │ + │ 'atom'. Expression has type: 'atom' Context expected type: [atom()] | [number()] + │ + + 'atom' is not compatible with [atom()] | [number()] + because + 'atom' is not compatible with [atom()] error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:357:22 │ 357 │ catch test69_pos(atom). - │ ^^^^ 'atom'. + │ ^^^^ + │ │ + │ 'atom'. Expression has type: 'atom' Context expected type: [atom()] | [number()] + │ + + 'atom' is not compatible with [atom()] | [number()] + because + 'atom' is not compatible with [atom()] error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:404:11 @@ -361,6 +393,17 @@ Because in the expression's type: ] , [atom() | number()]} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[number() | atom()], [atom() | number()]} is not compatible with {[atom()], [number()]} + because + [number() | atom()] is not compatible with [atom()] + because + number() | atom() is not compatible with atom() + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:461:5 │ @@ -381,6 +424,17 @@ Because in the expression's type: ] , [atom() | number()]} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[atom() | number()], [atom() | number()]} is not compatible with {[atom()] | [number()], [atom()] | [number()]} + because + [atom() | number()] is not compatible with [atom()] | [number()] + because + [atom() | number()] is not compatible with [atom()] + because + atom() | number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:465:12 │ @@ -455,6 +509,16 @@ Because in the expression's type: Differs from the expected type: atom() | number() ] +------------------------------ Detailed message ------------------------------ + + [atom() | binary()] is not compatible with [atom() | number()] + because + atom() | binary() is not compatible with atom() | number() + because + binary() is not compatible with atom() | number() + because + binary() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:575:14 │ @@ -488,6 +552,12 @@ Because in the expression's type: Context expects type: [A] ] +------------------------------ Detailed message ------------------------------ + + [A] is not compatible with [[A]] + because + A is not compatible with [A] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:611:21 │ @@ -682,6 +752,13 @@ Because in the expression's type: Context expects type: 'ok' } +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {none(), 'err'} is not compatible with {'ok', 'ok'} + because + 'err' is not compatible with 'ok' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:741:5 │ @@ -698,6 +775,16 @@ Because in the expression's type: However the following candidate: 'v2_op' Differs from the expected type: 'stuff1' | 'v0_op2' | 'stuff2' | 'v0_op1' | 'v1_op2' | ... +------------------------------ Detailed message ------------------------------ + + v2_op() is not compatible with v1_op() + because + 'v2_op' | v1_op() is not compatible with v1_op() + because + 'v2_op' | v1_op() is not compatible with 'v1_op1' | 'v1_op2' | stuff() | v0_op() + because + 'v2_op' is not compatible with 'v1_op1' | 'v1_op2' | stuff() | v0_op() + error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) ┌─ check/src/misc.erl:760:1 │ @@ -747,6 +834,16 @@ Because in the expression's type: Context expects type: #set{} | #{term() => []} No candidate matches in the expected union. +------------------------------ Detailed message ------------------------------ + + misc:set() is not compatible with sets:set() + because + [] is not compatible with sets:set() + because + [] is not compatible with sets:set(term()) + because + [] is not compatible with #set{} | #{term() => []} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:850:5 │ @@ -764,6 +861,13 @@ Because in the expression's type: Context expects type: pid() } +------------------------------ Detailed message ------------------------------ + + at tuple index 3: + {'ok', 'lists', number()} is not compatible with {'ok', atom(), pid()} + because + number() is not compatible with pid() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:860:5 │ @@ -803,6 +907,12 @@ Because in the expression's type: Here the type is: {binary()} Context expects type: [binary()] +------------------------------ Detailed message ------------------------------ + + {binary()} is not compatible with erlang:iovec() + because + {binary()} is not compatible with [binary()] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:949:15 │ @@ -829,6 +939,14 @@ Because in the expression's type: No candidate of the expression's type matches the expected type. ] +------------------------------ Detailed message ------------------------------ + + ['MM' | 'MS' | 'EE' | 'MA' | 'GE'] is not compatible with [erlang:priority_level()] + because + 'MM' | 'MS' | 'EE' | 'MA' | 'GE' is not compatible with erlang:priority_level() + because + 'MM' | 'MS' | 'EE' | 'MA' | 'GE' is not compatible with 'low' | 'normal' | 'high' | 'max' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:971:5 │ @@ -844,6 +962,12 @@ Because in the expression's type: Here the type is: {number(), number(), number()} Context expects type: atom() +------------------------------ Detailed message ------------------------------ + + erlang:timestamp() is not compatible with atom() + because + {number(), number(), number()} is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:987:12 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/neg.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/neg.pretty index 585b5f8642..55ce8bf6f5 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/neg.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/neg.pretty @@ -39,6 +39,13 @@ Because in the expression's type: Context expects type: atom() } +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {'ok', term()} is not compatible with {atom(), atom()} + because + term() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/neg.erl:27:21 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/numbers.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/numbers.pretty index 8c78c1ffbe..8760657fa4 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/numbers.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/numbers.pretty @@ -150,6 +150,12 @@ Because in the expression's type: However the following candidate: 'a' Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + 'a' | number() is not compatible with number() + because + 'a' is not compatible with number() + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/numbers.erl:538:1 │ @@ -294,6 +300,13 @@ Because in the expression's type: Context expects type: 'ok' } +------------------------------ Detailed message ------------------------------ + + at tuple index 5: + {number(), number(), number(), number(), 'error'} is not compatible with {number(), number(), number(), number(), 'ok'} + because + 'error' is not compatible with 'ok' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/numbers.erl:658:3 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/opaque.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/opaque.pretty index 5c207ff164..765efea8fe 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/opaque.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/opaque.pretty @@ -16,6 +16,16 @@ Because in the expression's type: Context expects type: #{...} The expected map has no corresponding key for: {ok, error}. +------------------------------ Detailed message ------------------------------ + + sets:set({'ok', 'error'}) is not compatible with sets:set({'ok', 'ok'}) + because + #set{} | #{{ok, error} => []} is not compatible with sets:set({'ok', 'ok'}) + because + #set{} | #{{ok, error} => []} is not compatible with #set{} | #{{ok, ok} => []} + because + #{{ok, error} => []} is not compatible with #set{} | #{{ok, ok} => []} + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/opaque.erl:29:1 │ @@ -37,6 +47,12 @@ Because in the expression's type: Here the type is: {'ok'} Context expects type: none() +------------------------------ Detailed message ------------------------------ + + misc:o() is not compatible with none() + because + {'ok'} is not compatible with none() + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/opaque.erl:86:1 │ @@ -77,6 +93,14 @@ Because in the expression's type: However the following candidate: 'a' Differs from the expected type: {'ok'} +------------------------------ Detailed message ------------------------------ + + misc:o() | 'a' is not compatible with misc:o() + because + misc:o() | 'a' is not compatible with {'ok'} + because + 'a' is not compatible with {'ok'} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/opaque.erl:135:18 │ @@ -93,6 +117,14 @@ Because in the expression's type: However the following candidate: 'a' Differs from the expected type: {'ok'} +------------------------------ Detailed message ------------------------------ + + misc:o() | 'a' is not compatible with misc:o() + because + misc:o() | 'a' is not compatible with {'ok'} + because + 'a' is not compatible with {'ok'} + error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) ┌─ check/src/opaque.erl:150:1 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/other.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/other.pretty index da1b4e48cb..b75aabcf84 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/other.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/other.pretty @@ -13,6 +13,12 @@ Because in the expression's type: Here the type is: term() Context expects type: #{...} +------------------------------ Detailed message ------------------------------ + + term() is not compatible with logger:metadata() + because + term() is not compatible with #{domain => [atom()], file => file:filename(), gl => pid(), line => number(), mfa => {atom(), atom(), number()}, pid => pid(), report_cb => logger:report_cb(), time => logger:timestamp(), atom() => term()} + error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) ┌─ check/src/other.erl:59:27 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/otp28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/otp28.pretty index 5113f80c15..026d55c435 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/otp28.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/otp28.pretty @@ -14,6 +14,14 @@ Because in the expression's type: Context expects type: 'ok' | 'error' No candidate matches in the expected union. +------------------------------ Detailed message ------------------------------ + + 'warning' is not compatible with foo() + because + 'warning' is not compatible with 'ok' | 'error' + because + 'warning' is not compatible with 'ok' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/otp28.erl:28:5 │ @@ -31,6 +39,12 @@ Because in the expression's type: Context expects type: atom() ] +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [atom()] + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/otp28.erl:40:5 │ @@ -48,6 +62,12 @@ Because in the expression's type: Context expects type: pid() ] +------------------------------ Detailed message ------------------------------ + + [binary()] is not compatible with [pid()] + because + binary() is not compatible with pid() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/otp28.erl:52:5 │ @@ -75,6 +95,15 @@ Because in the expression's type: } ] +------------------------------ Detailed message ------------------------------ + + [{atom(), binary()}] is not compatible with [{atom(), atom()}] + because + at tuple index 2: + {atom(), binary()} is not compatible with {atom(), atom()} + because + binary() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/otp28.erl:68:5 │ @@ -92,6 +121,13 @@ Because in the expression's type: Context expects type: atom() , ... } +------------------------------ Detailed message ------------------------------ + + #{atom() => binary()} is not compatible with #{atom() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/otp28.erl:76:5 │ @@ -111,4 +147,13 @@ Because in the expression's type: , atom()} ] +------------------------------ Detailed message ------------------------------ + + [{atom(), binary(), binary(), atom()}] is not compatible with [{atom(), binary(), atom(), binary()}] + because + at tuple index 3: + {atom(), binary(), binary(), atom()} is not compatible with {atom(), binary(), atom(), binary()} + because + binary() is not compatible with atom() + 7 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques.pretty index 59bd5e6099..b41039f95b 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques.pretty @@ -17,6 +17,17 @@ Because in the expression's type: , term(), term()} } +------------------------------ Detailed message ------------------------------ + + gb_sets:set(atom()) is not compatible with gb_sets:set(number()) + because + {number(), gb_sets:gb_set_node(atom())} is not compatible with gb_sets:set(number()) + because + at tuple index 2: + {number(), gb_sets:gb_set_node(atom())} is not compatible with {number(), gb_sets:gb_set_node(number())} + because + gb_sets:gb_set_node(atom()) is not compatible with gb_sets:gb_set_node(number()) + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/otp_opaques.erl:42:5 │ @@ -34,6 +45,12 @@ Because in the expression's type: Context expects type: A ] +------------------------------ Detailed message ------------------------------ + + [[A]] is not compatible with [A] + because + [A] is not compatible with A + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/otp_opaques.erl:99:17 │ @@ -50,6 +67,14 @@ Because in the expression's type: Context expects type: #set{} | #{a => []} No candidate of the expression's type matches the expected type. +------------------------------ Detailed message ------------------------------ + + maps:iterator('k', 'v') is not compatible with sets:set('a') + because + {'k', 'v', maps:iterator('k', 'v')} | 'none' | [number()] | [['k']] is not compatible with sets:set('a') + because + {'k', 'v', maps:iterator('k', 'v')} | 'none' | [number()] | [['k']] is not compatible with #set{} | #{a => []} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/otp_opaques.erl:102:13 │ @@ -74,6 +99,14 @@ Because in the expression's type: Context expects type: #set{} | #{a => []} No candidate of the expression's type matches the expected type. +------------------------------ Detailed message ------------------------------ + + maps:iterator('k', 'v') is not compatible with sets:set('a') + because + {'k', 'v', maps:iterator('k', 'v')} | 'none' | [number()] | [['k']] is not compatible with sets:set('a') + because + {'k', 'v', maps:iterator('k', 'v')} | 'none' | [number()] | [['k']] is not compatible with #set{} | #{a => []} + error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) ┌─ check/src/otp_opaques.erl:124:5 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded.pretty index aa87b295ad..117ed8b349 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded.pretty @@ -30,13 +30,26 @@ Because in the expression's type: Context expects type: 'b' ) +------------------------------ Detailed message ------------------------------ + + fun(('a') -> 'z') is not compatible with fun(('a') -> 'b') | fun(('a') -> 'c') + because + fun(('a') -> 'z') is not compatible with fun(('a') -> 'b') + because + 'z' is not compatible with 'b' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/overloaded.erl:126:15 │ 126 │ Res = bar({fun(a) -> a end}), - │ ^^^^^^^^^^^^^^^^^ {fun}. + │ ^^^^^^^^^^^^^^^^^ + │ │ + │ {fun}. Expression has type: {fun((dynamic()) -> dynamic())} Context expected type: fun(('a') -> 'b') | fun(('a') -> 'c') + │ + +expected union does not contain any tuple type of size 1 error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/overloaded.erl:198:37 @@ -94,6 +107,12 @@ Because in the expression's type: However the following candidate: {} Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | {} is not compatible with number() + because + {} is not compatible with number() + error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) ┌─ check/src/overloaded.erl:261:1 │ @@ -111,9 +130,16 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ check/src/overloaded.erl:269:14 │ 269 │ _ = swap(""), - │ ^^ string_lit. + │ ^^ + │ │ + │ string_lit. Expression has type: [] Context expected type: atom() | binary() + │ + + [] is not compatible with atom() | binary() + because + [] is not compatible with atom() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/overloaded.erl:290:5 diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded_specs_union.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded_specs_union.pretty index 6687ec3321..3483635724 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded_specs_union.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded_specs_union.pretty @@ -14,6 +14,12 @@ Because in the expression's type: However the following candidate: pid() Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + atom() | pid() is not compatible with atom() + because + pid() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/overloaded_specs_union.erl:19:29 │ @@ -30,4 +36,12 @@ Because in the expression's type: However the following candidate: pid() Differs from the expected type: atom() | binary() +------------------------------ Detailed message ------------------------------ + + atom() | binary() | pid() is not compatible with atom() | binary() + because + pid() is not compatible with atom() | binary() + because + pid() is not compatible with atom() + 2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/pats.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/pats.pretty index 171c12dc46..d0d4f19c1a 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/pats.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/pats.pretty @@ -14,4 +14,10 @@ Because in the expression's type: However the following candidate: 'error' Differs from the expected type: #{term() => term()} +------------------------------ Detailed message ------------------------------ + + #{a => 'ok'} | 'error' is not compatible with #{term() => term()} + because + 'error' is not compatible with #{term() => term()} + 1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/records.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/records.pretty index f59eda6cd2..5b6854f238 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/records.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/records.pretty @@ -18,9 +18,16 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ check/src/records.erl:50:21 │ 50 │ mk_rec_neg(rec2) -> #rec2{}. - │ ^^^^^^^ #rec2{...}. + │ ^^^^^^^ + │ │ + │ #rec2{...}. Expression has type: #rec2{} Context expected type: #rec1{} | #rec3{} + │ + + #rec2{} is not compatible with #rec1{} | #rec3{} + because + #rec2{} is not compatible with #rec1{} error: undefined_field (See https://fb.me/eqwalizer_errors#undefined_field) ┌─ check/src/records.erl:59:11 @@ -101,6 +108,13 @@ Because in the expression's type: Context expects type: number() , number()} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {atom(), number()} is not compatible with {number(), atom()} + because + atom() is not compatible with number() + error: undefined_field (See https://fb.me/eqwalizer_errors#undefined_field) ┌─ check/src/records.erl:144:17 │ @@ -167,6 +181,14 @@ Because in the expression's type: Context expects type: number() } +------------------------------ Detailed message ------------------------------ + + #any_box{inner :: 'ok'} is not compatible with int_box() + because + #any_box{inner :: 'ok'} is not compatible with #any_box{inner :: number()} + because + 'ok' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:222:5 │ @@ -184,6 +206,12 @@ Because in the expression's type: Context expects type: number() } +------------------------------ Detailed message ------------------------------ + + #any_box{inner :: 'ok'} is not compatible with #any_box{inner :: number()} + because + 'ok' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:282:27 │ @@ -200,6 +228,12 @@ Because in the expression's type: Context expects type: number() | 'false' | 'true' No candidate matches in the expected union. +------------------------------ Detailed message ------------------------------ + + 'a' is not compatible with number() | boolean() + because + 'a' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:287:23 │ @@ -216,6 +250,12 @@ Because in the expression's type: Context expects type: number() | 'false' | 'true' No candidate matches in the expected union. +------------------------------ Detailed message ------------------------------ + + 'a' is not compatible with number() | boolean() + because + 'a' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:292:5 │ @@ -233,6 +273,14 @@ Because in the expression's type: Context expects type: number() } +------------------------------ Detailed message ------------------------------ + + #int_bool_box{inner :: 'true'} is not compatible with only_int_box() + because + #int_bool_box{inner :: 'true'} is not compatible with #int_bool_box{inner :: number()} + because + 'true' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:308:28 │ @@ -249,6 +297,12 @@ Because in the expression's type: Context expects type: number() | 'false' | 'true' No candidate matches in the expected union. +------------------------------ Detailed message ------------------------------ + + 'a' is not compatible with number() | boolean() + because + 'a' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:314:5 │ @@ -266,6 +320,14 @@ Because in the expression's type: Context expects type: boolean() } +------------------------------ Detailed message ------------------------------ + + #int_bool_box{inner :: number()} is not compatible with only_bool_box() + because + #int_bool_box{inner :: number()} is not compatible with #int_bool_box{inner :: boolean()} + because + number() is not compatible with boolean() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:319:5 │ @@ -281,6 +343,12 @@ Because in the expression's type: Here the type is: #int_bool_box{inner :: number()} Context expects type: #any_box{} +------------------------------ Detailed message ------------------------------ + + only_int_box() is not compatible with #any_box{} + because + #int_bool_box{inner :: number()} is not compatible with #any_box{} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:319:5 │ @@ -315,6 +383,15 @@ Because in the expression's type: No candidate matches in the expected union. } +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {'int_bool_box', 'a'} is not compatible with {'int_bool_box', number() | boolean()} + because + 'a' is not compatible with number() | boolean() + because + 'a' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:334:5 │ @@ -332,6 +409,15 @@ Because in the expression's type: Context expects type: number() } +------------------------------ Detailed message ------------------------------ + + {'int_bool_box', 'a'} is not compatible with only_int_box() + because + at tuple index 2: + {'int_bool_box', 'a'} is not compatible with {'int_bool_box', number()} + because + 'a' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:352:5 │ @@ -348,6 +434,12 @@ Because in the expression's type: However the following candidate: 'false' Differs from the expected type: 'true' +------------------------------ Detailed message ------------------------------ + + boolean() | 'true' is not compatible with 'true' + because + 'false' is not compatible with 'true' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:355:13 │ @@ -371,6 +463,12 @@ Because in the expression's type: Here the type is: #bad_default{} Context expects type: #int_bool_box{inner :: number()} +------------------------------ Detailed message ------------------------------ + + #bad_default{} is not compatible with only_int_box() + because + #bad_default{} is not compatible with #int_bool_box{inner :: number()} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:372:5 │ @@ -388,6 +486,13 @@ Because in the expression's type: Context expects type: 'bad_default' , number()} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {'int_bool_box', number()} is not compatible with {'bad_default', number()} + because + 'int_bool_box' is not compatible with 'bad_default' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:388:31 │ @@ -405,6 +510,12 @@ Because in the expression's type: Context expects type: number() } +------------------------------ Detailed message ------------------------------ + + #refined_two_fields{} is not compatible with #refined_two_fields{inner :: number()} + because + term() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:402:5 │ @@ -483,6 +594,12 @@ Because in the expression's type: However the following candidate: 'my_record' Differs from the expected type: binary() +------------------------------ Detailed message ------------------------------ + + 'my_record' | binary() is not compatible with binary() + because + 'my_record' is not compatible with binary() + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/records.erl:517:1 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases.pretty index ffd83bc179..215d6a54ae 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases.pretty @@ -17,6 +17,16 @@ Because in the expression's type: Context expects type: 'b' , chainA()} +------------------------------ Detailed message ------------------------------ + + chainA() is not compatible with chainB() + because + 'nil' | {'a', chainA()} is not compatible with chainB() + because + 'nil' | {'a', chainA()} is not compatible with 'nil' | {'b', chainB()} + because + {'a', chainA()} is not compatible with 'nil' | {'b', chainB()} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/recursive_aliases.erl:62:20 │ @@ -36,6 +46,16 @@ Because in the expression's type: Context expects type: 'a' , chainB()} +------------------------------ Detailed message ------------------------------ + + chainB() is not compatible with chainA() + because + 'nil' | {'b', chainB()} is not compatible with chainA() + because + 'nil' | {'b', chainB()} is not compatible with 'nil' | {'a', chainA()} + because + {'b', chainB()} is not compatible with 'nil' | {'a', chainA()} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/recursive_aliases.erl:65:20 │ @@ -55,6 +75,16 @@ Because in the expression's type: Context expects type: 'a' , chainAB()} +------------------------------ Detailed message ------------------------------ + + chainAB() is not compatible with chainA() + because + 'nil' | {'a', chainAB()} | {'b', chainAB()} is not compatible with chainA() + because + 'nil' | {'a', chainAB()} | {'b', chainAB()} is not compatible with 'nil' | {'a', chainA()} + because + {'b', chainAB()} is not compatible with 'nil' | {'a', chainA()} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/recursive_aliases.erl:68:20 │ @@ -74,6 +104,16 @@ Because in the expression's type: Context expects type: 'b' , chainAB()} +------------------------------ Detailed message ------------------------------ + + chainAB() is not compatible with chainB() + because + 'nil' | {'a', chainAB()} | {'b', chainAB()} is not compatible with chainB() + because + 'nil' | {'a', chainAB()} | {'b', chainAB()} is not compatible with 'nil' | {'b', chainB()} + because + {'a', chainAB()} is not compatible with 'nil' | {'b', chainB()} + error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) ┌─ check/src/recursive_aliases.erl:70:1 │ @@ -103,6 +143,17 @@ Because in the expression's type: However the following candidate: {'a', atom(), pchainA(atom())} Differs from the expected type: 'nil' | {'a', pchainAB(atom())} | {'b', pchainAB(atom())} +------------------------------ Detailed message ------------------------------ + + pchainA(atom()) is not compatible with pchainAB(atom()) + because + 'nil' | {'a', atom(), pchainA(atom())} is not compatible with pchainAB(atom()) + because + 'nil' | {'a', atom(), pchainA(atom())} is not compatible with 'nil' | {'a', pchainAB(atom())} | {'b', pchainAB(atom())} + because + {'a', atom(), pchainA(atom())} is not compatible with 'nil' | {'a', pchainAB(atom())} | {'b', pchainAB(atom())} + expected union does not contain any tuple type of size 3 + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/recursive_aliases.erl:113:23 │ @@ -121,6 +172,16 @@ Because in the expression's type: Context expects type: #{a := ..., ...} The type of the expression is missing the following required keys: a. +------------------------------ Detailed message ------------------------------ + + mChainB() is not compatible with mChainA() + because + 'nil' | #{b := mChainB()} is not compatible with mChainA() + because + 'nil' | #{b := mChainB()} is not compatible with 'nil' | #{a := mChainA()} + because + #{b := mChainB()} is not compatible with 'nil' | #{a := mChainA()} + error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) ┌─ check/src/recursive_aliases.erl:138:15 │ @@ -149,6 +210,16 @@ Because in the expression's type: No candidate matches in the expected union. , pchainA('a')} +------------------------------ Detailed message ------------------------------ + + pchainA('a') is not compatible with pchainA('b' | 'c') + because + 'nil' | {'a', 'a', pchainA('a')} is not compatible with pchainA('b' | 'c') + because + 'nil' | {'a', 'a', pchainA('a')} is not compatible with 'nil' | {'a', 'b' | 'c', pchainA('b' | 'c')} + because + {'a', 'a', pchainA('a')} is not compatible with 'nil' | {'a', 'b' | 'c', pchainA('b' | 'c')} + error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) ┌─ check/src/recursive_aliases.erl:202:1 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/refine.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/refine.pretty index 711e1dc2e9..b443f787c6 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/refine.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/refine.pretty @@ -23,6 +23,13 @@ Because in the expression's type: Context expects type: none() , A} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {B, A} is not compatible with {none(), none()} + because + B is not compatible with none() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:22:15 │ @@ -48,6 +55,12 @@ Because in the expression's type: Context expects type: none() ) +------------------------------ Detailed message ------------------------------ + + fun((B | A) -> A) is not compatible with fun((A | B) -> none()) + because + A is not compatible with none() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:34:16 │ @@ -65,6 +78,12 @@ Because in the expression's type: Context expects type: none() ) +------------------------------ Detailed message ------------------------------ + + fun((atom() | A) -> A) is not compatible with fun((A | atom()) -> none()) + because + A is not compatible with none() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:84:27 │ @@ -114,6 +133,13 @@ Because in the expression's type: Context expects type: none() , binary()} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {number(), binary()} is not compatible with {none(), none()} + because + number() is not compatible with none() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:126:32 │ @@ -131,6 +157,13 @@ Because in the expression's type: Context expects type: none() , atom()} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {number(), atom()} is not compatible with {none(), none()} + because + number() is not compatible with none() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:139:28 │ @@ -157,6 +190,14 @@ Because in the expression's type: Differs from the expected type: 'a' ] +------------------------------ Detailed message ------------------------------ + + ['a' | 'b'] is not compatible with ['a'] + because + 'a' | 'b' is not compatible with 'a' + because + 'b' is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:151:28 │ @@ -183,6 +224,14 @@ Because in the expression's type: Differs from the expected type: 'a' ] +------------------------------ Detailed message ------------------------------ + + ['a' | 'b'] is not compatible with ['a'] + because + 'a' | 'b' is not compatible with 'a' + because + 'b' is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:166:5 │ @@ -224,6 +273,13 @@ Because in the expression's type: Context expects type: 'not_my_rec' , number(), atom()} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {'my_rec', number(), atom()} is not compatible with {'not_my_rec', term(), term()} + because + 'my_rec' is not compatible with 'not_my_rec' + error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) ┌─ check/src/refine.erl:199:10 │ @@ -254,6 +310,13 @@ Because in the expression's type: Context expects type: number() , number()} +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {'my_rec', atom(), number()} is not compatible with {'my_rec', number(), atom()} + because + atom() is not compatible with number() + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/refine.erl:218:1 │ @@ -311,6 +374,13 @@ Because in the expression's type: Context expects type: number() , number()} +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {'my_rec', atom(), number()} is not compatible with {'my_rec', number(), atom()} + because + atom() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:250:26 │ @@ -328,6 +398,15 @@ Because in the expression's type: Context expects type: number() , number()} +------------------------------ Detailed message ------------------------------ + + {'my_rec', atom(), number()} is not compatible with dynamic(#my_rec{}) + because + at tuple index 2: + {'my_rec', atom(), number()} is not compatible with {'my_rec', number(), atom()} + because + atom() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:262:26 │ @@ -345,6 +424,13 @@ Because in the expression's type: Context expects type: atom() , atom()} +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {'my_rec', number(), atom()} is not compatible with {'my_rec', atom(), number()} + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:262:26 │ @@ -362,6 +448,15 @@ Because in the expression's type: Context expects type: atom() , atom()} +------------------------------ Detailed message ------------------------------ + + #my_rec{} is not compatible with dynamic({'my_rec', atom(), number()}) + because + at tuple index 2: + {'my_rec', number(), atom()} is not compatible with {'my_rec', atom(), number()} + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:278:21 │ @@ -379,6 +474,13 @@ Because in the expression's type: Context expects type: atom() , atom()} +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {'my_rec', number(), atom()} is not compatible with {'my_rec', atom(), atom()} + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:282:16 │ @@ -395,6 +497,12 @@ Because in the expression's type: However the following candidate: atom() Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + atom() | number() is not compatible with number() + because + atom() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:286:13 │ @@ -411,6 +519,12 @@ Because in the expression's type: However the following candidate: 'a' Differs from the expected type: {'my_rec', term(), term()} +------------------------------ Detailed message ------------------------------ + + #my_rec{} | 'a' is not compatible with {'my_rec', term(), term()} + because + 'a' is not compatible with {'my_rec', term(), term()} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/refine.erl:296:5 │ @@ -427,6 +541,12 @@ Because in the expression's type: However the following candidate: 'undefined' Differs from the expected type: binary() +------------------------------ Detailed message ------------------------------ + + 'undefined' | binary() is not compatible with binary() + because + 'undefined' is not compatible with binary() + error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) ┌─ check/src/refine.erl:378:27 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types.pretty index 8943deb90a..cc9f9d0634 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types.pretty @@ -13,6 +13,12 @@ Because in the expression's type: Here the type is: 'undefined' Context expects type: #{...} +------------------------------ Detailed message ------------------------------ + + 'undefined' is not compatible with complex_map() + because + 'undefined' is not compatible with #{id := number(), {secret, id} => number(), atom() => term()} + error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) ┌─ check/src/strict_complex_types.erl:29:25 │ @@ -40,6 +46,12 @@ Because in the expression's type: Here the type is: #{...} Context expects type: [T] +------------------------------ Detailed message ------------------------------ + + complex_map() is not compatible with [T] + because + #{id := number(), {secret, id} => number(), atom() => term()} is not compatible with [T] + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/strict_complex_types.erl:48:16 │ @@ -55,4 +67,10 @@ Because in the expression's type: Here the type is: #{...} Context expects type: [dynamic()] +------------------------------ Detailed message ------------------------------ + + complex_map() is not compatible with [dynamic()] + because + #{id := number(), {secret, id} => number(), atom() => term()} is not compatible with [dynamic()] + 5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg.pretty index 4413a8fee8..1ee53764d2 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg.pretty @@ -31,6 +31,12 @@ Because in the expression's type: Context expects type: atom() ) +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> term()) is not compatible with fun((term()) -> atom()) + because + term() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/subtype_neg.erl:27:11 │ @@ -47,6 +53,14 @@ Because in the expression's type: However the following candidate: 'c' Differs from the expected type: 'a' | 'b' +------------------------------ Detailed message ------------------------------ + + 'a' | 'b' | 'c' is not compatible with 'a' | 'b' + because + 'c' is not compatible with 'a' | 'b' + because + 'c' is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/subtype_neg.erl:30:11 │ @@ -73,6 +87,17 @@ Because in the expression's type: Differs from the expected type: 'a' , 'a' | 'b'} +------------------------------ Detailed message ------------------------------ + + {'a' | 'b', 'a' | 'b'} is not compatible with {'a', 'b'} | {'b', 'a'} + because + at tuple index 1: + {'a' | 'b', 'a' | 'b'} is not compatible with {'a', 'b'} + because + 'a' | 'b' is not compatible with 'a' + because + 'b' is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/subtype_neg.erl:38:11 │ @@ -91,6 +116,17 @@ Because in the expression's type: Differs from the expected type: 'a' , ab()} +------------------------------ Detailed message ------------------------------ + + pair_ab() is not compatible with pair_diff_elems() + because + {ab(), ab()} is not compatible with pair_diff_elems() + because + {ab(), ab()} is not compatible with {'a', 'b'} | {'b', 'a'} + because + at tuple index 1: + {ab(), ab()} is not compatible with {'a', 'b'} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/subtype_neg.erl:41:11 │ @@ -115,6 +151,10 @@ Because in the expression's type: Context expects type: #{a := ..., ...} The type of the expression is missing the following required keys: a. +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/subtype_neg.erl:52:13 │ @@ -131,6 +171,10 @@ Because in the expression's type: Context expects type: #{...} The expected map has no corresponding key for: b. +------------------------------ Detailed message ------------------------------ + +key `b` is declared in the former but not in the latter and the latter map has no default association + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/subtype_neg.erl:60:13 │ @@ -147,6 +191,10 @@ Because in the expression's type: Context expects type: #{a := ..., ...} The type of the expression is missing the following required keys: a. +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/subtype_neg.erl:64:13 │ @@ -164,6 +212,13 @@ Because in the expression's type: Context expects type: atom() , ... } +------------------------------ Detailed message ------------------------------ + + #{term() => number()} is not compatible with #{atom() => number()} + the default associations are not compatible + because + term() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/subtype_neg.erl:68:13 │ @@ -181,6 +236,13 @@ Because in the expression's type: Context expects type: number() , ... } +------------------------------ Detailed message ------------------------------ + + #{atom() => term()} is not compatible with #{atom() => number()} + the default associations are not compatible + because + term() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/subtype_neg.erl:72:13 │ @@ -197,6 +259,13 @@ Because in the expression's type: Context expects type: #{...} (no default association) The expected map has no default association while the type of the expression has one. +------------------------------ Detailed message ------------------------------ + + #{atom() => term()} is not compatible with #{} + because + #{atom() => term()} is not compatible with #{} + the latter map has no default association while the first map has one + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/subtype_neg.erl:79:15 │ @@ -222,6 +291,13 @@ Because in the expression's type: Context expects type: 'ok' } +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {{}, 'error'} is not compatible with {tuple(), 'ok'} + because + 'error' is not compatible with 'ok' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/subtype_neg.erl:87:5 │ @@ -239,6 +315,13 @@ Because in the expression's type: Context expects type: 'ok' } +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {[], 'error'} is not compatible with {[pid()], 'ok'} + because + 'error' is not compatible with 'ok' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/subtype_neg.erl:91:5 │ @@ -256,6 +339,13 @@ Because in the expression's type: Context expects type: 'ok' } +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {[], 'error'} is not compatible with {iolist(), 'ok'} + because + 'error' is not compatible with 'ok' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/subtype_neg.erl:94:13 │ @@ -292,4 +382,10 @@ Because in the expression's type: Context expects type: none() ] +------------------------------ Detailed message ------------------------------ + + ['a'] | [none()] is not compatible with [] + because + ['a'] is not compatible with [] + 20 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/t_maps.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/t_maps.pretty index 5c2b07ae96..d0e08f9ac4 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/t_maps.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/t_maps.pretty @@ -15,6 +15,13 @@ Because in the expression's type: Context expects type: atom() , ... } +------------------------------ Detailed message ------------------------------ + + #{number() => number()} is not compatible with #{number() => atom()} + the default associations are not compatible + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:41:5 │ @@ -33,6 +40,15 @@ Because in the expression's type: Differs from the expected type: atom() , ... } +------------------------------ Detailed message ------------------------------ + + #{number() => 'zero' | number()} is not compatible with #{number() => atom()} + the default associations are not compatible + because + 'zero' | number() is not compatible with atom() + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:56:5 │ @@ -50,6 +66,15 @@ Because in the expression's type: Context expects type: number() , ... } +------------------------------ Detailed message ------------------------------ + + #{one := 'one', zero := number()} is not compatible with #{one => number(), zero := number()} + because + at key `one`: + #{one := 'one', zero := number()} is not compatible with #{one => number(), zero := number()} + because + 'one' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:80:5 │ @@ -83,6 +108,15 @@ Because in the expression's type: Context expects type: n() , ... } +------------------------------ Detailed message ------------------------------ + + #{b() => term()} is not compatible with #{n() => term()} + the default associations are not compatible + because + b() is not compatible with n() + because + boolean() is not compatible with n() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:140:26 │ @@ -100,6 +134,17 @@ Because in the expression's type: Context expects type: n() , ... } +------------------------------ Detailed message ------------------------------ + + #{a := b()} is not compatible with #{a := n()} + because + at key `a`: + #{a := b()} is not compatible with #{a := n()} + because + b() is not compatible with n() + because + boolean() is not compatible with n() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:145:26 │ @@ -117,6 +162,17 @@ Because in the expression's type: Context expects type: n() , ... } +------------------------------ Detailed message ------------------------------ + + #{a := b()} is not compatible with #{a => n()} + because + at key `a`: + #{a := b()} is not compatible with #{a => n()} + because + b() is not compatible with n() + because + boolean() is not compatible with n() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:155:26 │ @@ -133,6 +189,10 @@ Because in the expression's type: Context expects type: #{a := ..., ...} The type of the expression is missing the following required keys: a. +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/t_maps.erl:165:1 │ @@ -156,6 +216,17 @@ Because in the expression's type: Context expects type: atom() , ... } +------------------------------ Detailed message ------------------------------ + + #{a := a(), n() => a()} is not compatible with #{a() => a()} + the default associations are not compatible + because + n() is not compatible with a() + because + number() is not compatible with a() + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:208:5 │ @@ -173,6 +244,17 @@ Because in the expression's type: Context expects type: number() , ... } +------------------------------ Detailed message ------------------------------ + + #{a := a(), n() => a()} is not compatible with #{n() => a()} + because + #{a := a(), n() => a()} is not compatible with #{n() => a()} + key `a` is declared in the former but not in the latter and key `a` isn't compatible with the default association of the latter map + because + 'a' is not compatible with n() + because + 'a' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:216:5 │ @@ -190,6 +272,17 @@ Because in the expression's type: Context expects type: number() , ... } +------------------------------ Detailed message ------------------------------ + + #{a := a(), n() => a()} is not compatible with #{n() => a()} + because + #{a := a(), n() => a()} is not compatible with #{n() => a()} + key `a` is declared in the former but not in the latter and key `a` isn't compatible with the default association of the latter map + because + 'a' is not compatible with n() + because + 'a' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:224:5 │ @@ -207,6 +300,17 @@ Because in the expression's type: Context expects type: number() , ... } +------------------------------ Detailed message ------------------------------ + + #{a => a(), n() => a()} is not compatible with #{n() => a()} + because + #{a => a(), n() => a()} is not compatible with #{n() => a()} + key `a` is declared in the former but not in the latter and key `a` isn't compatible with the default association of the latter map + because + 'a' is not compatible with n() + because + 'a' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:242:5 │ @@ -224,6 +328,17 @@ Because in the expression's type: Context expects type: F1 , ... } +------------------------------ Detailed message ------------------------------ + + #{bar := B1, foo := F1} is not compatible with foo_bar(B1, F1) + because + #{bar := B1, foo := F1} is not compatible with #{bar := F1, foo := B1} + because + at key `bar`: + #{bar := B1, foo := F1} is not compatible with #{bar := F1, foo := B1} + because + B1 is not compatible with F1 + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:254:5 │ @@ -241,6 +356,17 @@ Because in the expression's type: Context expects type: F1 , ... } +------------------------------ Detailed message ------------------------------ + + #{bar := B1, foo := F1} is not compatible with foo_bar_opt(B1, F1) + because + #{bar := B1, foo := F1} is not compatible with #{bar => F1, foo => B1} + because + at key `bar`: + #{bar := B1, foo := F1} is not compatible with #{bar => F1, foo => B1} + because + B1 is not compatible with F1 + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:266:5 │ @@ -259,6 +385,17 @@ Because in the expression's type: Differs from the expected type: K1 | K2 , ... } +------------------------------ Detailed message ------------------------------ + + #{K1 | V2 => V1 | K2} is not compatible with kv(K1 | K2, V1 | V2) + because + #{K1 | V2 => V1 | K2} is not compatible with #{K1 | K2 => V1 | V2} + the default associations are not compatible + because + K1 | V2 is not compatible with K1 | K2 + because + V2 is not compatible with K1 | K2 + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:283:19 │ @@ -275,6 +412,10 @@ Because in the expression's type: Context expects type: #{...} The expected map has no corresponding key for: b. +------------------------------ Detailed message ------------------------------ + +key `b` is declared in the former but not in the latter and the latter map has no default association + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:307:22 │ @@ -292,6 +433,17 @@ Because in the expression's type: Context expects type: number() , n()} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {a(), n()} is not compatible with {n(), a()} + because + a() is not compatible with n() + because + atom() is not compatible with n() + because + atom() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:321:5 │ @@ -309,6 +461,17 @@ Because in the expression's type: Context expects type: number() , n()} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {a(), n()} is not compatible with {n(), a()} + because + a() is not compatible with n() + because + atom() is not compatible with n() + because + atom() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:334:25 │ @@ -326,6 +489,13 @@ Because in the expression's type: Context expects type: K , ... } +------------------------------ Detailed message ------------------------------ + + #{V => K} is not compatible with #{K => V} + the default associations are not compatible + because + V is not compatible with K + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:351:25 │ @@ -345,6 +515,17 @@ Because in the expression's type: Context expects type: atom() , ... } +------------------------------ Detailed message ------------------------------ + + #{a() => n()} | #{n() => a()} | #{id => 'id' | 'no_id'} is not compatible with #{a() | n() => a()} + because + #{a() => n()} is not compatible with #{a() | n() => a()} + the default associations are not compatible + because + n() is not compatible with a() + because + number() is not compatible with a() + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/t_maps.erl:356:1 │ @@ -375,6 +556,15 @@ Because in the expression's type: No candidate of the expression's type matches the expected type. , a()} +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {'a' | 'b', a()} is not compatible with {n(), a()} + because + 'a' | 'b' is not compatible with n() + because + 'a' | 'b' is not compatible with number() + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/t_maps.erl:429:1 │ @@ -421,6 +611,10 @@ Because in the expression's type: Context expects type: #{n := ..., ...} The type of the expression is missing the following required keys: n. +------------------------------ Detailed message ------------------------------ + +key `n` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:536:5 │ @@ -439,6 +633,17 @@ Because in the expression's type: Differs from the expected type: 'b' | 'c' , ... } +------------------------------ Detailed message ------------------------------ + + #{a => 'b' | 'c' | 'a'} is not compatible with #{a => 'b' | 'c'} + because + at key `a`: + #{a => 'b' | 'c' | 'a'} is not compatible with #{a => 'b' | 'c'} + because + 'b' | 'c' | 'a' is not compatible with 'b' | 'c' + because + 'a' is not compatible with 'b' | 'c' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:571:5 │ @@ -455,6 +660,15 @@ Because in the expression's type: Context expects type: #{item_v2 := ..., ...} The type of the expression is missing the following required keys: item_v2. +------------------------------ Detailed message ------------------------------ + + rec_shape() is not compatible with rec_shape_v2() + because + #{item := rec_shape() | 'undefined'} is not compatible with rec_shape_v2() + because + #{item := rec_shape() | 'undefined'} is not compatible with #{item_v2 := rec_shape_v2() | 'undefined'} + key `item_v2` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:629:5 │ @@ -473,6 +687,14 @@ Because in the expression's type: Differs from the expected type: 'a' | #{item := 'a' | gen_shape('a')} , ... } +------------------------------ Detailed message ------------------------------ + + gen_shape('a' | 'b') is not compatible with 'a' | #{item := 'a' | #{item := 'a' | gen_shape('a')}} + because + #{item := 'a' | 'b' | gen_shape('a' | 'b')} is not compatible with 'a' | #{item := 'a' | #{item := 'a' | gen_shape('a')}} + because + #{item := 'a' | 'b' | gen_shape('a' | 'b')} is not compatible with 'a' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:641:5 │ @@ -489,6 +711,15 @@ Because in the expression's type: Context expects type: #{item := ..., ...} The type of the expression is missing the following required keys: item. +------------------------------ Detailed message ------------------------------ + + gen_shape_v2('a') is not compatible with gen_shape('a') + because + #{item_v2 := 'a' | gen_shape_v2('a')} is not compatible with gen_shape('a') + because + #{item_v2 := 'a' | gen_shape_v2('a')} is not compatible with #{item := 'a' | gen_shape('a')} + key `item` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:648:5 │ @@ -505,6 +736,10 @@ Because in the expression's type: Context expects type: #{...} The expected map has no corresponding key for: d. +------------------------------ Detailed message ------------------------------ + +key `d` is declared in the former but not in the latter and the latter map has no default association + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:661:5 │ @@ -522,6 +757,15 @@ Because in the expression's type: Context expects type: 'ka' , ... } +------------------------------ Detailed message ------------------------------ + + #{a => 'va', b => 'vb', c => 'vc', d => 'vd', e => 've'} is not compatible with #{a => 'ka', b => 'kb', c => 'kc'} + because + at key `a`: + #{a => 'va', b => 'vb', c => 'vc', d => 'vd', e => 've'} is not compatible with #{a => 'ka', b => 'kb', c => 'kc'} + because + 'va' is not compatible with 'ka' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:675:5 │ @@ -538,6 +782,10 @@ Because in the expression's type: Context expects type: #{c := ..., ...} The type of the expression is missing the following required keys: c. +------------------------------ Detailed message ------------------------------ + +key `c` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:682:5 │ @@ -554,6 +802,10 @@ Because in the expression's type: Context expects type: #{b := ..., ...} The type of the expression is missing the following required keys: b. +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:689:5 │ @@ -570,6 +822,10 @@ Because in the expression's type: Context expects type: #{b := ..., ...} The type of the expression is missing the following required keys: b. +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:710:5 │ @@ -586,6 +842,10 @@ Because in the expression's type: Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...} The type of the expression is missing the following required keys: k_req3, k_req2, k_req1. +------------------------------ Detailed message ------------------------------ + +keys `k_req1`, `k_req2`, `k_req3` are declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:732:27 │ @@ -602,6 +862,13 @@ Because in the expression's type: Context expects type: #{...} (no default association) The expected map has no default association while the type of the expression has one. +------------------------------ Detailed message ------------------------------ + + #{'a' | 'b' => boolean()} is not compatible with #{a => 'true', b => boolean()} + key a is not present in the former map but is incompatible with its default association + because + boolean() is not compatible with 'true' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:737:27 │ @@ -618,6 +885,10 @@ Because in the expression's type: Context expects type: #{b := ..., ...} The type of the expression is missing the following required keys: b. +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/t_maps.erl:742:27 │ @@ -634,4 +905,11 @@ Because in the expression's type: Context expects type: #{...} (no default association) The expected map has no default association while the type of the expression has one. +------------------------------ Detailed message ------------------------------ + + #{'a' | 'b' => boolean()} is not compatible with #{a => boolean()} + because + #{'a' | 'b' => boolean()} is not compatible with #{a => boolean()} + the latter map has no default association while the first map has one + 44 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/tries.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/tries.pretty index 5f9c8914f4..471b5c8ebe 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/tries.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/tries.pretty @@ -22,6 +22,12 @@ Because in the expression's type: However the following candidate: [] Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + [] | 'error' is not compatible with atom() + because + [] is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/tries.erl:75:16 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/tuple_union.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/tuple_union.pretty index 5b2cca1631..e02af30869 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/tuple_union.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/tuple_union.pretty @@ -16,6 +16,17 @@ Because in the expression's type: Differs from the expected type: 'ok' , 'arg' | 'nil'} +------------------------------ Detailed message ------------------------------ + + t4() is not compatible with t5() + because + {'msg', 'ok' | 'err', 'arg' | 'nil'} is not compatible with t5() + because + {'msg', 'ok' | 'err', 'arg' | 'nil'} is not compatible with {'msg', 'ok', 'arg'} | {'msg', 'err', 'arg'} | {'msg', 'ok', 'nil'} | {'msg', 'err', 'nil'} + because + at tuple index 2: + {'msg', 'ok' | 'err', 'arg' | 'nil'} is not compatible with {'msg', 'ok', 'arg'} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/tuple_union.erl:66:26 │ @@ -36,4 +47,14 @@ Because in the expression's type: No candidate of the expression's type matches the expected type. , tree2()} +------------------------------ Detailed message ------------------------------ + + tree3() is not compatible with tree1() + because + {'leaf', atom()} | {'b1' | 'b2' | 'b3', tree2()} is not compatible with tree1() + because + {'leaf', atom()} | {'b1' | 'b2' | 'b3', tree2()} is not compatible with {'leaf', atom()} | {'b1', tree1()} | {'b2', tree1()} + because + {'b1' | 'b2' | 'b3', tree2()} is not compatible with {'leaf', atom()} | {'b1', tree1()} | {'b2', tree1()} + 2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts.pretty index 069950f003..c5fb63ed41 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts.pretty @@ -22,6 +22,12 @@ Because in the expression's type: However the following candidate: string() Differs from the expected type: binary() +------------------------------ Detailed message ------------------------------ + + string() | binary() is not compatible with binary() + because + string() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/type_asserts.erl:63:26 │ @@ -57,6 +63,17 @@ Because in the expression's type: Context expects type: atom() , atom()} +------------------------------ Detailed message ------------------------------ + + 'false' | {number(), atom()} is not compatible with 'false' | {atom(), number()} + because + {number(), atom()} is not compatible with 'false' | {atom(), number()} + because + at tuple index 1: + {number(), atom()} is not compatible with {atom(), number()} + because + number() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/type_asserts.erl:92:3 │ @@ -74,6 +91,13 @@ Because in the expression's type: Context expects type: number() } +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {'false' | number(), term()} is not compatible with {'false' | number(), number()} + because + term() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/type_asserts.erl:105:39 │ @@ -126,6 +150,17 @@ Because in the expression's type: The expected map has no corresponding key for: kb. , ... } +------------------------------ Detailed message ------------------------------ + + #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kb := 'vb', kc := 'vc'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'}} is not compatible with #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb'}} | #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'}} | #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'}} + because + #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kb := 'vb', kc := 'vc'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'}} is not compatible with #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb'}} + the default associations are not compatible + because + #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kb := 'vb', kc := 'vc'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'} is not compatible with #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb'} + because + #{ka := 'va', kb := 'vb', kc := 'vc'} is not compatible with #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb'} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/type_asserts.erl:129:9 │ @@ -144,6 +179,17 @@ Because in the expression's type: The expected map has no corresponding key for: kb. , ... } +------------------------------ Detailed message ------------------------------ + + #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kb := 'vb', kc := 'vc'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'}} is not compatible with #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb'}} | #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'}} | #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'}} + because + #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kb := 'vb', kc := 'vc'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'}} is not compatible with #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb'}} + the default associations are not compatible + because + #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kb := 'vb', kc := 'vc'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'} is not compatible with #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb'} + because + #{ka := 'va', kb := 'vb', kc := 'vc'} is not compatible with #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb'} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/type_asserts.erl:132:9 │ @@ -162,6 +208,17 @@ Because in the expression's type: The expected map has no corresponding key for: kb. , ... } +------------------------------ Detailed message ------------------------------ + + #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kb := 'vb', kc := 'vc'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'}} is not compatible with #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb'}} | #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'}} | #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'}} + because + #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kb := 'vb', kc := 'vc'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'}} is not compatible with #{dynamic() => #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb'}} + the default associations are not compatible + because + #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kb := 'vb', kc := 'vc'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb', kc := 'vc'} | #{kb := 'vb'} is not compatible with #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb'} + because + #{ka := 'va', kb := 'vb', kc := 'vc'} is not compatible with #{kc := 'vc'} | #{ka := 'va'} | #{ka := 'va', kc := 'vc'} | #{ka := 'va', kb := 'vb'} | #{kb := 'vb'} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/type_asserts.erl:156:24 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual.pretty index b0892292bd..d03afc8cf8 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual.pretty @@ -15,4 +15,11 @@ Because in the expression's type: Context expects type: atom() } +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {binary()} is not compatible with {atom()} + because + binary() is not compatible with atom() + 1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_strict.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_strict.pretty index 034dbd779d..12f1d81948 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_strict.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_strict.pretty @@ -15,4 +15,11 @@ Because in the expression's type: Context expects type: atom() } +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {binary()} is not compatible with {atom()} + because + binary() is not compatible with atom() + 1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater.pretty index 3c6de10f94..ab0cebee3f 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater.pretty @@ -14,6 +14,12 @@ Because in the expression's type: However the following candidate: number() Differs from the expected type: binary() +------------------------------ Detailed message ------------------------------ + + number() | binary() is not compatible with binary() + because + number() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:172:22 │ @@ -30,6 +36,12 @@ Because in the expression's type: However the following candidate: number() Differs from the expected type: binary() +------------------------------ Detailed message ------------------------------ + + number() | binary() is not compatible with binary() + because + number() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:183:7 │ @@ -46,6 +58,12 @@ Because in the expression's type: However the following candidate: number() Differs from the expected type: binary() +------------------------------ Detailed message ------------------------------ + + number() | binary() is not compatible with binary() + because + number() is not compatible with binary() + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ eqwater/src/eqwater.erl:228:1 │ @@ -68,6 +86,12 @@ Because in the expression's type: However the following candidate: #ab_rec{} Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + #ab_rec{} | atom() is not compatible with atom() + because + #ab_rec{} is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:356:16 │ @@ -84,6 +108,12 @@ Because in the expression's type: However the following candidate: #ab_rec{} Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + #ab_rec{} | atom() is not compatible with atom() + because + #ab_rec{} is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:404:25 │ @@ -122,6 +152,12 @@ Because in the expression's type: However the following candidate: atom() Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with number() + because + atom() is not compatible with number() + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ eqwater/src/eqwater.erl:419:1 │ @@ -146,6 +182,12 @@ Because in the expression's type: However the following candidate: atom() Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with number() + because + atom() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:429:25 │ @@ -162,6 +204,12 @@ Because in the expression's type: However the following candidate: atom() Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with number() + because + atom() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:496:3 │ @@ -187,6 +235,13 @@ Because in the expression's type: Context expects type: atom() } +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {'union_field', binary()} is not compatible with {'union_field', atom()} + because + binary() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:559:50 │ @@ -203,6 +258,12 @@ Because in the expression's type: However the following candidate: 'ok' Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | 'ok' is not compatible with number() + because + 'ok' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:590:8 │ @@ -219,6 +280,12 @@ Because in the expression's type: However the following candidate: #c{} Differs from the expected type: #b{} +------------------------------ Detailed message ------------------------------ + + #b{} | #c{} is not compatible with #b{} + because + #c{} is not compatible with #b{} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:631:27 │ @@ -235,6 +302,12 @@ Because in the expression's type: However the following candidate: A Differs from the expected type: B +------------------------------ Detailed message ------------------------------ + + A | B is not compatible with B + because + A is not compatible with B + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:649:17 │ @@ -251,6 +324,12 @@ Because in the expression's type: However the following candidate: fun() Differs from the expected type: {term()} +------------------------------ Detailed message ------------------------------ + + fun() | {term()} is not compatible with {term()} + because + fun() is not compatible with {term()} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:660:17 │ @@ -267,6 +346,12 @@ Because in the expression's type: However the following candidate: tuple() Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + tuple() | atom() is not compatible with atom() + because + tuple() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:839:27 │ @@ -283,6 +368,12 @@ Because in the expression's type: However the following candidate: atom() Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with number() + because + atom() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:997:31 │ @@ -321,6 +412,12 @@ Because in the expression's type: However the following candidate: 'undefined' Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + number() | 'undefined' is not compatible with number() + because + 'undefined' is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:1122:14 │ @@ -340,6 +437,14 @@ Because in the expression's type: Context expects type: atom() ] +------------------------------ Detailed message ------------------------------ + + [[atom()]] | [atom()] is not compatible with [atom()] + because + [[atom()]] is not compatible with [atom()] + because + [atom()] is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:1131:15 │ @@ -359,6 +464,14 @@ Because in the expression's type: Context expects type: atom() ] +------------------------------ Detailed message ------------------------------ + + [[atom()]] | [atom()] is not compatible with [atom()] + because + [[atom()]] is not compatible with [atom()] + because + [atom()] is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:1155:7 │ @@ -375,6 +488,12 @@ Because in the expression's type: However the following candidate: string() Differs from the expected type: binary() +------------------------------ Detailed message ------------------------------ + + binary() | string() is not compatible with binary() + because + string() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:1181:7 │ @@ -391,6 +510,12 @@ Because in the expression's type: However the following candidate: atom() Differs from the expected type: binary() +------------------------------ Detailed message ------------------------------ + + binary() | atom() is not compatible with binary() + because + atom() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:1189:60 │ @@ -407,6 +532,12 @@ Because in the expression's type: However the following candidate: 'ok' Differs from the expected type: binary() +------------------------------ Detailed message ------------------------------ + + 'ok' | binary() is not compatible with binary() + because + 'ok' is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:1194:30 │ @@ -423,6 +554,12 @@ Because in the expression's type: However the following candidate: binary() Differs from the expected type: 'ok' +------------------------------ Detailed message ------------------------------ + + binary() | 'ok' is not compatible with 'ok' + because + binary() is not compatible with 'ok' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:1225:14 │ @@ -439,6 +576,12 @@ Because in the expression's type: However the following candidate: {term(), my_list()} Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + {term(), my_list()} | number() is not compatible with number() + because + {term(), my_list()} is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:1231:31 │ @@ -463,6 +606,12 @@ Because in the expression's type: However the following candidate: 'a' Differs from the expected type: 'b' +------------------------------ Detailed message ------------------------------ + + 'a' | 'b' is not compatible with 'b' + because + 'a' is not compatible with 'b' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:1269:5 │ @@ -475,9 +624,16 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ eqwater/src/eqwater.erl:1286:60 │ 1286 │ negate_atoms_neg(A) when not ((A == a) orelse (A == b)) -> A; - │ ^ A. + │ ^ + │ │ + │ A. Expression has type: 'c' Context expected type: 'a' | 'b' + │ + + 'c' is not compatible with 'a' | 'b' + because + 'c' is not compatible with 'a' error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:1291:43 diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists.pretty index bfb8103b16..c5cd5a3b25 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists.pretty @@ -16,6 +16,14 @@ Because in the expression's type: Differs from the expected type: binary() ] +------------------------------ Detailed message ------------------------------ + + [binary() | atom()] is not compatible with [binary()] + because + binary() | atom() is not compatible with binary() + because + atom() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater_lists.erl:48:23 │ @@ -49,6 +57,12 @@ Because in the expression's type: However the following candidate: [] Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + atom() | [] is not compatible with atom() + because + [] is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater_lists.erl:61:19 │ @@ -65,6 +79,12 @@ Because in the expression's type: However the following candidate: [] Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + atom() | [] is not compatible with atom() + because + [] is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater_lists.erl:69:19 │ @@ -101,6 +121,14 @@ Because in the expression's type: Context expects type: binary() ] +------------------------------ Detailed message ------------------------------ + + [atom()] | [binary()] is not compatible with [binary()] + because + [atom()] is not compatible with [binary()] + because + atom() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater_lists.erl:97:23 │ @@ -127,4 +155,14 @@ Because in the expression's type: Differs from the expected type: atom() ] +------------------------------ Detailed message ------------------------------ + + [atom() | binary()] is not compatible with [atom()] | [binary()] + because + [atom() | binary()] is not compatible with [atom()] + because + atom() | binary() is not compatible with atom() + because + binary() is not compatible with atom() + 8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps.pretty index b5f637ead3..847411f766 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps.pretty @@ -14,6 +14,10 @@ Because in the expression's type: Context expects type: #{b := ..., ...} The type of the expression is missing the following required keys: b. +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater_maps.erl:27:22 │ @@ -30,6 +34,10 @@ Because in the expression's type: Context expects type: #{b := ..., ...} The type of the expression is missing the following required keys: b. +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater_maps.erl:36:22 │ @@ -46,6 +54,12 @@ Because in the expression's type: However the following candidate: #{} Differs from the expected type: 'ok' +------------------------------ Detailed message ------------------------------ + + #{} | 'ok' is not compatible with 'ok' + because + #{} is not compatible with 'ok' + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater_maps.erl:42:22 │ @@ -62,6 +76,10 @@ Because in the expression's type: Context expects type: #{b := ..., ...} The type of the expression is missing the following required keys: b. +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater_maps.erl:55:34 │ @@ -70,20 +88,4 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: #{a := dynamic(), dynamic() => dynamic()} Context expected type: 'err' -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_maps.erl:70:29 - │ -70 │ (_, #{a := V}) -> is_ok(V) - │ ^ - │ │ - │ V. -Expression has type: 'ok' | 'err' -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'ok' - However the following candidate: 'err' - Differs from the expected type: 'ok' - -6 ERRORS +5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records.pretty index 245813d1e8..5a01001d2e 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records.pretty @@ -14,6 +14,14 @@ Because in the expression's type: However the following candidate: #rec1{} Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + user() is not compatible with number() + because + #rec1{} | number() is not compatible with number() + because + #rec1{} is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater_records.erl:40:16 │ @@ -30,6 +38,14 @@ Because in the expression's type: However the following candidate: #rec1{} Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + user() is not compatible with number() + because + #rec1{} | number() is not compatible with number() + because + #rec1{} is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater_records.erl:47:11 │ @@ -46,6 +62,14 @@ Because in the expression's type: However the following candidate: #rec1{} Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + user() is not compatible with number() + because + #rec1{} | number() is not compatible with number() + because + #rec1{} is not compatible with number() + error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ eqwater/src/eqwater_records.erl:104:1 │ @@ -72,6 +96,15 @@ Because in the expression's type: Context expects type: #rec1{} , #rec1{}} +------------------------------ Detailed message ------------------------------ + + {#rec1{}, #rec2{}} | {#rec2{}, #rec1{}} is not compatible with {#rec1{}, #rec2{}} + because + at tuple index 1: + {#rec2{}, #rec1{}} is not compatible with {#rec1{}, #rec2{}} + because + #rec2{} is not compatible with #rec1{} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater_records.erl:115:25 │ @@ -91,4 +124,13 @@ Because in the expression's type: Context expects type: #rec1{} , #rec1{}} +------------------------------ Detailed message ------------------------------ + + {#rec1{}, #rec2{}} | {#rec2{}, #rec1{}} is not compatible with {#rec1{}, #rec2{}} + because + at tuple index 1: + {#rec2{}, #rec1{}} is not compatible with {#rec1{}, #rec2{}} + because + #rec2{} is not compatible with #rec1{} + 6 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound.pretty index 332e999cda..4ee35cc78d 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound.pretty @@ -14,6 +14,14 @@ Because in the expression's type: However the following candidate: binary() Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + ab() is not compatible with atom() + because + atom() | binary() is not compatible with atom() + because + binary() is not compatible with atom() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater_sound.erl:50:14 │ @@ -30,6 +38,14 @@ Because in the expression's type: However the following candidate: atom() Differs from the expected type: binary() +------------------------------ Detailed message ------------------------------ + + ab() is not compatible with binary() + because + atom() | binary() is not compatible with binary() + because + atom() is not compatible with binary() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater_sound.erl:53:28 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement.pretty index c0c48c5e3c..8b70994f10 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement.pretty @@ -14,6 +14,12 @@ Because in the expression's type: However the following candidate: binary() Differs from the expected type: number() +------------------------------ Detailed message ------------------------------ + + binary() | number() is not compatible with number() + because + binary() is not compatible with number() + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/unlimited_refinement.erl:94:14 │ diff --git a/crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance.pretty b/crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance.pretty index 554970c163..803ac23f35 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance.pretty @@ -416,6 +416,12 @@ Because in the expression's type: Context expects type: atom() ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [atom()] + because + term() is not compatible with atom() + error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) ┌─ fault_tolerance/src/fault_tolerance.erl:169:8 │ @@ -666,6 +672,12 @@ Because in the expression's type: However the following candidate: [] Differs from the expected type: atom() +------------------------------ Detailed message ------------------------------ + + dynamic() | [] is not compatible with atom() + because + [] is not compatible with atom() + error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) ┌─ fault_tolerance/src/fault_tolerance.erl:254:11 │ diff --git a/crates/elp/src/resources/test/glean_help.stdout b/crates/elp/src/resources/test/glean_help.stdout index c4e938e143..bdde2ec540 100644 --- a/crates/elp/src/resources/test/glean_help.stdout +++ b/crates/elp/src/resources/test/glean_help.stdout @@ -1,4 +1,4 @@ -Usage: [--project PROJECT] [--module MODULE] [--to TO] [--v2] [--pretty] [--multi] +Usage: [--project PROJECT] [--module MODULE] [--to TO] [--v2] [--pretty] [--multi] [--prefix ARG] Available options: --project Path to directory with project, or to a JSON file (defaults to `.`) @@ -7,4 +7,5 @@ Available options: --v2 Produce glean db with macros, types, xrefs. Incompatible with previous --pretty Pretty print --multi Output each fact separately + --prefix Optional prefix to prepend to each fact -h, --help Prints help information diff --git a/crates/elp/src/resources/test/help.stdout b/crates/elp/src/resources/test/help.stdout index 1510d5bddb..acc7ae286d 100644 --- a/crates/elp/src/resources/test/help.stdout +++ b/crates/elp/src/resources/test/help.stdout @@ -1,4 +1,4 @@ -Usage: [--log-file LOG_FILE] [--erl ERL] [--escript ESCRIPT] [--no-log-buffering] [--no-buck-generated] [--buck-quick-start] [[--color WHEN]] [COMMAND ...] +Usage: [--log-file LOG_FILE] [--erl ERL] [--escript ESCRIPT] [--no-log-buffering] [--no-buck-generated] [--buck-quick-start] [COMMAND ...] Available options: --log-file @@ -7,7 +7,6 @@ Available options: --no-log-buffering --no-buck-generated When using buck, do not invoke a build step for generated files. --buck-quick-start Use buck2 targets for first stage project loading - --color Use color in output; WHEN is 'always', 'never', or 'auto' -h, --help Prints help information Available commands: @@ -21,7 +20,6 @@ Available commands: dialyze-all Run Dialyzer on the whole project by shelling out to a `dialyzer-run` tool on the path to do the legwork. lint Parse files in project and emit diagnostics, optionally apply fixes. ssr Run SSR (Structural Search and Replace) pattern matching on project files. - search Alias for 'ssr': Run SSR (Structural Search and Replace) pattern matching on project files. parse-all Dump ast for all files in a project for specified rebar.config file parse-elp Tree-sitter parse all files in a project for specified rebar.config file explain Explain a diagnostic code diff --git a/crates/elp/src/resources/test/hierarchical_config/basic.stdout b/crates/elp/src/resources/test/hierarchical_config/basic.stdout deleted file mode 100644 index de8cb63308..0000000000 --- a/crates/elp/src/resources/test/hierarchical_config/basic.stdout +++ /dev/null @@ -1,5 +0,0 @@ -Diagnostics reported: -Reporting all diagnostics codes -app_a/src/app_a.erl:6:1-6:5::[Warning] [L1230] function main/0 is unused -app_b/src/app_b.erl:4:9-4:16::[Warning] [W0002] Unused macro (MACRO_B) -app_b/src/app_b.erl:6:1-6:5::[Warning] [L1230] function main/0 is unused diff --git a/crates/elp/src/resources/test/lint_help.stdout b/crates/elp/src/resources/test/lint_help.stdout index bffdd1fe91..8d03db6ee3 100644 --- a/crates/elp/src/resources/test/lint_help.stdout +++ b/crates/elp/src/resources/test/lint_help.stdout @@ -1,4 +1,4 @@ -Usage: [--project PROJECT] [--module MODULE] [--app APP] [--file FILE] [--rebar] [--as PROFILE] [--include-generated] [--include-tests] [--no-diags] [[--format FORMAT]] [--include-erlc-diagnostics] [--include-ct-diagnostics] [--include-edoc-diagnostics] [--include-eqwalizer-diagnostics] [--include-suppressed] [--use-cli-severity] [--diagnostic-ignore CODE] [--diagnostic-filter CODE] [--experimental] [--read-config] [--config-file CONFIG_FILE] [--apply-fix] [--ignore-fix-only] [--in-place] [--to TO] [--recursive] [--with-check] [--check-eqwalize-all] [--one-shot] [--report-system-stats] [--no-stream] ... +Usage: [--project PROJECT] [--module MODULE] [--app APP] [--file FILE] [--rebar] [--as PROFILE] [--include-generated] [--include-tests] [--no-diags] [[--format FORMAT]] [--prefix ARG] [--include-erlc-diagnostics] [--include-ct-diagnostics] [--include-edoc-diagnostics] [--include-eqwalizer-diagnostics] [--include-suppressed] [--use-cli-severity] [--diagnostic-ignore CODE] [--diagnostic-filter CODE] [--experimental] [--read-config] [--config-file CONFIG_FILE] [--apply-fix] [--ignore-fix-only] [--in-place] [--to TO] [--recursive] [--with-check] [--check-eqwalize-all] [--one-shot] [--report-system-stats] ... Available positional items: Rest of args are space separated list of apps to ignore @@ -14,6 +14,7 @@ Available options: --include-tests Also generate diagnostics for test files --no-diags Do not print the full diagnostics for a file, just the count --format Show diagnostics in JSON format + --prefix Optional prefix to prepend to each diagnostic file path. Only used when --format=json is set --include-erlc-diagnostics Include diagnostics produced by erlc --include-ct-diagnostics Include Common Test diagnostics --include-edoc-diagnostics Include EDoc diagnostics @@ -37,5 +38,4 @@ Available options: --one-shot Apply to all matching diagnostic occurrences at once, rather than one at a time. --report-system-stats Report system memory usage and other statistics - --no-stream Disable streaming of diagnostics when applying fixes (collect all before printing) -h, --help Prints help information diff --git a/crates/elp/src/resources/test/linter/custom_function_matches.stdout b/crates/elp/src/resources/test/linter/custom_function_matches.stdout index c552fa7dfa..08c0321771 100644 --- a/crates/elp/src/resources/test/linter/custom_function_matches.stdout +++ b/crates/elp/src/resources/test/linter/custom_function_matches.stdout @@ -1,4 +1,5 @@ Reporting all diagnostics codes module specified: custom_function_matches -Diagnostics reported: -app_a/src/custom_function_matches.erl:14:5-14:26::[Warning] [W0017] Function 'not_excluded:function/0' is undefined. +Diagnostics reported in 1 modules: + custom_function_matches: 1 + 13:4-13:25::[Warning] [W0017] Function 'not_excluded:function/0' is undefined. diff --git a/crates/elp/src/resources/test/linter/elp_lint_ct.stdout b/crates/elp/src/resources/test/linter/elp_lint_ct.stdout index 471efc7900..db2b6e3afa 100644 --- a/crates/elp/src/resources/test/linter/elp_lint_ct.stdout +++ b/crates/elp/src/resources/test/linter/elp_lint_ct.stdout @@ -1,2 +1,3 @@ -Diagnostics reported: -app_a/test/app_a_unreachable_test_SUITE.erl:8:1-8:2::[Error] [W0008] Unreachable test (b/1) \ No newline at end of file +Diagnostics reported in 1 modules: + app_a_unreachable_test_SUITE: 1 + 7:0-7:1::[Error] [W0008] Unreachable test (b/1) diff --git a/crates/elp/src/resources/test/linter/elp_lint_edoc.stdout b/crates/elp/src/resources/test/linter/elp_lint_edoc.stdout index a667df3930..022b3b8972 100644 --- a/crates/elp/src/resources/test/linter/elp_lint_edoc.stdout +++ b/crates/elp/src/resources/test/linter/elp_lint_edoc.stdout @@ -1,2 +1,3 @@ -Diagnostics reported: -app_a/src/app_a_edoc.erl:5:1-6:1::[Warning] [O0039] tag @docc not recognized. \ No newline at end of file +Diagnostics reported in 1 modules: + app_a_edoc: 1 + 4:0-5:0::[Warning] [O0039] tag @docc not recognized. diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint2.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint2.stdout index 47dc6d4a5e..b0cc8a1337 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint2.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint2.stdout @@ -1,4 +1,4 @@ module specified: app_a -Diagnostics reported: -app_a/src/app_a.erl:9:1-9:5::[Error] [P1700] head mismatch 'fooX' vs 'food' - 7:1-7:5: Mismatched clause name +Diagnostics reported in 1 modules: + app_a: 1 + 8:0-8:4::[Error] [P1700] head mismatch 'fooX' vs 'food' diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_adhoc_output.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_adhoc_output.stdout index 0d0d56491d..5adeaace66 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_adhoc_output.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_adhoc_output.stdout @@ -1,12 +1,13 @@ module specified: app_b -Diagnostics reported: -app_b/src/app_b.erl:8:5-8:36::[WeakWarning] [ad-hoc: application:get_env/2] 'application:get_env/2' called -app_b/src/app_b.erl:5:5-5:35::[WeakWarning] [ad-hoc: application:get_env/2] 'application:get_env/2' called +Diagnostics reported in 1 modules: + app_b: 2 + 7:4-7:35::[WeakWarning] [ad-hoc: application:get_env/2] 'application:get_env/2' called + 4:4-4:34::[WeakWarning] [ad-hoc: application:get_env/2] 'application:get_env/2' called --------------------------------------------- Applying fixes in module 'app_b' for - 8:5-8:36::[WeakWarning] [ad-hoc: application:get_env/2] 'application:get_env/2' called - 5:5-5:35::[WeakWarning] [ad-hoc: application:get_env/2] 'application:get_env/2' called + 7:4-7:35::[WeakWarning] [ad-hoc: application:get_env/2] 'application:get_env/2' called + 4:4-4:34::[WeakWarning] [ad-hoc: application:get_env/2] 'application:get_env/2' called @@ -1,8 +1,8 @@ -module(app_b). -export([application_env_error/0, application_env_no_error/0]). diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_app.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_app.stdout index edd7c5cf1c..a5c27f4367 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_app.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_app.stdout @@ -1,3 +1,3 @@ -Diagnostics reported: -app_a/src/app_a.erl:9:1-9:5::[Error] [P1700] head mismatch 'fooX' vs 'food' - 7:1-7:5: Mismatched clause name +Diagnostics reported in 1 modules: + app_a: 1 + 8:0-8:4::[Error] [P1700] head mismatch 'fooX' vs 'food' diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_config_output.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_config_output.stdout index 6daa076a31..8b6d166b16 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_config_output.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_config_output.stdout @@ -1,10 +1,13 @@ - 7:1-7:5: Mismatched clause name -Diagnostics reported: -app_a/src/app_a.erl:5:5-5:35::[Warning] [W0011] module `app_a` belongs to app `app_a`, but reads env for `misc` -app_a/src/app_a.erl:9:1-9:5::[Error] [P1700] head mismatch 'fooX' vs 'food' -app_a/src/app_a.erl:9:6-9:7::[Warning] [W0010] this variable is unused -app_a/src/app_a_unused_param.erl:5:5-5:6::[Warning] [L1268] variable 'X' is unused -app_a/src/app_a_unused_param.erl:5:5-5:6::[Warning] [W0010] this variable is unused -app_b/src/app_b.erl:5:5-5:35::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` -app_b/src/app_b_unused_param.erl:5:5-5:6::[Warning] [L1268] variable 'X' is unused -app_b/src/app_b_unused_param.erl:5:5-5:6::[Warning] [W0010] this variable is unused \ No newline at end of file +Diagnostics reported in 4 modules: + app_a: 3 + 8:5-8:6::[Warning] [W0010] this variable is unused + 4:4-4:34::[Warning] [W0011] module `app_a` belongs to app `app_a`, but reads env for `misc` + 8:0-8:4::[Error] [P1700] head mismatch 'fooX' vs 'food' + app_a_unused_param: 2 + 4:4-4:5::[Warning] [W0010] this variable is unused + 4:4-4:5::[Warning] [L1268] variable 'X' is unused + app_b: 1 + 4:4-4:34::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` + app_b_unused_param: 2 + 4:4-4:5::[Warning] [W0010] this variable is unused + 4:4-4:5::[Warning] [L1268] variable 'X' is unused diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_custom_config_output.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_custom_config_output.stdout index 90ccbcb5c0..50166d0687 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_custom_config_output.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_custom_config_output.stdout @@ -1,5 +1,9 @@ -Diagnostics reported: -app_a/src/app_a.erl:5:5-5:35::[Warning] [W0011] module `app_a` belongs to app `app_a`, but reads env for `misc` -app_a/src/app_a_unused_param.erl:5:5-5:6::[Warning] [L1268] variable 'X' is unused -app_b/src/app_b.erl:5:5-5:35::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` -app_b/src/app_b_unused_param.erl:5:5-5:6::[Warning] [L1268] variable 'X' is unused \ No newline at end of file +Diagnostics reported in 4 modules: + app_a: 1 + 4:4-4:34::[Warning] [W0011] module `app_a` belongs to app `app_a`, but reads env for `misc` + app_a_unused_param: 1 + 4:4-4:5::[Warning] [L1268] variable 'X' is unused + app_b: 1 + 4:4-4:34::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` + app_b_unused_param: 1 + 4:4-4:5::[Warning] [L1268] variable 'X' is unused diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_erlang_service.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_erlang_service.stdout index eeb41e5adf..071903fae8 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_erlang_service.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_erlang_service.stdout @@ -1,3 +1,4 @@ module specified: expression_updates_literal -Diagnostics reported: -app_a/src/expression_updates_literal.erl:8:7-9:16::[Warning] [L1318] expression updates a literal +Diagnostics reported in 1 modules: + expression_updates_literal: 1 + 7:6-8:15::[Warning] [L1318] expression updates a literal diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_explicit_enable_output.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_explicit_enable_output.stdout index 1d7771b3b9..cf937cab11 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_explicit_enable_output.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_explicit_enable_output.stdout @@ -1,12 +1,19 @@ -Diagnostics reported: -app_a/src/app_a.erl:1:1-1:1::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. -app_a/src/app_a.erl:5:5-5:35::[Warning] [W0011] module `app_a` belongs to app `app_a`, but reads env for `misc` -app_a/src/app_a_edoc.erl:1:1-1:1::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. -app_a/src/app_a_ssr.erl:1:1-1:1::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. -app_a/src/app_a_unused_param.erl:1:1-1:1::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. -app_a/src/app_a_unused_param.erl:5:5-5:6::[Warning] [L1268] variable 'X' is unused -app_a/src/spelling.erl:1:1-1:1::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. -app_b/src/app_b.erl:1:1-1:1::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. -app_b/src/app_b.erl:5:5-5:35::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` -app_b/src/app_b_unused_param.erl:1:1-1:1::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. -app_b/src/app_b_unused_param.erl:5:5-5:6::[Warning] [L1268] variable 'X' is unused \ No newline at end of file +Diagnostics reported in 7 modules: + app_a: 2 + 4:4-4:34::[Warning] [W0011] module `app_a` belongs to app `app_a`, but reads env for `misc` + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + app_a_edoc: 1 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + app_a_ssr: 1 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + app_a_unused_param: 2 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 4:4-4:5::[Warning] [L1268] variable 'X' is unused + app_b: 2 + 4:4-4:34::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + app_b_unused_param: 2 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 4:4-4:5::[Warning] [L1268] variable 'X' is unused + spelling: 1 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_fix_ignore.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_fix_ignore.stdout index 3e4a25f329..4c42e88eec 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_fix_ignore.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_fix_ignore.stdout @@ -1,10 +1,11 @@ module specified: app_b -Diagnostics reported: -app_b/src/app_b.erl:5:5-5:35::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` +Diagnostics reported in 1 modules: + app_b: 1 + 4:4-4:34::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` --------------------------------------------- Applying fix in module 'app_b' for - 5:5-5:35::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` + 4:4-4:34::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` @@ -1,7 +1,8 @@ -module(app_b). -export([application_env_error/0, application_env_no_error/0]). diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_fixme_spelling.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_fixme_spelling.stdout index 2cec0678d2..fcba7f3aee 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_fixme_spelling.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_fixme_spelling.stdout @@ -1,10 +1,11 @@ module specified: spelling -Diagnostics reported: -app_a/src/spelling.erl:2:2-2:10::[Error] [W0013] misspelled attribute, saw 'dyalizer' but expected 'dialyzer' +Diagnostics reported in 1 modules: + spelling: 1 + 1:1-1:9::[Error] [W0013] misspelled attribute, saw 'dyalizer' but expected 'dialyzer' --------------------------------------------- Applying fix in module 'spelling' for - 2:2-2:10::[Error] [W0013] misspelled attribute, saw 'dyalizer' but expected 'dialyzer' + 1:1-1:9::[Error] [W0013] misspelled attribute, saw 'dyalizer' but expected 'dialyzer' @@ -1,4 +1,5 @@ -module(spelling). +% elp:fixme W0013 (misspelled_attribute) diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_ignore.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_ignore.stdout index 1e7e049554..07a81b80e2 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_ignore.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_ignore.stdout @@ -1,6 +1,9 @@ -Diagnostics reported: -app_a/src/app_a.erl:9:6-9:7::[Warning] [W0010] this variable is unused -app_a/src/app_a_unused_param.erl:5:5-5:6::[Warning] [L1268] variable 'X' is unused -app_a/src/app_a_unused_param.erl:5:5-5:6::[Warning] [W0010] this variable is unused -app_b/src/app_b_unused_param.erl:5:5-5:6::[Warning] [L1268] variable 'X' is unused -app_b/src/app_b_unused_param.erl:5:5-5:6::[Warning] [W0010] this variable is unused \ No newline at end of file +Diagnostics reported in 3 modules: + app_a: 1 + 8:5-8:6::[Warning] [W0010] this variable is unused + app_a_unused_param: 2 + 4:4-4:5::[Warning] [W0010] this variable is unused + 4:4-4:5::[Warning] [L1268] variable 'X' is unused + app_b_unused_param: 2 + 4:4-4:5::[Warning] [W0010] this variable is unused + 4:4-4:5::[Warning] [L1268] variable 'X' is unused diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_ignore_apps.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_ignore_apps.stdout index 4b8d3cc466..e7a35d0262 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_ignore_apps.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_ignore_apps.stdout @@ -1,2 +1,3 @@ -Diagnostics reported: -app_b/src/app_b_unused_param.erl:5:5-5:6::[Warning] [W0010] this variable is unused +Diagnostics reported in 1 modules: + app_b_unused_param: 1 + 4:4-4:5::[Warning] [W0010] this variable is unused diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_ignore_apps_b.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_ignore_apps_b.stdout index 5a42009118..00d4e2355e 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_ignore_apps_b.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_ignore_apps_b.stdout @@ -1,3 +1,5 @@ -Diagnostics reported: -app_a/src/app_a.erl:9:6-9:7::[Warning] [W0010] this variable is unused -app_a/src/app_a_unused_param.erl:5:5-5:6::[Warning] [W0010] this variable is unused +Diagnostics reported in 2 modules: + app_a: 1 + 8:5-8:6::[Warning] [W0010] this variable is unused + app_a_unused_param: 1 + 4:4-4:5::[Warning] [W0010] this variable is unused diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_json_output.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_json_output.stdout index 5d6b5e78bc..4fb3478926 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_json_output.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_json_output.stdout @@ -1,3 +1,3 @@ {"path":"app_a/src/app_a.erl","line":9,"char":6,"code":"ELP","severity":"warning","name":"W0010 (unused_function_arg)","original":null,"replacement":null,"description":"this variable is unused\n\nFor more information see: /erlang-error-index/w/W0010","docPath":"website/docs/erlang-error-index/w/W0010.md"} {"path":"app_a/src/app_a_unused_param.erl","line":5,"char":5,"code":"ELP","severity":"warning","name":"W0010 (unused_function_arg)","original":null,"replacement":null,"description":"this variable is unused\n\nFor more information see: /erlang-error-index/w/W0010","docPath":"website/docs/erlang-error-index/w/W0010.md"} -{"path":"app_b/src/app_b_unused_param.erl","line":5,"char":5,"code":"ELP","severity":"warning","name":"W0010 (unused_function_arg)","original":null,"replacement":null,"description":"this variable is unused\n\nFor more information see: /erlang-error-index/w/W0010","docPath":"website/docs/erlang-error-index/w/W0010.md"} \ No newline at end of file +{"path":"app_b/src/app_b_unused_param.erl","line":5,"char":5,"code":"ELP","severity":"warning","name":"W0010 (unused_function_arg)","original":null,"replacement":null,"description":"this variable is unused\n\nFor more information see: /erlang-error-index/w/W0010","docPath":"website/docs/erlang-error-index/w/W0010.md"} diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_json_output_prefix.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_json_output_prefix.stdout new file mode 100644 index 0000000000..7389cc926a --- /dev/null +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_json_output_prefix.stdout @@ -0,0 +1,3 @@ +{"path":"my/prefix/app_a/src/app_a.erl","line":9,"char":6,"code":"ELP","severity":"warning","name":"W0010 (unused_function_arg)","original":null,"replacement":null,"description":"this variable is unused\n\nFor more information see: /erlang-error-index/w/W0010","docPath":"website/docs/erlang-error-index/w/W0010.md"} +{"path":"my/prefix/app_a/src/app_a_unused_param.erl","line":5,"char":5,"code":"ELP","severity":"warning","name":"W0010 (unused_function_arg)","original":null,"replacement":null,"description":"this variable is unused\n\nFor more information see: /erlang-error-index/w/W0010","docPath":"website/docs/erlang-error-index/w/W0010.md"} +{"path":"my/prefix/app_b/src/app_b_unused_param.erl","line":5,"char":5,"code":"ELP","severity":"warning","name":"W0010 (unused_function_arg)","original":null,"replacement":null,"description":"this variable is unused\n\nFor more information see: /erlang-error-index/w/W0010","docPath":"website/docs/erlang-error-index/w/W0010.md"} diff --git a/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_json_output.stdout b/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_json_output.stdout index 7b6a1e705c..8b664bb080 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_json_output.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_json_output.stdout @@ -1,18 +1,30 @@ -{"path":"app_a/src/app_a.erl","line":12,"char":1,"code":"ELP","severity":"warning","name":"L1230 (L1230)","original":null,"replacement":null,"description":"function bar/0 is unused\n\nFor more information see: /erlang-error-index/l/L1230","docPath":null} -{"path":"app_a/src/app_a.erl","line":13,"char":5,"code":"ELP","severity":"warning","name":"W0026 (unexported_function)","original":null,"replacement":null,"description":"Function 'app_a:baz/2' is not exported.\n\nFor more information see: /erlang-error-index/w/W0026","docPath":"website/docs/erlang-error-index/w/W0026.md"} -{"path":"app_a/src/app_a.erl","line":16,"char":1,"code":"ELP","severity":"warning","name":"L1230 (L1230)","original":null,"replacement":null,"description":"function baz/2 is unused\n\nFor more information see: /erlang-error-index/l/L1230","docPath":null} -{"path":"app_a/src/app_a.erl","line":20,"char":1,"code":"ELP","severity":"warning","name":"L1230 (L1230)","original":null,"replacement":null,"description":"function bat/2 is unused\n\nFor more information see: /erlang-error-index/l/L1230","docPath":null} {"path":"app_a/src/app_a.erl","line":5,"char":5,"code":"ELP","severity":"warning","name":"W0011 (application_get_env)","original":null,"replacement":null,"description":"module `app_a` belongs to app `app_a`, but reads env for `misc`\n\nFor more information see: /erlang-error-index/w/W0011","docPath":"website/docs/erlang-error-index/w/W0011.md"} -{"path":"app_a/src/app_a.erl","line":8,"char":7,"code":"ELP","severity":"warning","name":"W0018 (unexpected_semi_or_dot)","original":null,"replacement":null,"description":"Unexpected ';'\n\nFor more information see: /erlang-error-index/w/W0018","docPath":"website/docs/erlang-error-index/w/W0018.md"} +{"path":"app_a/src/app_a.erl","line":1,"char":1,"code":"ELP","severity":"error","name":"W0012 (compile-warn-missing-spec)","original":null,"replacement":null,"description":"Please add \"-compile(warn_missing_spec_all).\" to the module. If exported functions are not all specced, they need to be specced.\n\nFor more information see: /erlang-error-index/w/W0012","docPath":"website/docs/erlang-error-index/w/W0012.md"} {"path":"app_a/src/app_a.erl","line":9,"char":1,"code":"ELP","severity":"error","name":"P1700 (head_mismatch)","original":null,"replacement":null,"description":"head mismatch 'fooX' vs 'food'\n\nFor more information see: /erlang-error-index/p/P1700","docPath":null} -{"path":"app_a/src/app_a_ssr.erl","line":7,"char":6,"code":"ELP","severity":"warning","name":"W0060 (bound_var_in_lhs)","original":null,"replacement":null,"description":"Match on a bound variable\n\nFor more information see: /erlang-error-index/w/W0060","docPath":"website/docs/erlang-error-index/w/W0060.md"} -{"path":"app_a/src/app_a_ssr.erl","line":8,"char":6,"code":"ELP","severity":"warning","name":"W0060 (bound_var_in_lhs)","original":null,"replacement":null,"description":"Match on a bound variable\n\nFor more information see: /erlang-error-index/w/W0060","docPath":"website/docs/erlang-error-index/w/W0060.md"} +{"path":"app_a/src/app_a.erl","line":8,"char":7,"code":"ELP","severity":"warning","name":"W0018 (unexpected_semi_or_dot)","original":null,"replacement":null,"description":"Unexpected ';'\n\nFor more information see: /erlang-error-index/w/W0018","docPath":"website/docs/erlang-error-index/w/W0018.md"} +{"path":"app_a/src/app_a.erl","line":1,"char":9,"code":"ELP","severity":"disabled","name":"W0046 (undocumented_module)","original":null,"replacement":null,"description":"The module is not documented.\n\nFor more information see: /erlang-error-index/w/W0046","docPath":"website/docs/erlang-error-index/w/W0046.md"} +{"path":"app_a/src/app_a.erl","line":13,"char":5,"code":"ELP","severity":"warning","name":"W0026 (unexported_function)","original":null,"replacement":null,"description":"Function 'app_a:baz/2' is not exported.\n\nFor more information see: /erlang-error-index/w/W0026","docPath":"website/docs/erlang-error-index/w/W0026.md"} +{"path":"app_a/src/app_a.erl","line":12,"char":1,"code":"ELP","severity":"warning","name":"L1230 (L1230)","original":null,"replacement":null,"description":"function bar/0 is unused\n\nFor more information see: /erlang-error-index/l/L1230","docPath":null} +{"path":"app_a/src/app_a.erl","line":16,"char":1,"code":"ELP","severity":"warning","name":"L1230 (L1230)","original":null,"replacement":null,"description":"function baz/2 is unused\n\nFor more information see: /erlang-error-index/l/L1230","docPath":null} +{"path":"app_a/src/app_a_edoc.erl","line":1,"char":1,"code":"ELP","severity":"error","name":"W0012 (compile-warn-missing-spec)","original":null,"replacement":null,"description":"Please add \"-compile(warn_missing_spec_all).\" to the module. If exported functions are not all specced, they need to be specced.\n\nFor more information see: /erlang-error-index/w/W0012","docPath":"website/docs/erlang-error-index/w/W0012.md"} +{"path":"app_a/src/app_a_edoc.erl","line":1,"char":9,"code":"ELP","severity":"disabled","name":"W0046 (undocumented_module)","original":null,"replacement":null,"description":"The module is not documented.\n\nFor more information see: /erlang-error-index/w/W0046","docPath":"website/docs/erlang-error-index/w/W0046.md"} +{"path":"app_a/src/app_a_ssr.erl","line":1,"char":1,"code":"ELP","severity":"error","name":"W0012 (compile-warn-missing-spec)","original":null,"replacement":null,"description":"Please add \"-compile(warn_missing_spec_all).\" to the module. If exported functions are not all specced, they need to be specced.\n\nFor more information see: /erlang-error-index/w/W0012","docPath":"website/docs/erlang-error-index/w/W0012.md"} +{"path":"app_a/src/app_a_ssr.erl","line":1,"char":9,"code":"ELP","severity":"disabled","name":"W0046 (undocumented_module)","original":null,"replacement":null,"description":"The module is not documented.\n\nFor more information see: /erlang-error-index/w/W0046","docPath":"website/docs/erlang-error-index/w/W0046.md"} +{"path":"app_a/src/app_a_unused_param.erl","line":1,"char":1,"code":"ELP","severity":"error","name":"W0012 (compile-warn-missing-spec)","original":null,"replacement":null,"description":"Please add \"-compile(warn_missing_spec_all).\" to the module. If exported functions are not all specced, they need to be specced.\n\nFor more information see: /erlang-error-index/w/W0012","docPath":"website/docs/erlang-error-index/w/W0012.md"} +{"path":"app_a/src/app_a_unused_param.erl","line":1,"char":9,"code":"ELP","severity":"disabled","name":"W0046 (undocumented_module)","original":null,"replacement":null,"description":"The module is not documented.\n\nFor more information see: /erlang-error-index/w/W0046","docPath":"website/docs/erlang-error-index/w/W0046.md"} {"path":"app_a/src/app_a_unused_param.erl","line":5,"char":5,"code":"ELP","severity":"warning","name":"L1268 (L1268)","original":null,"replacement":null,"description":"variable 'X' is unused\n\nFor more information see: /erlang-error-index/l/L1268","docPath":null} +{"path":"app_b/src/app_b.erl","line":5,"char":5,"code":"ELP","severity":"warning","name":"W0011 (application_get_env)","original":null,"replacement":null,"description":"module `app_b` belongs to app `app_b`, but reads env for `misc`\n\nFor more information see: /erlang-error-index/w/W0011","docPath":"website/docs/erlang-error-index/w/W0011.md"} +{"path":"app_b/src/app_b.erl","line":1,"char":1,"code":"ELP","severity":"error","name":"W0012 (compile-warn-missing-spec)","original":null,"replacement":null,"description":"Please add \"-compile(warn_missing_spec_all).\" to the module. If exported functions are not all specced, they need to be specced.\n\nFor more information see: /erlang-error-index/w/W0012","docPath":"website/docs/erlang-error-index/w/W0012.md"} +{"path":"app_b/src/app_b.erl","line":1,"char":9,"code":"ELP","severity":"disabled","name":"W0046 (undocumented_module)","original":null,"replacement":null,"description":"The module is not documented.\n\nFor more information see: /erlang-error-index/w/W0046","docPath":"website/docs/erlang-error-index/w/W0046.md"} +{"path":"app_b/src/app_b_unused_param.erl","line":1,"char":1,"code":"ELP","severity":"error","name":"W0012 (compile-warn-missing-spec)","original":null,"replacement":null,"description":"Please add \"-compile(warn_missing_spec_all).\" to the module. If exported functions are not all specced, they need to be specced.\n\nFor more information see: /erlang-error-index/w/W0012","docPath":"website/docs/erlang-error-index/w/W0012.md"} +{"path":"app_b/src/app_b_unused_param.erl","line":1,"char":9,"code":"ELP","severity":"disabled","name":"W0046 (undocumented_module)","original":null,"replacement":null,"description":"The module is not documented.\n\nFor more information see: /erlang-error-index/w/W0046","docPath":"website/docs/erlang-error-index/w/W0046.md"} +{"path":"app_b/src/app_b_unused_param.erl","line":5,"char":5,"code":"ELP","severity":"warning","name":"L1268 (L1268)","original":null,"replacement":null,"description":"variable 'X' is unused\n\nFor more information see: /erlang-error-index/l/L1268","docPath":null} {"path":"app_a/src/custom_function_matches.erl","line":13,"char":5,"code":"ELP","severity":"warning","name":"W0017 (undefined_function)","original":null,"replacement":null,"description":"Function 'excluded:function/0' is undefined.\n\nFor more information see: /erlang-error-index/w/W0017","docPath":"website/docs/erlang-error-index/w/W0017.md"} {"path":"app_a/src/custom_function_matches.erl","line":14,"char":5,"code":"ELP","severity":"warning","name":"W0017 (undefined_function)","original":null,"replacement":null,"description":"Function 'not_excluded:function/0' is undefined.\n\nFor more information see: /erlang-error-index/w/W0017","docPath":"website/docs/erlang-error-index/w/W0017.md"} {"path":"app_a/src/custom_function_matches.erl","line":15,"char":5,"code":"ELP","severity":"warning","name":"W0017 (undefined_function)","original":null,"replacement":null,"description":"Function 'cross:call/0' is undefined.\n\nFor more information see: /erlang-error-index/w/W0017","docPath":"website/docs/erlang-error-index/w/W0017.md"} +{"path":"app_a/src/expression_updates_literal.erl","line":2,"char":9,"code":"ELP","severity":"disabled","name":"W0046 (undocumented_module)","original":null,"replacement":null,"description":"The module is not documented.\n\nFor more information see: /erlang-error-index/w/W0046","docPath":"website/docs/erlang-error-index/w/W0046.md"} {"path":"app_a/src/expression_updates_literal.erl","line":7,"char":1,"code":"ELP","severity":"warning","name":"L1309 (L1309)","original":null,"replacement":null,"description":"missing specification for function a_fun/0\n\nFor more information see: /erlang-error-index/l/L1309","docPath":null} {"path":"app_a/src/expression_updates_literal.erl","line":8,"char":7,"code":"ELP","severity":"warning","name":"L1318 (L1318)","original":null,"replacement":null,"description":"expression updates a literal\n\nFor more information see: /erlang-error-index/l/L1318","docPath":null} {"path":"app_a/src/spelling.erl","line":2,"char":2,"code":"ELP","severity":"error","name":"W0013 (misspelled_attribute)","original":null,"replacement":null,"description":"misspelled attribute, saw 'dyalizer' but expected 'dialyzer'\n\nFor more information see: /erlang-error-index/w/W0013","docPath":"website/docs/erlang-error-index/w/W0013.md"} -{"path":"app_b/src/app_b.erl","line":5,"char":5,"code":"ELP","severity":"warning","name":"W0011 (application_get_env)","original":null,"replacement":null,"description":"module `app_b` belongs to app `app_b`, but reads env for `misc`\n\nFor more information see: /erlang-error-index/w/W0011","docPath":"website/docs/erlang-error-index/w/W0011.md"} -{"path":"app_b/src/app_b_unused_param.erl","line":5,"char":5,"code":"ELP","severity":"warning","name":"L1268 (L1268)","original":null,"replacement":null,"description":"variable 'X' is unused\n\nFor more information see: /erlang-error-index/l/L1268","docPath":null} \ No newline at end of file +{"path":"app_a/src/spelling.erl","line":1,"char":1,"code":"ELP","severity":"error","name":"W0012 (compile-warn-missing-spec)","original":null,"replacement":null,"description":"Please add \"-compile(warn_missing_spec_all).\" to the module. If exported functions are not all specced, they need to be specced.\n\nFor more information see: /erlang-error-index/w/W0012","docPath":"website/docs/erlang-error-index/w/W0012.md"} +{"path":"app_a/src/spelling.erl","line":1,"char":9,"code":"ELP","severity":"disabled","name":"W0046 (undocumented_module)","original":null,"replacement":null,"description":"The module is not documented.\n\nFor more information see: /erlang-error-index/w/W0046","docPath":"website/docs/erlang-error-index/w/W0046.md"} diff --git a/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_output.stdout b/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_output.stdout index 5bcd503e10..954278d91b 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_output.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_output.stdout @@ -1,21 +1,41 @@ - 7:1-7:5: Mismatched clause name -Diagnostics reported: Reporting all diagnostics codes -app_a/src/app_a.erl:12:1-12:4::[Warning] [L1230] function bar/0 is unused -app_a/src/app_a.erl:13:5-13:14::[Warning] [W0026] Function 'app_a:baz/2' is not exported. -app_a/src/app_a.erl:16:1-16:4::[Warning] [L1230] function baz/2 is unused -app_a/src/app_a.erl:20:1-20:4::[Warning] [L1230] function bat/2 is unused -app_a/src/app_a.erl:5:5-5:35::[Warning] [W0011] module `app_a` belongs to app `app_a`, but reads env for `misc` -app_a/src/app_a.erl:8:7-8:8::[Warning] [W0018] Unexpected ';' -app_a/src/app_a.erl:9:1-9:5::[Error] [P1700] head mismatch 'fooX' vs 'food' -app_a/src/app_a_ssr.erl:7:6-7:7::[Warning] [W0060] Match on a bound variable -app_a/src/app_a_ssr.erl:8:6-8:7::[Warning] [W0060] Match on a bound variable -app_a/src/app_a_unused_param.erl:5:5-5:6::[Warning] [L1268] variable 'X' is unused -app_a/src/custom_function_matches.erl:13:5-13:22::[Warning] [W0017] Function 'excluded:function/0' is undefined. -app_a/src/custom_function_matches.erl:14:5-14:26::[Warning] [W0017] Function 'not_excluded:function/0' is undefined. -app_a/src/custom_function_matches.erl:15:5-15:15::[Warning] [W0017] Function 'cross:call/0' is undefined. -app_a/src/expression_updates_literal.erl:7:1-7:6::[Warning] [L1309] missing specification for function a_fun/0 -app_a/src/expression_updates_literal.erl:8:7-9:16::[Warning] [L1318] expression updates a literal -app_a/src/spelling.erl:2:2-2:10::[Error] [W0013] misspelled attribute, saw 'dyalizer' but expected 'dialyzer' -app_b/src/app_b.erl:5:5-5:35::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` -app_b/src/app_b_unused_param.erl:5:5-5:6::[Warning] [L1268] variable 'X' is unused \ No newline at end of file +Diagnostics reported in 9 modules: + app_a: 8 + 4:4-4:34::[Warning] [W0011] module `app_a` belongs to app `app_a`, but reads env for `misc` + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 8:0-8:4::[Error] [P1700] head mismatch 'fooX' vs 'food' + 7:6-7:7::[Warning] [W0018] Unexpected ';' + 0:8-0:13::[WeakWarning] [W0046] The module is not documented. + 12:4-12:13::[Warning] [W0026] Function 'app_a:baz/2' is not exported. + 11:0-11:3::[Warning] [L1230] function bar/0 is unused + 15:0-15:3::[Warning] [L1230] function baz/2 is unused + app_a_edoc: 2 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 0:8-0:18::[WeakWarning] [W0046] The module is not documented. + app_a_ssr: 2 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 0:8-0:17::[WeakWarning] [W0046] The module is not documented. + app_a_unused_param: 3 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 0:8-0:26::[WeakWarning] [W0046] The module is not documented. + 4:4-4:5::[Warning] [L1268] variable 'X' is unused + app_b: 3 + 4:4-4:34::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 0:8-0:13::[WeakWarning] [W0046] The module is not documented. + app_b_unused_param: 3 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 0:8-0:26::[WeakWarning] [W0046] The module is not documented. + 4:4-4:5::[Warning] [L1268] variable 'X' is unused + custom_function_matches: 3 + 12:4-12:21::[Warning] [W0017] Function 'excluded:function/0' is undefined. + 13:4-13:25::[Warning] [W0017] Function 'not_excluded:function/0' is undefined. + 14:4-14:14::[Warning] [W0017] Function 'cross:call/0' is undefined. + expression_updates_literal: 3 + 1:8-1:34::[WeakWarning] [W0046] The module is not documented. + 6:0-6:5::[Warning] [L1309] missing specification for function a_fun/0 + 7:6-8:15::[Warning] [L1318] expression updates a literal + spelling: 3 + 1:1-1:9::[Error] [W0013] misspelled attribute, saw 'dyalizer' but expected 'dialyzer' + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 0:8-0:16::[WeakWarning] [W0046] The module is not documented. diff --git a/crates/elp/src/resources/test/linter/ssr_ad_hoc.stdout b/crates/elp/src/resources/test/linter/ssr_ad_hoc.stdout index 7ded0e8d2f..55650830ba 100644 --- a/crates/elp/src/resources/test/linter/ssr_ad_hoc.stdout +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc.stdout @@ -1,3 +1,3 @@ -Diagnostics reported: -app_a/src/app_a.erl:16:13-16:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {_@A, _@B}. -app_a/src/app_a.erl:20:13-20:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {_@A, _@B}. \ No newline at end of file +Diagnostics reported in 1 modules: + app_a: 1 + 15:12-15:17::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {_@A, _@B}. diff --git a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli.stdout b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli.stdout index e673a7be31..2e8c69b6a4 100644 --- a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli.stdout +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli.stdout @@ -1,5 +1,3 @@ - app_a: 2 - 16:13-16:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {_@A, _@B}. - 20:13-20:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {_@A, _@B}. - -Matches found in 1 modules +Matches found in 1 modules: + app_a: 1 + 15:12-15:17::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {_@A, _@B}. diff --git a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_dump_config.stdout b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_dump_config.stdout deleted file mode 100644 index 880b8f3473..0000000000 --- a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_dump_config.stdout +++ /dev/null @@ -1,12 +0,0 @@ - -# Add this to your .elp_lint.toml -[[ad_hoc_lints.lints]] -type = "LintMatchSsr" -ssr_pattern = "ssr: ?BAR(_@AA)." -severity = "info" - -[[ad_hoc_lints.lints]] -type = "LintMatchSsr" -ssr_pattern = "ssr: {4}." -severity = "info" - diff --git a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_expand.stdout b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_expand.stdout index 78f52012ac..16ad74ebac 100644 --- a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_expand.stdout +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_expand.stdout @@ -1,4 +1,3 @@ +Matches found in 1 modules: app_a_ssr: 1 - 11:11-11:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {4}. - -Matches found in 1 modules + 10:10-10:17::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {4}. diff --git a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_no_expand.stdout b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_no_expand.stdout index f5a1e98710..0e246ef6f5 100644 --- a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_no_expand.stdout +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_no_expand.stdout @@ -1,4 +1,3 @@ +Matches found in 1 modules: app_a_ssr: 1 - 11:11-11:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: ?BAR(_@AA). - -Matches found in 1 modules + 10:10-10:17::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: ?BAR(_@AA). diff --git a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_visible_expand.stdout b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_visible_expand.stdout index 6f49895580..351b8ffee2 100644 --- a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_visible_expand.stdout +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_visible_expand.stdout @@ -1,5 +1,4 @@ +Matches found in 1 modules: app_a_ssr: 2 - 11:11-11:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: ?BAR(_@AA). - 11:11-11:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {4}. - -Matches found in 1 modules + 10:10-10:17::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: ?BAR(_@AA). + 10:10-10:17::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {4}. diff --git a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_multiple.stdout b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_multiple.stdout index a71ebede29..afffa751be 100644 --- a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_multiple.stdout +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_multiple.stdout @@ -1,5 +1,4 @@ +Matches found in 1 modules: app_a_ssr: 2 - 7:10-7:15::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: 3. - 11:11-11:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {4}. - -Matches found in 1 modules + 6:9-6:14::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: 3. + 10:10-10:17::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {4}. diff --git a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_parens_invisible.stdout b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_parens_invisible.stdout index 6938fabb87..cefa90c758 100644 --- a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_parens_invisible.stdout +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_parens_invisible.stdout @@ -1,4 +1,3 @@ +Matches found in 1 modules: app_a_ssr: 1 - 7:10-7:15::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: (((3))). - -Matches found in 1 modules + 6:9-6:14::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: (((3))). diff --git a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_parens_visible.stdout b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_parens_visible.stdout index a43317a2cf..f830e74c63 100644 --- a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_parens_visible.stdout +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_parens_visible.stdout @@ -1,6 +1,5 @@ +Matches found in 1 modules: app_a_ssr: 3 - 7:10-7:15::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: (_@A). - 7:11-7:14::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: (_@A). - 8:10-8:13::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: (_@A). - -Matches found in 1 modules + 6:9-6:14::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: (_@A). + 6:10-6:13::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: (_@A). + 7:9-7:12::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: (_@A). diff --git a/crates/elp/src/resources/test/linter/ssr_context_separator.stdout b/crates/elp/src/resources/test/linter/ssr_context_separator.stdout deleted file mode 100644 index f791ea85bf..0000000000 --- a/crates/elp/src/resources/test/linter/ssr_context_separator.stdout +++ /dev/null @@ -1,20 +0,0 @@ - app_a: 2 -app_a/src/app_a.erl:16:13-16:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {_@A, _@B}. - 14 | app_b:application_env_error(). - 15 | - 16 | baz(A,B) -> {A,B}. - | ^^^^^ - 17 | - 18 | % Some more context, see if it renders - -==== -app_a/src/app_a.erl:20:13-20:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {_@A, _@B}. - 18 | % Some more context, see if it renders - 19 | - 20 | bat(A,B) -> {A,B}. - | ^^^^^ - 21 | - 22 | % And some more context, see if it renders - - -Matches found in 1 modules diff --git a/crates/elp/src/resources/test/linter/ssr_context_separator_color.stdout b/crates/elp/src/resources/test/linter/ssr_context_separator_color.stdout deleted file mode 100644 index 119d62a52b..0000000000 --- a/crates/elp/src/resources/test/linter/ssr_context_separator_color.stdout +++ /dev/null @@ -1,18 +0,0 @@ - app_a: 2 -app_a/src/app_a.erl:16:13-16:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {_@A, _@B}. - 14 | app_b:application_env_error(). - 15 | - 16 | baz(A,B) -> {A,B}. - 17 | - 18 | % Some more context, see if it renders - -==== -app_a/src/app_a.erl:20:13-20:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {_@A, _@B}. - 18 | % Some more context, see if it renders - 19 | - 20 | bat(A,B) -> {A,B}. - 21 | - 22 | % And some more context, see if it renders - - -Matches found in 1 modules diff --git a/crates/elp/src/resources/test/linter/warnings_as_errors.stdout b/crates/elp/src/resources/test/linter/warnings_as_errors.stdout index 01007e94c4..493afa95c7 100644 --- a/crates/elp/src/resources/test/linter/warnings_as_errors.stdout +++ b/crates/elp/src/resources/test/linter/warnings_as_errors.stdout @@ -1,21 +1,41 @@ - 7:1-7:5: Mismatched clause name -Diagnostics reported: Reporting all diagnostics codes -app_a/src/app_a.erl:12:1-12:4::[Error] [L1230] function bar/0 is unused -app_a/src/app_a.erl:13:5-13:14::[Warning] [W0026] Function 'app_a:baz/2' is not exported. -app_a/src/app_a.erl:16:1-16:4::[Error] [L1230] function baz/2 is unused -app_a/src/app_a.erl:20:1-20:4::[Error] [L1230] function bat/2 is unused -app_a/src/app_a.erl:5:5-5:35::[Warning] [W0011] module `app_a` belongs to app `app_a`, but reads env for `misc` -app_a/src/app_a.erl:8:7-8:8::[Warning] [W0018] Unexpected ';' -app_a/src/app_a.erl:9:1-9:5::[Error] [P1700] head mismatch 'fooX' vs 'food' -app_a/src/app_a_ssr.erl:7:6-7:7::[Warning] [W0060] Match on a bound variable -app_a/src/app_a_ssr.erl:8:6-8:7::[Warning] [W0060] Match on a bound variable -app_a/src/app_a_unused_param.erl:5:5-5:6::[Error] [L1268] variable 'X' is unused -app_a/src/custom_function_matches.erl:13:5-13:22::[Warning] [W0017] Function 'excluded:function/0' is undefined. -app_a/src/custom_function_matches.erl:14:5-14:26::[Warning] [W0017] Function 'not_excluded:function/0' is undefined. -app_a/src/custom_function_matches.erl:15:5-15:15::[Warning] [W0017] Function 'cross:call/0' is undefined. -app_a/src/expression_updates_literal.erl:7:1-7:6::[Error] [L1309] missing specification for function a_fun/0 -app_a/src/expression_updates_literal.erl:8:7-9:16::[Error] [L1318] expression updates a literal -app_a/src/spelling.erl:2:2-2:10::[Error] [W0013] misspelled attribute, saw 'dyalizer' but expected 'dialyzer' -app_b/src/app_b.erl:5:5-5:35::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` -app_b/src/app_b_unused_param.erl:5:5-5:6::[Error] [L1268] variable 'X' is unused \ No newline at end of file +Diagnostics reported in 9 modules: + app_a: 8 + 4:4-4:34::[Warning] [W0011] module `app_a` belongs to app `app_a`, but reads env for `misc` + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 8:0-8:4::[Error] [P1700] head mismatch 'fooX' vs 'food' + 7:6-7:7::[Warning] [W0018] Unexpected ';' + 0:8-0:13::[WeakWarning] [W0046] The module is not documented. + 12:4-12:13::[Warning] [W0026] Function 'app_a:baz/2' is not exported. + 11:0-11:3::[Error] [L1230] function bar/0 is unused + 15:0-15:3::[Error] [L1230] function baz/2 is unused + app_a_edoc: 2 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 0:8-0:18::[WeakWarning] [W0046] The module is not documented. + app_a_ssr: 2 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 0:8-0:17::[WeakWarning] [W0046] The module is not documented. + app_a_unused_param: 3 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 0:8-0:26::[WeakWarning] [W0046] The module is not documented. + 4:4-4:5::[Error] [L1268] variable 'X' is unused + app_b: 3 + 4:4-4:34::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 0:8-0:13::[WeakWarning] [W0046] The module is not documented. + app_b_unused_param: 3 + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 0:8-0:26::[WeakWarning] [W0046] The module is not documented. + 4:4-4:5::[Error] [L1268] variable 'X' is unused + custom_function_matches: 3 + 12:4-12:21::[Warning] [W0017] Function 'excluded:function/0' is undefined. + 13:4-13:25::[Warning] [W0017] Function 'not_excluded:function/0' is undefined. + 14:4-14:14::[Warning] [W0017] Function 'cross:call/0' is undefined. + expression_updates_literal: 3 + 1:8-1:34::[WeakWarning] [W0046] The module is not documented. + 6:0-6:5::[Error] [L1309] missing specification for function a_fun/0 + 7:6-8:15::[Error] [L1318] expression updates a literal + spelling: 3 + 1:1-1:9::[Error] [W0013] misspelled attribute, saw 'dyalizer' but expected 'dialyzer' + 0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + 0:8-0:16::[WeakWarning] [W0046] The module is not documented. diff --git a/crates/elp/src/resources/test/linter_config/basic.stdout b/crates/elp/src/resources/test/linter_config/basic.stdout deleted file mode 100644 index 946fd7dc9a..0000000000 --- a/crates/elp/src/resources/test/linter_config/basic.stdout +++ /dev/null @@ -1,5 +0,0 @@ -Diagnostics reported: -Reporting all diagnostics codes -app_a/src/app_a.erl:3:9-3:16::[Warning] [W0002] Unused macro (MACRO_A) -app_a/src/app_a.erl:4:9-4:14::[Warning] [L1260] record rec_a is unused -app_b/src/app_b.erl:3:9-3:16::[Warning] [W0002] Unused macro (MACRO_B) \ No newline at end of file diff --git a/crates/elp/src/resources/test/parse_elp_help.stdout b/crates/elp/src/resources/test/parse_elp_help.stdout index 75cc38354e..1457aed5c5 100644 --- a/crates/elp/src/resources/test/parse_elp_help.stdout +++ b/crates/elp/src/resources/test/parse_elp_help.stdout @@ -1,4 +1,4 @@ -Usage: [--project PROJECT] [--module MODULE] [--file ARG] [--to TO] [--no-diags] [--experimental] [--as PROFILE] [--dump-includes] [--rebar] [--include-generated] [--serial] [--use-cli-severity] [[--format FORMAT]] [--report-system-stats] [[--severity SEVERITY]] +Usage: [--project PROJECT] [--module MODULE] [--file ARG] [--to TO] [--no-diags] [--experimental] [--as PROFILE] [--dump-includes] [--rebar] [--include-generated] [--serial] [--use-cli-severity] [[--format FORMAT]] [--report-system-stats] Available options: --project Path to directory with project, or to a JSON file (defaults to `.`) @@ -15,5 +15,4 @@ Available options: --use-cli-severity If specified, use the provided CLI severity mapping instead of the default one --format Show diagnostics in JSON format --report-system-stats Report system memory usage and other statistics - --severity Minimum severity level to report. Valid values: error, warning, weak_warning, information -h, --help Prints help information diff --git a/crates/elp/src/resources/test/ssr_help.stdout b/crates/elp/src/resources/test/ssr_help.stdout index d51bdf1627..a90220787a 100644 --- a/crates/elp/src/resources/test/ssr_help.stdout +++ b/crates/elp/src/resources/test/ssr_help.stdout @@ -1,26 +1,19 @@ -Usage: [--project PROJECT] [--module MODULE] [--app APP] [--file FILE] [--rebar] [--as PROFILE] [--include-generated] [--include-tests] [[--format FORMAT]] [[--macros STRATEGY]] [--parens] [--dump-config] [--show-source] [-B NUM] [-A NUM] [-C NUM] [--group-separator SEP] [--no-group-separator] [--report-system-stats] ... +Usage: [--project PROJECT] [--module MODULE] [--app APP] [--file FILE] [--rebar] [--as PROFILE] [--include-generated] [--include-tests] [[--format FORMAT]] [[--macros STRATEGY]] [--parens] [--report-system-stats] ... Available positional items: SSR specs to use Available options: - --project Path to directory with project, or to a JSON file (defaults to `.`) - --module Parse a single module from the project, not the entire project. - --app Parse a single application from the project, not the entire project. - --file Parse a single file from the project, not the entire project. This can be an include file or escript, etc. - --rebar Run with rebar - --as Rebar3 profile to pickup (default is test) - --include-generated Also generate diagnostics for generated files - --include-tests Also generate diagnostics for test files - --format Show diagnostics in JSON format - --macros Macro expansion strategy: expand | no-expand | visible-expand (default expand) - --parens Explicitly match parentheses. If omitted, they are ignored. - --dump-config Dump a configuration snippet that can be put in .elp_lint.toml to match the given SSR patterns - --show-source Show source code context for matches - -B, --before-context Print NUM lines of leading context, enables --show-source - -A, --after-context Print NUM lines of trailing context, enables --show-source - -C, --context Print NUM lines of output context, enables --show-source - --group-separator Print SEP on line between matches with context, enables --show-source - --no-group-separator Do not print separator for matches with context, enables --show-source - --report-system-stats Report system memory usage and other statistics - -h, --help Prints help information + --project Path to directory with project, or to a JSON file (defaults to `.`) + --module Parse a single module from the project, not the entire project. + --app Parse a single application from the project, not the entire project. + --file Parse a single file from the project, not the entire project. This can be an include file or escript, etc. + --rebar Run with rebar + --as Rebar3 profile to pickup (default is test) + --include-generated Also generate diagnostics for generated files + --include-tests Also generate diagnostics for test files + --format Show diagnostics in JSON format + --macros Macro expansion strategy: expand | no-expand | visible-expand (default expand) + --parens Explicitly match parentheses. If omitted, they are ignored. + --report-system-stats Report system memory usage and other statistics + -h, --help Prints help information diff --git a/crates/elp/src/resources/test/standard/eqwalize_all_bail_on_error_failure.pretty b/crates/elp/src/resources/test/standard/eqwalize_all_bail_on_error_failure.pretty index 1d868bbbc6..08361b2a89 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_all_bail_on_error_failure.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_all_bail_on_error_failure.pretty @@ -44,6 +44,10 @@ Because in the expression's type: Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...} The type of the expression is missing the following required keys: k_req3, k_req2, k_req1. +------------------------------ Detailed message ------------------------------ + +keys `k_req1`, `k_req2`, `k_req3` are declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:102:5 │ @@ -64,6 +68,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d => atom()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d => atom()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:125:5 │ @@ -85,6 +100,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d := pid(), e := pid()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/test/app_a_SUITE.erl:18:5 │ @@ -153,6 +179,14 @@ Because in the expression's type: No candidate matches in the expected union. ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [T | X] + because + term() is not compatible with T | X + because + term() is not compatible with T + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -170,6 +204,12 @@ Because in the expression's type: Context expects type: T ) -> boolean() | {'true', X}) +------------------------------ Detailed message ------------------------------ + + fun((T) -> boolean() | {'true', X}) is not compatible with fun((term()) -> boolean() | {'true', term()}) + because + term() is not compatible with T + error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) ┌─ app_a/src/app_a_mod2.erl:22:1 │ @@ -192,14 +232,6 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: 'wrong_ret' Context expected type: 'error' -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ app_a/test/app_a_test_helpers_not_opted_in.erl:5:11 - │ -5 │ fail() -> error. - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_b/src/app_b.erl:16:5 │ @@ -208,4 +240,4 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: [T] Context expected type: T -21 ERRORS +20 ERRORS diff --git a/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.jsonl b/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.jsonl index b311705d68..536452ef3a 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.jsonl +++ b/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.jsonl @@ -2,9 +2,9 @@ {"path":"app_a/src/app_a.erl","line":14,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'error'","replacement":null,"description":"```lang=error,counterexample\n`'error'`.\n\nExpression has type: 'error'\nContext expected type: 'ok'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/src/app_a.erl","line":18,"char":13,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'an_atom'","replacement":null,"description":"```lang=error,counterexample\n`'an_atom'`.\n\nExpression has type: 'an_atom'\nContext expected type: number()\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/src/app_a.erl","line":56,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: redundant_fixme","original":null,"replacement":null,"description":"```lang=error,counterexample\n\nredundant fixme\n```\n\n> [docs on `redundant_fixme`](https://fb.me/eqwalizer_errors#redundant_fixme)","docPath":null} -{"path":"app_a/src/app_a.erl","line":78,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: #{k_extra => term(), k_ok => term(), k_req1 => term(), k_req2 => term(), k_wrong1 => pid(), k_wrong2 => pid()}\nContext expected type: #{k_ok => term(), k_req1 := atom(), k_req2 := atom(), k_req3 := atom(), k_wrong1 => atom(), k_wrong2 => atom()}\n```\n```\nBecause in the expression's type:\n Here the type is: #{k_req2 => ..., k_req1 => ..., ...}\n Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...}\n The type of the expression is missing the following required keys: k_req3, k_req2, k_req1.\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/src/app_a.erl","line":102,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: id(#{a := 'va', b := #{c := #{d => atom()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n```\n```\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n Here the type is: #{d => ..., ...}\n Context expects type: #{d := ..., e := ..., ...}\n The type of the expression is missing the following required keys: d, e.\n , ... }\n , ... }\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/src/app_a.erl","line":125,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n```\n```\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n #{ d =>\n Here the type is: pid()\n Context expects type: atom()\n , ... }\n , ... }\n , ... }\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} +{"path":"app_a/src/app_a.erl","line":78,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: #{k_extra => term(), k_ok => term(), k_req1 => term(), k_req2 => term(), k_wrong1 => pid(), k_wrong2 => pid()}\nContext expected type: #{k_ok => term(), k_req1 := atom(), k_req2 := atom(), k_req3 := atom(), k_wrong1 => atom(), k_wrong2 => atom()}\n```\n```\nBecause in the expression's type:\n Here the type is: #{k_req2 => ..., k_req1 => ..., ...}\n Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...}\n The type of the expression is missing the following required keys: k_req3, k_req2, k_req1.\n\n------------------------------ Detailed message ------------------------------\n\nkeys `k_req1`, `k_req2`, `k_req3` are declared as required in the latter but not in the former\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} +{"path":"app_a/src/app_a.erl","line":102,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: id(#{a := 'va', b := #{c := #{d => atom()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n```\n```\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n Here the type is: #{d => ..., ...}\n Context expects type: #{d := ..., e := ..., ...}\n The type of the expression is missing the following required keys: d, e.\n , ... }\n , ... }\n\n------------------------------ Detailed message ------------------------------\n\n id(#{a := 'va', b := #{c := #{d => atom()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n at key `b`:\n #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{c := #{d => atom()}} is not compatible with #{c := id(#{d := atom(), e := atom()})}\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} +{"path":"app_a/src/app_a.erl","line":125,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n```\n```\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n #{ d =>\n Here the type is: pid()\n Context expects type: atom()\n , ... }\n , ... }\n , ... }\n\n------------------------------ Detailed message ------------------------------\n\n id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n at key `b`:\n #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{c := #{d := pid(), e := pid()}} is not compatible with #{c := id(#{d := atom(), e := atom()})}\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/test/app_a_SUITE.erl","line":18,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"app_a_test_helpers:fail()","replacement":null,"description":"```lang=error,counterexample\n`app_a_test_helpers:fail()`.\n\nExpression has type: 'error'\nContext expected type: 'ok'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/src/app_a_errors_generated.erl","line":8,"char":10,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'wrong_ret'","replacement":null,"description":"```lang=error,counterexample\n`'wrong_ret'`.\n\nExpression has type: 'wrong_ret'\nContext expected type: 'foo'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/src/app_a_lists.erl","line":576,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"flatmap(thing_to_list/1, List)","replacement":null,"description":"```lang=error,counterexample\n`flatmap(thing_to_list/1, List)`.\n\nExpression has type: [term()]\nContext expected type: string()\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} @@ -12,10 +12,9 @@ {"path":"app_a/src/app_a_lists.erl","line":595,"char":29,"code":"ELP","severity":"error","name":"eqWAlizer: recursive_constraint","original":null,"replacement":null,"description":"```lang=error,counterexample\n\nRecursive constraint: DeepList\n```\n\n> [docs on `recursive_constraint`](https://fb.me/eqwalizer_errors#recursive_constraint)","docPath":null} {"path":"app_a/src/app_a_lists.erl","line":613,"char":29,"code":"ELP","severity":"error","name":"eqWAlizer: recursive_constraint","original":null,"replacement":null,"description":"```lang=error,counterexample\n\nRecursive constraint: DeepList\n```\n\n> [docs on `recursive_constraint`](https://fb.me/eqwalizer_errors#recursive_constraint)","docPath":null} {"path":"app_a/src/app_a_lists.erl","line":1114,"char":36,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"H3","replacement":null,"description":"```lang=error,counterexample\n`H3`.\n\nExpression has type: term()\nContext expected type: [term()]\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/src/app_a_lists.erl","line":1305,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"filtermap(F, L)","replacement":null,"description":"```lang=error,counterexample\n`filtermap(F, L)`.\n\nExpression has type: [term()]\nContext expected type: [T | X]\n```\n```\nBecause in the expression's type:\n [\n Here the type is: term()\n Context expects type: T | X\n No candidate matches in the expected union.\n ]\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/src/app_a_lists.erl","line":1305,"char":15,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"F","replacement":null,"description":"```lang=error,counterexample\n`F`.\n\nExpression has type: fun((T) -> boolean() | {'true', X})\nContext expected type: fun((term()) -> boolean() | {'true', term()})\n```\n```\nBecause in the expression's type:\n fun((\n Here the type is: term()\n Context expects type: T\n ) -> boolean() | {'true', X})\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} +{"path":"app_a/src/app_a_lists.erl","line":1305,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"filtermap(F, L)","replacement":null,"description":"```lang=error,counterexample\n`filtermap(F, L)`.\n\nExpression has type: [term()]\nContext expected type: [T | X]\n```\n```\nBecause in the expression's type:\n [\n Here the type is: term()\n Context expects type: T | X\n No candidate matches in the expected union.\n ]\n\n------------------------------ Detailed message ------------------------------\n\n [term()] is not compatible with [T | X]\n because\n term() is not compatible with T | X\n because\n term() is not compatible with T\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} +{"path":"app_a/src/app_a_lists.erl","line":1305,"char":15,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"F","replacement":null,"description":"```lang=error,counterexample\n`F`.\n\nExpression has type: fun((T) -> boolean() | {'true', X})\nContext expected type: fun((term()) -> boolean() | {'true', term()})\n```\n```\nBecause in the expression's type:\n fun((\n Here the type is: term()\n Context expects type: T\n ) -> boolean() | {'true', X})\n\n------------------------------ Detailed message ------------------------------\n\n fun((T) -> boolean() | {'true', X}) is not compatible with fun((term()) -> boolean() | {'true', term()})\n because\n term() is not compatible with T\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/src/app_a_mod2.erl","line":22,"char":1,"code":"ELP","severity":"error","name":"eqWAlizer: type_alias_is_non_productive","original":null,"replacement":null,"description":"```lang=error,counterexample\n\nrecursive type invalid/0 is not productive\n```\n\n> [docs on `type_alias_is_non_productive`](https://fb.me/eqwalizer_errors#type_alias_is_non_productive)","docPath":null} {"path":"app_a/src/app_a_mod2.erl","line":31,"char":9,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'an_atom'","replacement":null,"description":"```lang=error,counterexample\n`'an_atom'`.\n\nExpression has type: 'an_atom'\nContext expected type: number()\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/test/app_a_test_helpers.erl","line":6,"char":11,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'wrong_ret'","replacement":null,"description":"```lang=error,counterexample\n`'wrong_ret'`.\n\nExpression has type: 'wrong_ret'\nContext expected type: 'error'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/test/app_a_test_helpers_not_opted_in.erl","line":5,"char":11,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'error'","replacement":null,"description":"```lang=error,counterexample\n`'error'`.\n\nExpression has type: 'error'\nContext expected type: 'ok'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_b/src/app_b.erl","line":16,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"L","replacement":null,"description":"```lang=error,counterexample\n`L`.\n\nExpression has type: [T]\nContext expected type: T\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} diff --git a/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.pretty b/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.pretty index 1d868bbbc6..08361b2a89 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.pretty @@ -44,6 +44,10 @@ Because in the expression's type: Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...} The type of the expression is missing the following required keys: k_req3, k_req2, k_req1. +------------------------------ Detailed message ------------------------------ + +keys `k_req1`, `k_req2`, `k_req3` are declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:102:5 │ @@ -64,6 +68,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d => atom()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d => atom()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:125:5 │ @@ -85,6 +100,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d := pid(), e := pid()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/test/app_a_SUITE.erl:18:5 │ @@ -153,6 +179,14 @@ Because in the expression's type: No candidate matches in the expected union. ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [T | X] + because + term() is not compatible with T | X + because + term() is not compatible with T + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -170,6 +204,12 @@ Because in the expression's type: Context expects type: T ) -> boolean() | {'true', X}) +------------------------------ Detailed message ------------------------------ + + fun((T) -> boolean() | {'true', X}) is not compatible with fun((term()) -> boolean() | {'true', term()}) + because + term() is not compatible with T + error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) ┌─ app_a/src/app_a_mod2.erl:22:1 │ @@ -192,14 +232,6 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: 'wrong_ret' Context expected type: 'error' -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ app_a/test/app_a_test_helpers_not_opted_in.erl:5:11 - │ -5 │ fail() -> error. - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_b/src/app_b.erl:16:5 │ @@ -208,4 +240,4 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: [T] Context expected type: T -21 ERRORS +20 ERRORS diff --git a/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics_gen.jsonl b/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics_gen.jsonl index b311705d68..536452ef3a 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics_gen.jsonl +++ b/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics_gen.jsonl @@ -2,9 +2,9 @@ {"path":"app_a/src/app_a.erl","line":14,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'error'","replacement":null,"description":"```lang=error,counterexample\n`'error'`.\n\nExpression has type: 'error'\nContext expected type: 'ok'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/src/app_a.erl","line":18,"char":13,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'an_atom'","replacement":null,"description":"```lang=error,counterexample\n`'an_atom'`.\n\nExpression has type: 'an_atom'\nContext expected type: number()\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/src/app_a.erl","line":56,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: redundant_fixme","original":null,"replacement":null,"description":"```lang=error,counterexample\n\nredundant fixme\n```\n\n> [docs on `redundant_fixme`](https://fb.me/eqwalizer_errors#redundant_fixme)","docPath":null} -{"path":"app_a/src/app_a.erl","line":78,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: #{k_extra => term(), k_ok => term(), k_req1 => term(), k_req2 => term(), k_wrong1 => pid(), k_wrong2 => pid()}\nContext expected type: #{k_ok => term(), k_req1 := atom(), k_req2 := atom(), k_req3 := atom(), k_wrong1 => atom(), k_wrong2 => atom()}\n```\n```\nBecause in the expression's type:\n Here the type is: #{k_req2 => ..., k_req1 => ..., ...}\n Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...}\n The type of the expression is missing the following required keys: k_req3, k_req2, k_req1.\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/src/app_a.erl","line":102,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: id(#{a := 'va', b := #{c := #{d => atom()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n```\n```\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n Here the type is: #{d => ..., ...}\n Context expects type: #{d := ..., e := ..., ...}\n The type of the expression is missing the following required keys: d, e.\n , ... }\n , ... }\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/src/app_a.erl","line":125,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n```\n```\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n #{ d =>\n Here the type is: pid()\n Context expects type: atom()\n , ... }\n , ... }\n , ... }\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} +{"path":"app_a/src/app_a.erl","line":78,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: #{k_extra => term(), k_ok => term(), k_req1 => term(), k_req2 => term(), k_wrong1 => pid(), k_wrong2 => pid()}\nContext expected type: #{k_ok => term(), k_req1 := atom(), k_req2 := atom(), k_req3 := atom(), k_wrong1 => atom(), k_wrong2 => atom()}\n```\n```\nBecause in the expression's type:\n Here the type is: #{k_req2 => ..., k_req1 => ..., ...}\n Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...}\n The type of the expression is missing the following required keys: k_req3, k_req2, k_req1.\n\n------------------------------ Detailed message ------------------------------\n\nkeys `k_req1`, `k_req2`, `k_req3` are declared as required in the latter but not in the former\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} +{"path":"app_a/src/app_a.erl","line":102,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: id(#{a := 'va', b := #{c := #{d => atom()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n```\n```\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n Here the type is: #{d => ..., ...}\n Context expects type: #{d := ..., e := ..., ...}\n The type of the expression is missing the following required keys: d, e.\n , ... }\n , ... }\n\n------------------------------ Detailed message ------------------------------\n\n id(#{a := 'va', b := #{c := #{d => atom()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n at key `b`:\n #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{c := #{d => atom()}} is not compatible with #{c := id(#{d := atom(), e := atom()})}\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} +{"path":"app_a/src/app_a.erl","line":125,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n```\n```\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n #{ d =>\n Here the type is: pid()\n Context expects type: atom()\n , ... }\n , ... }\n , ... }\n\n------------------------------ Detailed message ------------------------------\n\n id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n at key `b`:\n #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{c := #{d := pid(), e := pid()}} is not compatible with #{c := id(#{d := atom(), e := atom()})}\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/test/app_a_SUITE.erl","line":18,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"app_a_test_helpers:fail()","replacement":null,"description":"```lang=error,counterexample\n`app_a_test_helpers:fail()`.\n\nExpression has type: 'error'\nContext expected type: 'ok'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/src/app_a_errors_generated.erl","line":8,"char":10,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'wrong_ret'","replacement":null,"description":"```lang=error,counterexample\n`'wrong_ret'`.\n\nExpression has type: 'wrong_ret'\nContext expected type: 'foo'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/src/app_a_lists.erl","line":576,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"flatmap(thing_to_list/1, List)","replacement":null,"description":"```lang=error,counterexample\n`flatmap(thing_to_list/1, List)`.\n\nExpression has type: [term()]\nContext expected type: string()\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} @@ -12,10 +12,9 @@ {"path":"app_a/src/app_a_lists.erl","line":595,"char":29,"code":"ELP","severity":"error","name":"eqWAlizer: recursive_constraint","original":null,"replacement":null,"description":"```lang=error,counterexample\n\nRecursive constraint: DeepList\n```\n\n> [docs on `recursive_constraint`](https://fb.me/eqwalizer_errors#recursive_constraint)","docPath":null} {"path":"app_a/src/app_a_lists.erl","line":613,"char":29,"code":"ELP","severity":"error","name":"eqWAlizer: recursive_constraint","original":null,"replacement":null,"description":"```lang=error,counterexample\n\nRecursive constraint: DeepList\n```\n\n> [docs on `recursive_constraint`](https://fb.me/eqwalizer_errors#recursive_constraint)","docPath":null} {"path":"app_a/src/app_a_lists.erl","line":1114,"char":36,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"H3","replacement":null,"description":"```lang=error,counterexample\n`H3`.\n\nExpression has type: term()\nContext expected type: [term()]\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/src/app_a_lists.erl","line":1305,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"filtermap(F, L)","replacement":null,"description":"```lang=error,counterexample\n`filtermap(F, L)`.\n\nExpression has type: [term()]\nContext expected type: [T | X]\n```\n```\nBecause in the expression's type:\n [\n Here the type is: term()\n Context expects type: T | X\n No candidate matches in the expected union.\n ]\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/src/app_a_lists.erl","line":1305,"char":15,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"F","replacement":null,"description":"```lang=error,counterexample\n`F`.\n\nExpression has type: fun((T) -> boolean() | {'true', X})\nContext expected type: fun((term()) -> boolean() | {'true', term()})\n```\n```\nBecause in the expression's type:\n fun((\n Here the type is: term()\n Context expects type: T\n ) -> boolean() | {'true', X})\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} +{"path":"app_a/src/app_a_lists.erl","line":1305,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"filtermap(F, L)","replacement":null,"description":"```lang=error,counterexample\n`filtermap(F, L)`.\n\nExpression has type: [term()]\nContext expected type: [T | X]\n```\n```\nBecause in the expression's type:\n [\n Here the type is: term()\n Context expects type: T | X\n No candidate matches in the expected union.\n ]\n\n------------------------------ Detailed message ------------------------------\n\n [term()] is not compatible with [T | X]\n because\n term() is not compatible with T | X\n because\n term() is not compatible with T\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} +{"path":"app_a/src/app_a_lists.erl","line":1305,"char":15,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"F","replacement":null,"description":"```lang=error,counterexample\n`F`.\n\nExpression has type: fun((T) -> boolean() | {'true', X})\nContext expected type: fun((term()) -> boolean() | {'true', term()})\n```\n```\nBecause in the expression's type:\n fun((\n Here the type is: term()\n Context expects type: T\n ) -> boolean() | {'true', X})\n\n------------------------------ Detailed message ------------------------------\n\n fun((T) -> boolean() | {'true', X}) is not compatible with fun((term()) -> boolean() | {'true', term()})\n because\n term() is not compatible with T\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/src/app_a_mod2.erl","line":22,"char":1,"code":"ELP","severity":"error","name":"eqWAlizer: type_alias_is_non_productive","original":null,"replacement":null,"description":"```lang=error,counterexample\n\nrecursive type invalid/0 is not productive\n```\n\n> [docs on `type_alias_is_non_productive`](https://fb.me/eqwalizer_errors#type_alias_is_non_productive)","docPath":null} {"path":"app_a/src/app_a_mod2.erl","line":31,"char":9,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'an_atom'","replacement":null,"description":"```lang=error,counterexample\n`'an_atom'`.\n\nExpression has type: 'an_atom'\nContext expected type: number()\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/test/app_a_test_helpers.erl","line":6,"char":11,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'wrong_ret'","replacement":null,"description":"```lang=error,counterexample\n`'wrong_ret'`.\n\nExpression has type: 'wrong_ret'\nContext expected type: 'error'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/test/app_a_test_helpers_not_opted_in.erl","line":5,"char":11,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'error'","replacement":null,"description":"```lang=error,counterexample\n`'error'`.\n\nExpression has type: 'error'\nContext expected type: 'ok'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_b/src/app_b.erl","line":16,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"L","replacement":null,"description":"```lang=error,counterexample\n`L`.\n\nExpression has type: [T]\nContext expected type: T\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} diff --git a/crates/elp/src/resources/test/standard/eqwalize_app_a.jsonl b/crates/elp/src/resources/test/standard/eqwalize_app_a.jsonl index 943c4a231d..f56ea404dc 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_app_a.jsonl +++ b/crates/elp/src/resources/test/standard/eqwalize_app_a.jsonl @@ -2,6 +2,6 @@ {"path":"app_a/src/app_a.erl","line":14,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'error'","replacement":null,"description":"```lang=error,counterexample\n`'error'`.\n\nExpression has type: 'error'\nContext expected type: 'ok'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/src/app_a.erl","line":18,"char":13,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'an_atom'","replacement":null,"description":"```lang=error,counterexample\n`'an_atom'`.\n\nExpression has type: 'an_atom'\nContext expected type: number()\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/src/app_a.erl","line":56,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: redundant_fixme","original":null,"replacement":null,"description":"```lang=error,counterexample\n\nredundant fixme\n```\n\n> [docs on `redundant_fixme`](https://fb.me/eqwalizer_errors#redundant_fixme)","docPath":null} -{"path":"app_a/src/app_a.erl","line":78,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: #{k_extra => term(), k_ok => term(), k_req1 => term(), k_req2 => term(), k_wrong1 => pid(), k_wrong2 => pid()}\nContext expected type: #{k_ok => term(), k_req1 := atom(), k_req2 := atom(), k_req3 := atom(), k_wrong1 => atom(), k_wrong2 => atom()}\n```\n```\nBecause in the expression's type:\n Here the type is: #{k_req2 => ..., k_req1 => ..., ...}\n Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...}\n The type of the expression is missing the following required keys: k_req3, k_req2, k_req1.\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/src/app_a.erl","line":102,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: id(#{a := 'va', b := #{c := #{d => atom()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n```\n```\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n Here the type is: #{d => ..., ...}\n Context expects type: #{d := ..., e := ..., ...}\n The type of the expression is missing the following required keys: d, e.\n , ... }\n , ... }\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/src/app_a.erl","line":125,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n```\n```\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n #{ d =>\n Here the type is: pid()\n Context expects type: atom()\n , ... }\n , ... }\n , ... }\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} +{"path":"app_a/src/app_a.erl","line":78,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: #{k_extra => term(), k_ok => term(), k_req1 => term(), k_req2 => term(), k_wrong1 => pid(), k_wrong2 => pid()}\nContext expected type: #{k_ok => term(), k_req1 := atom(), k_req2 := atom(), k_req3 := atom(), k_wrong1 => atom(), k_wrong2 => atom()}\n```\n```\nBecause in the expression's type:\n Here the type is: #{k_req2 => ..., k_req1 => ..., ...}\n Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...}\n The type of the expression is missing the following required keys: k_req3, k_req2, k_req1.\n\n------------------------------ Detailed message ------------------------------\n\nkeys `k_req1`, `k_req2`, `k_req3` are declared as required in the latter but not in the former\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} +{"path":"app_a/src/app_a.erl","line":102,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: id(#{a := 'va', b := #{c := #{d => atom()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n```\n```\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n Here the type is: #{d => ..., ...}\n Context expects type: #{d := ..., e := ..., ...}\n The type of the expression is missing the following required keys: d, e.\n , ... }\n , ... }\n\n------------------------------ Detailed message ------------------------------\n\n id(#{a := 'va', b := #{c := #{d => atom()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n at key `b`:\n #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{c := #{d => atom()}} is not compatible with #{c := id(#{d := atom(), e := atom()})}\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} +{"path":"app_a/src/app_a.erl","line":125,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"X","replacement":null,"description":"```lang=error,counterexample\n`X`.\n\nExpression has type: id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n```\n```\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n #{ d =>\n Here the type is: pid()\n Context expects type: atom()\n , ... }\n , ... }\n , ... }\n\n------------------------------ Detailed message ------------------------------\n\n id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n at key `b`:\n #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{c := #{d := pid(), e := pid()}} is not compatible with #{c := id(#{d := atom(), e := atom()})}\n```\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} diff --git a/crates/elp/src/resources/test/standard/eqwalize_app_a.pretty b/crates/elp/src/resources/test/standard/eqwalize_app_a.pretty index f5f3065414..3cfdbd0dc2 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_app_a.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_app_a.pretty @@ -44,6 +44,10 @@ Because in the expression's type: Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...} The type of the expression is missing the following required keys: k_req3, k_req2, k_req1. +------------------------------ Detailed message ------------------------------ + +keys `k_req1`, `k_req2`, `k_req3` are declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:102:5 │ @@ -64,6 +68,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d => atom()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d => atom()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:125:5 │ @@ -85,4 +100,15 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d := pid(), e := pid()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + 7 ERRORS diff --git a/crates/elp/src/resources/test/standard/eqwalize_app_a_lists_fast.pretty b/crates/elp/src/resources/test/standard/eqwalize_app_a_lists_fast.pretty index 8c93bd01fe..f61a47edfe 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_app_a_lists_fast.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_app_a_lists_fast.pretty @@ -50,6 +50,14 @@ Because in the expression's type: No candidate matches in the expected union. ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [T | X] + because + term() is not compatible with T | X + because + term() is not compatible with T + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -67,4 +75,10 @@ Because in the expression's type: Context expects type: T ) -> boolean() | {'true', X}) +------------------------------ Detailed message ------------------------------ + + fun((T) -> boolean() | {'true', X}) is not compatible with fun((term()) -> boolean() | {'true', term()}) + because + term() is not compatible with T + 7 ERRORS diff --git a/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics.pretty b/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics.pretty index 482195c7ab..472665ffe8 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics.pretty @@ -44,6 +44,10 @@ Because in the expression's type: Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...} The type of the expression is missing the following required keys: k_req3, k_req2, k_req1. +------------------------------ Detailed message ------------------------------ + +keys `k_req1`, `k_req2`, `k_req3` are declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:102:5 │ @@ -64,6 +68,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d => atom()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d => atom()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:125:5 │ @@ -85,6 +100,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d := pid(), e := pid()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_errors_generated.erl:8:10 │ @@ -145,6 +171,14 @@ Because in the expression's type: No candidate matches in the expected union. ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [T | X] + because + term() is not compatible with T | X + because + term() is not compatible with T + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -162,6 +196,12 @@ Because in the expression's type: Context expects type: T ) -> boolean() | {'true', X}) +------------------------------ Detailed message ------------------------------ + + fun((T) -> boolean() | {'true', X}) is not compatible with fun((term()) -> boolean() | {'true', term()}) + because + term() is not compatible with T + error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) ┌─ app_a/src/app_a_mod2.erl:22:1 │ diff --git a/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_gen.pretty b/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_gen.pretty index 482195c7ab..472665ffe8 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_gen.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_gen.pretty @@ -44,6 +44,10 @@ Because in the expression's type: Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...} The type of the expression is missing the following required keys: k_req3, k_req2, k_req1. +------------------------------ Detailed message ------------------------------ + +keys `k_req1`, `k_req2`, `k_req3` are declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:102:5 │ @@ -64,6 +68,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d => atom()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d => atom()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:125:5 │ @@ -85,6 +100,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d := pid(), e := pid()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_errors_generated.erl:8:10 │ @@ -145,6 +171,14 @@ Because in the expression's type: No candidate matches in the expected union. ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [T | X] + because + term() is not compatible with T | X + because + term() is not compatible with T + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -162,6 +196,12 @@ Because in the expression's type: Context expects type: T ) -> boolean() | {'true', X}) +------------------------------ Detailed message ------------------------------ + + fun((T) -> boolean() | {'true', X}) is not compatible with fun((term()) -> boolean() | {'true', term()}) + because + term() is not compatible with T + error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) ┌─ app_a/src/app_a_mod2.erl:22:1 │ diff --git a/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_gen_rebar.pretty b/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_gen_rebar.pretty index 043aa00af0..6782313a4a 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_gen_rebar.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_gen_rebar.pretty @@ -44,6 +44,10 @@ Because in the expression's type: Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...} The type of the expression is missing the following required keys: k_req3, k_req2, k_req1. +------------------------------ Detailed message ------------------------------ + +keys `k_req1`, `k_req2`, `k_req3` are declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:102:5 │ @@ -64,6 +68,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d => atom()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d => atom()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:125:5 │ @@ -85,6 +100,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d := pid(), e := pid()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/test/app_a_SUITE.erl:18:5 │ @@ -153,6 +179,14 @@ Because in the expression's type: No candidate matches in the expected union. ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [T | X] + because + term() is not compatible with T | X + because + term() is not compatible with T + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -170,6 +204,12 @@ Because in the expression's type: Context expects type: T ) -> boolean() | {'true', X}) +------------------------------ Detailed message ------------------------------ + + fun((T) -> boolean() | {'true', X}) is not compatible with fun((term()) -> boolean() | {'true', term()}) + because + term() is not compatible with T + error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) ┌─ app_a/src/app_a_mod2.erl:22:1 │ @@ -192,12 +232,4 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: 'wrong_ret' Context expected type: 'error' -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ app_a/test/app_a_test_helpers_not_opted_in.erl:5:11 - │ -5 │ fail() -> error. - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - -20 ERRORS +19 ERRORS diff --git a/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_rebar.pretty b/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_rebar.pretty index 043aa00af0..6782313a4a 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_rebar.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_rebar.pretty @@ -44,6 +44,10 @@ Because in the expression's type: Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...} The type of the expression is missing the following required keys: k_req3, k_req2, k_req1. +------------------------------ Detailed message ------------------------------ + +keys `k_req1`, `k_req2`, `k_req3` are declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:102:5 │ @@ -64,6 +68,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d => atom()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d => atom()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:125:5 │ @@ -85,6 +100,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d := pid(), e := pid()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/test/app_a_SUITE.erl:18:5 │ @@ -153,6 +179,14 @@ Because in the expression's type: No candidate matches in the expected union. ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [T | X] + because + term() is not compatible with T | X + because + term() is not compatible with T + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -170,6 +204,12 @@ Because in the expression's type: Context expects type: T ) -> boolean() | {'true', X}) +------------------------------ Detailed message ------------------------------ + + fun((T) -> boolean() | {'true', X}) is not compatible with fun((term()) -> boolean() | {'true', term()}) + because + term() is not compatible with T + error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) ┌─ app_a/src/app_a_mod2.erl:22:1 │ @@ -192,12 +232,4 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: 'wrong_ret' Context expected type: 'error' -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ app_a/test/app_a_test_helpers_not_opted_in.erl:5:11 - │ -5 │ fail() -> error. - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - -20 ERRORS +19 ERRORS diff --git a/crates/elp/src/resources/test/standard/eqwalize_target_diagnostics.pretty b/crates/elp/src/resources/test/standard/eqwalize_target_diagnostics.pretty index 482195c7ab..472665ffe8 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_target_diagnostics.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_target_diagnostics.pretty @@ -44,6 +44,10 @@ Because in the expression's type: Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...} The type of the expression is missing the following required keys: k_req3, k_req2, k_req1. +------------------------------ Detailed message ------------------------------ + +keys `k_req1`, `k_req2`, `k_req3` are declared as required in the latter but not in the former + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:102:5 │ @@ -64,6 +68,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d => atom()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d => atom()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a.erl:125:5 │ @@ -85,6 +100,17 @@ Because in the expression's type: , ... } , ... } +------------------------------ Detailed message ------------------------------ + + id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + at key `b`: + #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}} + because + #{c := #{d := pid(), e := pid()}} is not compatible with #{c := id(#{d := atom(), e := atom()})} + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_errors_generated.erl:8:10 │ @@ -145,6 +171,14 @@ Because in the expression's type: No candidate matches in the expected union. ] +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [T | X] + because + term() is not compatible with T | X + because + term() is not compatible with T + error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -162,6 +196,12 @@ Because in the expression's type: Context expects type: T ) -> boolean() | {'true', X}) +------------------------------ Detailed message ------------------------------ + + fun((T) -> boolean() | {'true', X}) is not compatible with fun((term()) -> boolean() | {'true', term()}) + because + term() is not compatible with T + error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) ┌─ app_a/src/app_a_mod2.erl:22:1 │ diff --git a/crates/elp/src/resources/test/xref/unavailable_type.stdout b/crates/elp/src/resources/test/xref/unavailable_type.stdout deleted file mode 100644 index 688be17de3..0000000000 --- a/crates/elp/src/resources/test/xref/unavailable_type.stdout +++ /dev/null @@ -1,5 +0,0 @@ -Reporting all diagnostics codes -module specified: unavailable_type -Diagnostics reported: -app_a/src/unavailable_type.erl:10:43-10:58::[Warning] [W0059] The type 'app_c:my_type_c/0' is defined in application 'app_c', but the application is not a dependency of 'app_a' (defined in 'root//xref:app_a'). -app_a/src/unavailable_type.erl:6:16-6:31::[Warning] [W0059] The type 'app_c:my_type_c/0' is defined in application 'app_c', but the application is not a dependency of 'app_a' (defined in 'root//xref:app_a'). diff --git a/crates/elp/src/server.rs b/crates/elp/src/server.rs index 98890640bc..4914cf9f3f 100644 --- a/crates/elp/src/server.rs +++ b/crates/elp/src/server.rs @@ -24,7 +24,7 @@ use anyhow::bail; use capabilities::text_document_symbols_dynamic_registration; use crossbeam_channel::Receiver; use crossbeam_channel::Sender; -use crossbeam_channel::select_biased; +use crossbeam_channel::select; use dispatch::NotificationDispatcher; use elp_eqwalizer::ast::Pos; use elp_eqwalizer::types::Type; @@ -434,28 +434,27 @@ impl Server { } fn next_event(&self) -> Option { - // Select the next event, in order of priority. - // If multiple operations are ready at the same time, the - // operation nearest to the front of the list is always selected. - select_biased! { - // We want to send progress messages as soon as possible - recv(self.progress.receiver()) -> msg => { - Some(Event::Task(Task::Progress(msg.unwrap()))) - } - - // Ditto telemetry - recv(telemetry::receiver()) -> msg => { - Some(Event::Telemetry(msg.unwrap())) - } - + select! { recv(self.connection.receiver) -> msg => { msg.ok().map(Event::Lsp) } + recv(self.vfs_loader.receiver) -> msg => { + Some(Event::Vfs(msg.unwrap())) + } + recv(self.task_pool.receiver) -> msg => { Some(Event::Task(msg.unwrap())) } + recv(self.progress.receiver()) -> msg => { + Some(Event::Task(Task::Progress(msg.unwrap()))) + } + + recv(telemetry::receiver()) -> msg => { + Some(Event::Telemetry(msg.unwrap())) + } + recv (self.project_pool.receiver) -> msg => { Some(Event::Task(msg.unwrap())) } @@ -468,16 +467,6 @@ impl Server { Some(Event::Task(msg.unwrap())) } - // We put vfs loader events last, they run with all - // available threads, we do not want to starve the - // other sources. - // Note: when we do process one, we will coalesce - // all pending vfs loader events into a single main loop turn - recv(self.vfs_loader.receiver) -> msg => { - Some(Event::Vfs(msg.unwrap())) - } - - } } @@ -518,7 +507,6 @@ impl Server { a_file_per_project = FxHashSet::default(); } spinner.end(); - log::info!(target: FILE_WATCH_LOGGER_NAME, "Project reloading complete"); self.reload_manager .lock() .set_reload_done(a_file_per_project); @@ -570,7 +558,6 @@ impl Server { let to_reload = self.reload_manager.lock().query_changed_files(); if let Some(to_reload) = to_reload { - log::info!(target: FILE_WATCH_LOGGER_NAME, "Asking for project reload"); let query_config = self.reload_manager.lock().set_reload_active(); self.reload_project(to_reload, query_config); } @@ -635,16 +622,7 @@ impl Server { .diagnostics .diagnostics_for(*file_id) .iter() - .map(|d| { - let vfs = self.vfs.clone(); - ide_to_lsp_diagnostic(&line_index, d, |related_file_id| { - // Get the line index and URL for the related file - let url = file_id_to_url(&vfs.read(), related_file_id); - let snapshot = self.snapshot(); - let line_index = snapshot.analysis.line_index(related_file_id).ok()?; - Some(((*line_index).clone(), url)) - }) - }) + .map(|d| ide_to_lsp_diagnostic(&line_index, &url, d)) .collect(); self.send_notification::( @@ -848,20 +826,11 @@ impl Server { Arc::make_mut(&mut this.diagnostics) .clear(file_id); if let Ok(line_index) = analysis.line_index(file_id) { - let vfs = this.vfs.clone(); diagnostics = this .diagnostics .diagnostics_for(file_id) .iter() - .map(|d| { - let snapshot = this.snapshot(); - ide_to_lsp_diagnostic(&line_index, d, |related_file_id| { - // Get the line index and URL for the related file - let url = file_id_to_url(&vfs.read(), related_file_id); - let line_index = snapshot.analysis.line_index(related_file_id).ok()?; - Some(((*line_index).clone(), url)) - }) - }) + .map(|d| ide_to_lsp_diagnostic(&line_index, &url, d)) .collect() } } @@ -1053,10 +1022,8 @@ impl Server { log::info!(target: FILE_WATCH_LOGGER_NAME, "VFS change:{}:{}", &opened, &path); } if !opened { - // This call will add the file to the changed_files, - // picked up in `process_changes`, only if the new - // content is different from the current, checked via - // a hash. + // This call will add the file to the changed_files, picked + // up in `process_changes`, if it has changed. vfs.set_file_contents(path, contents); } } @@ -1429,11 +1396,9 @@ impl Server { fn switch_workspaces(&mut self, spinner: &Spinner, new_projects: Vec) -> Result<()> { if new_projects.is_empty() { log::info!("nothing new, not switching workspaces"); - log::info!(target: FILE_WATCH_LOGGER_NAME, "nothing new, not switching workspaces"); return Ok(()); } log::info!("will switch workspaces"); - log::info!(target: FILE_WATCH_LOGGER_NAME, "will switch workspaces"); let mut projects: Vec = self.projects.iter().cloned().collect(); for project in new_projects { @@ -1464,16 +1429,6 @@ impl Server { self.file_set_config = folders.file_set_config; - let watch_count = folders.watch.len(); - let buck_query_config = self.reload_manager.lock().get_query_config(); - let data = serde_json::json!({ - "app_count": project_apps.all_apps.len(), - "project_count": projects.len(), - "watch_count": watch_count, - "query_config": buck_query_config.to_string(), - }); - telemetry::send("project_size".to_string(), data); - let register_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { watchers: folders.watch, }; @@ -1848,13 +1803,9 @@ impl Server { } for (err, uri) in errors { if let Some(uri) = uri { - // It is not possible to put line breaks or other formatting in the message - let error_message = format!( - "Look at `Details` in the buck UI for more information, there is likely an invalid BUCK file: {err}" - ); let params = lsp_types::ShowMessageRequestParams { typ: lsp_types::MessageType::ERROR, - message: error_message, + message: err, actions: Some(vec![MessageActionItem { title: "Open Buck UI".to_string(), properties: HashMap::from_iter(vec![( @@ -1923,7 +1874,6 @@ impl Server { if !self.reload_manager.lock().ok_to_switch_workspace() { // There are other changed files, abort this reload, to // allow the next one. - log::info!(target: FILE_WATCH_LOGGER_NAME, "Not switching workspaces, more changed config files"); return Ok(false); } spinner.report("Switching to loaded projects".to_string()); @@ -2073,7 +2023,7 @@ impl Server { }; for (_, _, file_id) in module_index.iter_own() { - match snapshot.analysis.should_eqwalize(file_id) { + match snapshot.analysis.should_eqwalize(file_id, false) { Ok(true) => { files.push(file_id); } diff --git a/crates/elp/src/server/setup.rs b/crates/elp/src/server/setup.rs index 4b8615e07c..6dade5c677 100644 --- a/crates/elp/src/server/setup.rs +++ b/crates/elp/src/server/setup.rs @@ -33,7 +33,6 @@ use super::FILE_WATCH_LOGGER_NAME; use super::logger::LspLogger; use crate::config::Config; use crate::from_json; -// @fb-only: use crate::meta_only::get_log_dir; use crate::server::Handle; use crate::server::LOGGER_NAME; use crate::server::Server; @@ -126,9 +125,8 @@ impl ServerSetup { // Set up a logger for tracking down why we are seeing stale // results when branches are switched, as per T218973130 - // @fb-only: let log_dir = get_log_dir(); - let log_dir = format!("{}/elp", std::env::temp_dir().display()); // @oss-only - let _ = fs::create_dir_all(&log_dir); + let log_dir = "/tmp/elp"; + let _ = fs::create_dir_all(log_dir); let log_file = format!( "{}/elp_file_watch_reports-{}.log", log_dir, diff --git a/crates/elp/src/snapshot.rs b/crates/elp/src/snapshot.rs index 69ea6b97e0..e79251f73a 100644 --- a/crates/elp/src/snapshot.rs +++ b/crates/elp/src/snapshot.rs @@ -36,11 +36,9 @@ use parking_lot::Mutex; use parking_lot::RwLock; use serde::Deserialize; use serde::Serialize; -use vfs::AnchoredPathBuf; use crate::config::Config; use crate::convert; -use crate::convert::url_from_abs_path; use crate::line_endings::LineEndings; use crate::mem_docs::MemDocs; use crate::server::EqwalizerTypes; @@ -188,14 +186,6 @@ impl Snapshot { self.line_ending_map.read()[&id] } - pub(crate) fn anchored_path(&self, path: &AnchoredPathBuf) -> Option { - let mut base = self.vfs.read().file_path(path.anchor).clone(); - base.pop(); - let path = base.join(&path.path)?; - let path = path.as_path()?; - Some(url_from_abs_path(path)) - } - pub fn update_cache_for_file( &self, file_id: FileId, @@ -203,7 +193,7 @@ impl Snapshot { ) -> Result<()> { let _ = self.analysis.def_map(file_id)?; if optimize_for_eqwalizer { - let should_eqwalize = self.analysis.should_eqwalize(file_id)?; + let should_eqwalize = self.analysis.should_eqwalize(file_id, false)?; if should_eqwalize { let _ = self.analysis.module_ast(file_id)?; } @@ -252,7 +242,7 @@ impl Snapshot { let file_ids: Vec = module_index .iter_own() .filter_map(|(_, _, file_id)| { - if let Ok(true) = self.analysis.should_eqwalize(file_id) { + if let Ok(true) = self.analysis.should_eqwalize(file_id, false) { Some(file_id) } else { None diff --git a/crates/elp/src/to_proto.rs b/crates/elp/src/to_proto.rs index 3e5b1fd1e1..f9263cfcab 100644 --- a/crates/elp/src/to_proto.rs +++ b/crates/elp/src/to_proto.rs @@ -10,7 +10,6 @@ //! Conversion of rust-analyzer specific types to lsp_types equivalents. -use std::mem; use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering; @@ -48,11 +47,10 @@ use elp_ide::elp_ide_db::elp_base_db::FileId; use elp_ide::elp_ide_db::elp_base_db::FilePosition; use elp_ide::elp_ide_db::elp_base_db::FileRange; use elp_ide::elp_ide_db::rename::RenameError; -use elp_ide::elp_ide_db::source_change::FileSystemEdit; use elp_ide::elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::Indel; -use elp_ide_db::text_edit::TextEdit; use elp_project_model::ProjectBuildData; +use elp_text_edit::Indel; +use elp_text_edit::TextEdit; use lsp_types::CompletionItemTag; use lsp_types::Hover; use lsp_types::HoverContents; @@ -123,9 +121,9 @@ pub(crate) fn optional_versioned_text_document_identifier( pub(crate) fn text_document_edit( snap: &Snapshot, file_id: FileId, - text_document: lsp_types::OptionalVersionedTextDocumentIdentifier, edit: TextEdit, ) -> Result { + let text_document = optional_versioned_text_document_identifier(snap, file_id); let line_index = snap.analysis.line_index(file_id)?; let line_endings = snap.line_endings(file_id); let edits: Vec> = edit @@ -133,131 +131,34 @@ pub(crate) fn text_document_edit( .map(|it| lsp_types::OneOf::Left(text_edit(&line_index, line_endings, it))) .collect(); + // if snap.analysis.is_library_file(file_id)? && snap.config.change_annotation_support() { + // for edit in &mut edits { + // edit.annotation_id = Some(outside_workspace_annotation_id()) + // } + // } Ok(lsp_types::TextDocumentEdit { text_document, edits, }) } -pub(crate) fn text_document_ops( - snap: &Snapshot, - file_system_edit: FileSystemEdit, -) -> Cancellable> { - let mut ops = Vec::new(); - match file_system_edit { - FileSystemEdit::CreateFile { - dst, - initial_contents, - } => { - if let Some(uri) = snap.anchored_path(&dst) { - let create_file = lsp_types::ResourceOp::Create(lsp_types::CreateFile { - uri: uri.clone(), - options: None, - annotation_id: None, - }); - ops.push(lsp_types::DocumentChangeOperation::Op(create_file)); - if !initial_contents.is_empty() { - let text_document = - lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version: None }; - let text_edit = lsp_types::TextEdit { - range: lsp_types::Range::default(), - new_text: initial_contents, - }; - let edit_file = lsp_types::TextDocumentEdit { - text_document, - edits: vec![lsp_types::OneOf::Left(text_edit)], - }; - ops.push(lsp_types::DocumentChangeOperation::Edit(edit_file)); - } - } else { - log::warn!("create file failed: {:?}", dst); - } - } - FileSystemEdit::MoveFile { src, dst } => { - if let Some(new_uri) = snap.anchored_path(&dst) { - let old_uri = snap.file_id_to_url(src); - let rename_file = lsp_types::RenameFile { - old_uri, - new_uri, - options: None, - annotation_id: None, - }; - ops.push(lsp_types::DocumentChangeOperation::Op( - lsp_types::ResourceOp::Rename(rename_file), - )) - } else { - log::warn!("rename file failed: {:?} -> {:?}", src, dst); - } - } - } - Ok(ops) -} - pub(crate) fn workspace_edit( snap: &Snapshot, - mut source_change: SourceChange, + source_change: SourceChange, ) -> Result { - let mut document_changes: Vec = Vec::new(); - - // This is copying RA's order of operations, first file creates, - // then edits, then file moves. - - // This allows us to apply edits to the file once it has - // moved. Except we have no FileId at that point - for op in &mut source_change.file_system_edits { - if let FileSystemEdit::CreateFile { - dst, - initial_contents, - } = op - { - // replace with a placeholder to avoid cloning the edit - let op = FileSystemEdit::CreateFile { - dst: dst.clone(), - initial_contents: mem::take(initial_contents), - }; - let ops = text_document_ops(snap, op)?; - document_changes.extend_from_slice(&ops); - } - } - - for op in source_change.file_system_edits { - if !matches!(op, FileSystemEdit::CreateFile { .. }) { - let ops = text_document_ops(snap, op)?; - document_changes.extend_from_slice(&ops); - } - } - + let mut edits: Vec<_> = vec![]; for (file_id, edit) in source_change.source_file_edits { - let text_document = optional_versioned_text_document_identifier(snap, file_id); - let edit = text_document_edit(snap, file_id, text_document, edit)?; - document_changes.push(lsp_types::DocumentChangeOperation::Edit( - lsp_types::TextDocumentEdit { - text_document: edit.text_document, - edits: edit.edits.into_iter().collect(), - }, - )); + // let edit = snippet_text_document_edit(snap, source_change.is_snippet, file_id, edit)?; + let edit = text_document_edit(snap, file_id, edit)?; + edits.push(lsp_types::TextDocumentEdit { + text_document: edit.text_document, + edits: edit.edits.into_iter().collect(), + }); } - - // Edits on renamed files. The LineIndex from the original can be used. - for (file_ref, edit) in source_change.new_file_edits { - if let Some(uri) = snap.anchored_path(&file_ref.clone().into()) { - let version = snap.url_file_version(&uri); - let text_document = lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version }; - let edit = text_document_edit(snap, file_ref.anchor, text_document, edit)?; - document_changes.push(lsp_types::DocumentChangeOperation::Edit( - lsp_types::TextDocumentEdit { - text_document: edit.text_document, - edits: edit.edits.into_iter().collect(), - }, - )); - } else { - log::warn!("new file edit failed: {:?}", file_ref); - } - } - + let document_changes = lsp_types::DocumentChanges::Edits(edits); let workspace_edit = lsp_types::WorkspaceEdit { changes: None, - document_changes: Some(lsp_types::DocumentChanges::Operations(document_changes)), + document_changes: Some(document_changes), change_annotations: None, }; Ok(workspace_edit) @@ -281,6 +182,10 @@ pub(crate) fn code_action( ) -> Result { let mut res = lsp_types::CodeAction { title: assist.label.to_string(), + // group: assist + // .group + // .filter(|_| snap.config.code_action_group()) + // .map(|gr| gr.0), kind: Some(code_action_kind(assist.id.1)), edit: None, is_preferred: None, diff --git a/crates/elp/tests/slow-tests/buck_tests.rs b/crates/elp/tests/slow-tests/buck_tests.rs index 91f2b234d9..e76fdb8bad 100644 --- a/crates/elp/tests/slow-tests/buck_tests.rs +++ b/crates/elp/tests/slow-tests/buck_tests.rs @@ -31,7 +31,7 @@ mod tests { #[test] #[ignore] fn test_success_case() { - let path_str = "../../test/test_projects/buck_tests"; + let path_str = "../../test_projects/buck_tests"; let path: PathBuf = path_str.into(); let cli = Fake::default(); @@ -65,7 +65,7 @@ mod tests { let ast = analysis.module_ast(file_id).unwrap(); assert_eq!(ast.errors, vec![]); let eq_enabled = analysis - .is_eqwalizer_enabled(file_id) + .is_eqwalizer_enabled(file_id, false) .unwrap_or_else(|_| panic!("Failed to check if eqwalizer enabled for {module}")); assert_eq!(eq_enabled, eqwalizer_enabled); let project_data = analysis.project_data(file_id).unwrap(); @@ -76,7 +76,7 @@ mod tests { #[test] #[ignore] fn test_load_buck_targets() { - let path_str = "../../test/test_projects/buck_tests"; + let path_str = "../../test_projects/buck_tests"; let path: PathBuf = path_str.into(); let (elp_config, buck_config) = diff --git a/crates/elp/tests/slow-tests/main.rs b/crates/elp/tests/slow-tests/main.rs index e256ce2c62..98455e8850 100644 --- a/crates/elp/tests/slow-tests/main.rs +++ b/crates/elp/tests/slow-tests/main.rs @@ -36,7 +36,7 @@ use crate::support::diagnostic_project; fn test_run_mock_lsp() { if cfg!(feature = "buck") { let workspace_root = AbsPathBuf::assert( - Utf8Path::new(env!("CARGO_WORKSPACE_DIR")).join("test/test_projects/end_to_end"), + Utf8Path::new(env!("CARGO_WORKSPACE_DIR")).join("test_projects/end_to_end"), ); // Sanity check @@ -70,7 +70,7 @@ fn test_run_mock_lsp() { } ], "textDocument": { - "uri": "file:///[..]/test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", + "uri": "file:///[..]/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", "version": 0 } } @@ -99,7 +99,7 @@ fn test_run_mock_lsp() { } ], "textDocument": { - "uri": "file:///[..]/test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", + "uri": "file:///[..]/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", "version": 0 } } @@ -128,7 +128,7 @@ fn test_run_mock_lsp() { } ], "textDocument": { - "uri": "file:///[..]/test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", + "uri": "file:///[..]/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", "version": 0 } } @@ -157,7 +157,7 @@ fn test_run_mock_lsp() { } ], "textDocument": { - "uri": "file:///[..]/test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", + "uri": "file:///[..]/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", "version": 0 } } @@ -175,7 +175,7 @@ fn test_run_mock_lsp() { fn test_e2e_eqwalizer_module() { if cfg!(feature = "buck") { let workspace_root = AbsPathBuf::assert( - Utf8Path::new(env!("CARGO_WORKSPACE_DIR")).join("test/test_projects/standard"), + Utf8Path::new(env!("CARGO_WORKSPACE_DIR")).join("test_projects/standard"), ); // Sanity check @@ -268,7 +268,7 @@ fn test_e2e_eqwalizer_module() { "codeDescription": { "href": "https://fb.me/eqwalizer_errors#incompatible_types" }, - "message": "`X`.\nExpression has type: #{k_extra => term(), k_ok => term(), k_req1 => term(), k_req2 => term(), k_wrong1 => pid(), k_wrong2 => pid()}\nContext expected type: #{k_ok => term(), k_req1 := atom(), k_req2 := atom(), k_req3 := atom(), k_wrong1 => atom(), k_wrong2 => atom()}\n\nBecause in the expression's type:\n Here the type is: #{k_req2 => ..., k_req1 => ..., ...}\n Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...}\n The type of the expression is missing the following required keys: k_req3, k_req2, k_req1.\n See https://fb.me/eqwalizer_errors#incompatible_types", + "message": "`X`.\nExpression has type: #{k_extra => term(), k_ok => term(), k_req1 => term(), k_req2 => term(), k_wrong1 => pid(), k_wrong2 => pid()}\nContext expected type: #{k_ok => term(), k_req1 := atom(), k_req2 := atom(), k_req3 := atom(), k_wrong1 => atom(), k_wrong2 => atom()}\n\nBecause in the expression's type:\n Here the type is: #{k_req2 => ..., k_req1 => ..., ...}\n Context expects type: #{k_req3 := ..., k_req2 := ..., k_req1 := ..., ...}\n The type of the expression is missing the following required keys: k_req3, k_req2, k_req1.\n\n------------------------------ Detailed message ------------------------------\n\nkeys `k_req1`, `k_req2`, `k_req3` are declared as required in the latter but not in the former\n See https://fb.me/eqwalizer_errors#incompatible_types", "range": { "end": { "character": 5, @@ -287,7 +287,7 @@ fn test_e2e_eqwalizer_module() { "codeDescription": { "href": "https://fb.me/eqwalizer_errors#incompatible_types" }, - "message": "`X`.\nExpression has type: id(#{a := 'va', b := #{c := #{d => atom()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n Here the type is: #{d => ..., ...}\n Context expects type: #{d := ..., e := ..., ...}\n The type of the expression is missing the following required keys: d, e.\n , ... }\n , ... }\n See https://fb.me/eqwalizer_errors#incompatible_types", + "message": "`X`.\nExpression has type: id(#{a := 'va', b := #{c := #{d => atom()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n Here the type is: #{d => ..., ...}\n Context expects type: #{d := ..., e := ..., ...}\n The type of the expression is missing the following required keys: d, e.\n , ... }\n , ... }\n\n------------------------------ Detailed message ------------------------------\n\n id(#{a := 'va', b := #{c := #{d => atom()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n at key `b`:\n #{a := 'va', b := #{c := #{d => atom()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{c := #{d => atom()}} is not compatible with #{c := id(#{d := atom(), e := atom()})}\n See https://fb.me/eqwalizer_errors#incompatible_types", "range": { "end": { "character": 5, @@ -306,7 +306,7 @@ fn test_e2e_eqwalizer_module() { "codeDescription": { "href": "https://fb.me/eqwalizer_errors#incompatible_types" }, - "message": "`X`.\nExpression has type: id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n #{ d =>\n Here the type is: pid()\n Context expects type: atom()\n , ... }\n , ... }\n , ... }\n See https://fb.me/eqwalizer_errors#incompatible_types", + "message": "`X`.\nExpression has type: id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}})\nContext expected type: #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n\nBecause in the expression's type:\n #{ b =>\n #{ c =>\n #{ d =>\n Here the type is: pid()\n Context expects type: atom()\n , ... }\n , ... }\n , ... }\n\n------------------------------ Detailed message ------------------------------\n\n id(#{a := 'va', b := #{c := #{d := pid(), e := pid()}}}) is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n at key `b`:\n #{a := 'va', b := #{c := #{d := pid(), e := pid()}}} is not compatible with #{a := 'va', b := #{c := id(#{d := atom(), e := atom()})}}\n because\n #{c := #{d := pid(), e := pid()}} is not compatible with #{c := id(#{d := atom(), e := atom()})}\n See https://fb.me/eqwalizer_errors#incompatible_types", "range": { "end": { "character": 5, @@ -321,7 +321,7 @@ fn test_e2e_eqwalizer_module() { "source": "eqWAlizer" } ], - "uri": "file:///[..]/test/test_projects/standard/app_a/src/app_a.erl", + "uri": "file:///[..]/test_projects/standard/app_a/src/app_a.erl", "version": 0 }"#]], ); @@ -334,7 +334,7 @@ fn test_e2e_eqwalizer_module() { // #[test] // fn test_e2e_eqwalizer_header() { // let workspace_root = -// AbsPathBuf::assert(Path::new(env!("CARGO_WORKSPACE_DIR")).join("test/test_projects/standard")); +// AbsPathBuf::assert(Path::new(env!("CARGO_WORKSPACE_DIR")).join("test_projects/standard")); // // Sanity check // assert!(std::fs::metadata(&workspace_root).is_ok()); diff --git a/crates/elp/tests/slow-tests/support.rs b/crates/elp/tests/slow-tests/support.rs index 2c794f6246..bf482a7816 100644 --- a/crates/elp/tests/slow-tests/support.rs +++ b/crates/elp/tests/slow-tests/support.rs @@ -408,7 +408,7 @@ impl Drop for TestServer { struct Timeout; fn recv_timeout(receiver: &Receiver) -> Result, Timeout> { - let timeout = Duration::from_mins(1); + let timeout = Duration::from_secs(60); select! { recv(receiver) -> msg => Ok(msg.ok()), recv(after(timeout)) -> _ => Err(Timeout), diff --git a/crates/eqwalizer/src/ipc.rs b/crates/eqwalizer/src/ipc.rs index 4d10d663ec..30b1dae582 100644 --- a/crates/eqwalizer/src/ipc.rs +++ b/crates/eqwalizer/src/ipc.rs @@ -159,8 +159,8 @@ pub struct IpcHandle { _child_for_drop: JodChild, } -const WRITE_TIMEOUT: Duration = Duration::from_mins(4); -const READ_TIMEOUT: Duration = Duration::from_mins(4); +const WRITE_TIMEOUT: Duration = Duration::from_secs(240); +const READ_TIMEOUT: Duration = Duration::from_secs(240); impl IpcHandle { fn spawn_cmd(cmd: &mut Command) -> Result { diff --git a/crates/eqwalizer/src/lib.rs b/crates/eqwalizer/src/lib.rs index 54333570fd..e6f49460a1 100644 --- a/crates/eqwalizer/src/lib.rs +++ b/crates/eqwalizer/src/lib.rs @@ -244,9 +244,7 @@ impl EqwalizerExe { impl Eqwalizer { fn cmd(&self) -> Command { let mut exe = EQWALIZER_EXE.lock(); - // This check is for the temporary directory being removed by an external process. - // As such, it is only applicable if ther *is* a temporary directory. - if exe._file.is_some() && !exe.cmd.is_file() { + if !exe.cmd.is_file() { log::error!("Eqwalizer exe has disappeared, recreating"); // We have a problem with the eqwalizer exe file, recreate it *exe = EqwalizerExe::ensure_exe(); diff --git a/crates/erlang_service/src/lib.rs b/crates/erlang_service/src/lib.rs index 072f439db3..16020d78f6 100644 --- a/crates/erlang_service/src/lib.rs +++ b/crates/erlang_service/src/lib.rs @@ -59,13 +59,12 @@ lazy_static! { pub static ref ESCRIPT: RwLock = RwLock::new("escript".to_string()); } -#[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub enum DiagnosticLocation { Normal(TextRange), Included { - file_attribute_location: TextRange, // Location of file_attribute for included file in the file compiled abstract forms - error_path: PathBuf, // Path of the file containing the error. It could be via a deeply nested include - error_location: TextRange, // Location of the error in the included file + directive_location: TextRange, // Location of include directive in the file compiled + error_location: TextRange, // Location of the error in the included file }, } @@ -736,8 +735,7 @@ fn decode_errors(buf: &[u8]) -> Result> { eetf::Term::decode(buf)? .as_match(pattern::VarList(( - Str, // path - Str, // error path + Str, pattern::Or(( (pattern::U32, pattern::U32), // Normal location pattern::FixList(((pattern::U32, pattern::U32), (pattern::U32, pattern::U32))), // Location in include file @@ -749,7 +747,7 @@ fn decode_errors(buf: &[u8]) -> Result> { .map_err(|err| anyhow!("Failed to decode errors: {:?}", err)) .map(|res| { res.into_iter() - .map(|(path, error_path, position, msg, code)| ParseError { + .map(|(path, position, msg, code)| ParseError { path: path.into(), location: match position { pattern::Union3::A((a, b)) => Some(DiagnosticLocation::Normal( @@ -757,8 +755,7 @@ fn decode_errors(buf: &[u8]) -> Result> { )), pattern::Union3::B(((a, b), (c, d))) => { Some(DiagnosticLocation::Included { - file_attribute_location: safe_textrange(a.into(), b.into()), - error_path: error_path.into(), + directive_location: safe_textrange(a.into(), b.into()), error_location: safe_textrange(c.into(), d.into()), }) } diff --git a/crates/hir/src/body.rs b/crates/hir/src/body.rs index 9ebac17c66..2f4968b7ba 100644 --- a/crates/hir/src/body.rs +++ b/crates/hir/src/body.rs @@ -43,7 +43,6 @@ use crate::FormList; use crate::FunctionClause; use crate::FunctionClauseId; use crate::InFile; -use crate::IncludeAttributeId; use crate::Literal; use crate::Name; use crate::NameArity; @@ -1156,24 +1155,6 @@ pub type ExprSource = InFileAstPtr; pub type MacroSource = InFileAstPtr; -/// Lightweight diagnostic for body lowering -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum BodyDiagnostic { - /// Macro failed to expand/resolve - UnresolvedMacro(MacroSource), - /// Include failed to resolve - UnresolvedInclude(InFile), -} - -impl BodyDiagnostic { - pub fn file_id(&self) -> FileId { - match self { - BodyDiagnostic::UnresolvedMacro(src) => src.file_id(), - BodyDiagnostic::UnresolvedInclude(include) => include.file_id, - } - } -} - #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct InFileAstPtr(InFile>) where @@ -1250,7 +1231,6 @@ pub struct BodySourceMap { term_map: FxHashMap, term_map_back: ArenaMap, macro_map: FxHashMap, - diagnostics: Vec, } impl BodySourceMap { @@ -1312,10 +1292,6 @@ impl BodySourceMap { .get(&InFileAstPtr::from_infile(call)) .copied() } - - pub fn diagnostics(&self) -> &[BodyDiagnostic] { - &self.diagnostics - } } #[cfg(test)] diff --git a/crates/hir/src/body/lower.rs b/crates/hir/src/body/lower.rs index 4abf0737b2..85c3378930 100644 --- a/crates/hir/src/body/lower.rs +++ b/crates/hir/src/body/lower.rs @@ -38,7 +38,6 @@ use crate::AttributeBody; use crate::BasedInteger; use crate::BinarySeg; use crate::Body; -use crate::BodyDiagnostic; use crate::BodySourceMap; use crate::CRClause; use crate::CallTarget; @@ -117,10 +116,6 @@ pub struct Ctx<'a> { // This means we need to lower a Var specially when processing a SSR // template, where if it has a prefix of `_@` it is a placeholder. in_ssr: bool, - // Track when we're lowering the RHS of a define preprocessor directive - in_macro_rhs: bool, - // Diagnostics collected during body lowering - diagnostics: Vec, } #[derive(Debug)] @@ -157,8 +152,6 @@ impl<'a> Ctx<'a> { starting_stack_size: 1, macro_source_map: FxHashMap::default(), in_ssr: false, - in_macro_rhs: false, - diagnostics: Vec::new(), } } @@ -223,7 +216,6 @@ impl<'a> Ctx<'a> { assert!(self.body.origin.is_valid()); self.body.shrink_to_fit(); - self.source_map.diagnostics = self.diagnostics; (Arc::new(self.body), self.source_map) } @@ -409,9 +401,7 @@ impl<'a> Ctx<'a> { let replacement = define.replacement(); match replacement { Some(MacroDefReplacement::Expr(expr)) => { - self.in_macro_rhs = true; let expr = self.lower_expr(&expr); - self.in_macro_rhs = false; let (body, source_map) = self.finish(); (DefineBody { body, expr }, source_map) } @@ -822,9 +812,6 @@ impl<'a> Ctx<'a> { ) }) .unwrap_or_else(|| { - // Record diagnostic for unresolved macro - self.record_unresolved_macro(call); - let expansion = self.alloc_pat(Pat::Missing, Some(expr)); let args = call .args() @@ -1182,9 +1169,6 @@ impl<'a> Ctx<'a> { }) .flatten() .unwrap_or_else(|| { - // Record diagnostic for unresolved macro - self.record_unresolved_macro(call); - call.args() .iter() .flat_map(|args| args.args()) @@ -1416,8 +1400,8 @@ impl<'a> Ctx<'a> { let exprs = self.lower_lc_exprs(lc.lc_exprs()); self.alloc_expr(Expr::Comprehension { builder, exprs }, Some(expr)) } - ast::ExprMax::MacroCallExpr(call) => { - self.resolve_macro(call, |this, source, replacement| match replacement { + ast::ExprMax::MacroCallExpr(call) => self + .resolve_macro(call, |this, source, replacement| match replacement { MacroReplacement::BuiltIn(built_in) => { this.lower_built_in_macro(built_in).map(|literal| { let expr_id = this.alloc_expr(Expr::Literal(literal), None); @@ -1480,9 +1464,6 @@ impl<'a> Ctx<'a> { ) }) .unwrap_or_else(|| { - // Record diagnostic for unresolved macro - self.record_unresolved_macro(call); - let expansion = self.alloc_expr(Expr::Missing, Some(expr)); let args = call .args() @@ -1499,8 +1480,7 @@ impl<'a> Ctx<'a> { }, Some(expr), ) - }) - } + }), ast::ExprMax::MacroString(_) => self.alloc_expr(Expr::Missing, Some(expr)), ast::ExprMax::ParenExpr(paren_expr) => { if let Some(inner_expr) = paren_expr.expr() { @@ -2010,9 +1990,6 @@ impl<'a> Ctx<'a> { }) .flatten() .unwrap_or_else(|| { - // Record diagnostic for unresolved macro - self.record_unresolved_macro(call); - call.args() .iter() .flat_map(|args| args.args()) @@ -2193,9 +2170,6 @@ impl<'a> Ctx<'a> { ) }) .unwrap_or_else(|| { - // Record diagnostic for unresolved macro - self.record_unresolved_macro(call); - let expansion = self.alloc_type_expr(TypeExpr::Missing, Some(expr)); let args = call .args() @@ -2562,9 +2536,6 @@ impl<'a> Ctx<'a> { ) }) .unwrap_or_else(|| { - // Record diagnostic for unresolved macro - self.record_unresolved_macro(call); - let expansion = self.alloc_term(Term::Missing, Some(expr)); let args = call .args() @@ -3026,23 +2997,6 @@ impl<'a> Ctx<'a> { self.macro_source_map.insert(name, source); } - fn record_unresolved_macro(&mut self, call: &ast::MacroCallExpr) { - // If we're in a macro RHS and this is ?FUNCTION_NAME or ?FUNCTION_ARITY, skip the diagnostic - if self.in_macro_rhs { - let macro_name = self.macro_call_name(call.name()); - if let MacroCallName::Var(var) = macro_name { - let name_str = var.as_string(self.db.upcast()); - if name_str == "FUNCTION_NAME" || name_str == "FUNCTION_ARITY" { - return; - } - } - } - - let source = InFileAstPtr::new(self.curr_file_id(), AstPtr::new(call).cast().unwrap()); - self.diagnostics - .push(BodyDiagnostic::UnresolvedMacro(source)); - } - fn curr_file_id(&self) -> FileId { self.macro_stack[self.macro_stack_id].file_id } diff --git a/crates/hir/src/body/scope.rs b/crates/hir/src/body/scope.rs index 4ac4e366d8..dd1da23e94 100644 --- a/crates/hir/src/body/scope.rs +++ b/crates/hir/src/body/scope.rs @@ -865,7 +865,7 @@ mod tests { f() -> As = [1,2,3], Bs = [4,5,6], - [{X,Y, ~} || X <- As && Y <- Bs] + [{X,Y}~ || X <- As && Y <- Bs] . ", &["Y", "X", "As", "Bs"], diff --git a/crates/hir/src/body/tests.rs b/crates/hir/src/body/tests.rs index eab603a76d..c616df812d 100644 --- a/crates/hir/src/body/tests.rs +++ b/crates/hir/src/body/tests.rs @@ -448,7 +448,6 @@ foo(#record.field) -> #record.field. fn record() { check( r#" -//- expect_parse_errors foo1(#record{field = 1}) -> #record{field = A + B}. foo2(#record{field}) -> #record{field = }. "#, @@ -474,7 +473,6 @@ foo2(#record{field}) -> #record{field = }. fn record_update() { check( r#" -//- expect_parse_errors foo1() -> Expr#record{field = undefined}. foo2() -> Expr#record{field = ok, missing = }. "#, @@ -559,7 +557,7 @@ fn case() { r#" foo() -> case 1 + 2 of - X when X andalso true; X =< 100, X >= 5 -> ok; + X when X andalso true; X <= 100, X >= 5 -> ok; _ -> error end. "#, @@ -568,7 +566,7 @@ foo() -> case (1 + 2) of X when (X andalso true); - (X =< 100), + (X < 100), (X >= 5) -> ok; @@ -838,7 +836,6 @@ foo() -> fn parens() { check( r#" -//- expect_parse_errors foo((ok), ()) -> (ok), (). @@ -998,7 +995,6 @@ foo(fun() -> ok end) -> ok. fn invalid_comprehension() { check( r#" -//- expect_parse_errors foo(<>, [Byte || Byte <- List]]) -> ok. "#, expect![[r#" @@ -1396,7 +1392,6 @@ fn call_type_erlang_bif() { fn record_type() { check( r#" -//- expect_parse_errors -type foo1() :: #record{}. -type foo2(B) :: #record{a :: integer(), b :: B}. -type foo3() :: #record{a ::}. @@ -1534,7 +1529,6 @@ fn record_definition() { fn simple_term() { check( r#" -//- expect_parse_errors -foo(ok). -missing_value(). "#, @@ -2699,7 +2693,6 @@ fn verbatim_binary_sigil_in_type() { // Note: \~ gets replaced by ~ in the fixture parsing check( r#" - //- expect_parse_errors -type foo() :: \~B"ab\"c\"\d"). -type bar() :: "hello"). "#, @@ -2730,7 +2723,6 @@ fn verbatim_binary_sigil_in_term() { fn lowering_with_error_nodes() { check( r#" - //- expect_parse_errors f(1a) -> ok begin 1 end. "#, expect![[r#" @@ -2997,10 +2989,8 @@ fn tree_print_record() { #[test] fn tree_print_attribute() { - // TODO: fix wild attribute parsing, T246546041, to remove expect_parse_errors check_ast( r#" - //- expect_parse_errors -wild(foo, []). -compile({inline, [foo/1]}). -compile({a/a, 1/1}). diff --git a/crates/hir/src/body/tree_print.rs b/crates/hir/src/body/tree_print.rs index d6b956690f..1123c46b75 100644 --- a/crates/hir/src/body/tree_print.rs +++ b/crates/hir/src/body/tree_print.rs @@ -15,8 +15,6 @@ use std::fmt; use std::fmt::Write as _; use std::str; -use elp_base_db::FileId; - use super::DefineBody; use super::FoldBody; use super::RecordBody; @@ -35,15 +33,11 @@ use crate::ComprehensionExpr; use crate::Define; use crate::Expr; use crate::ExprId; -use crate::FormIdx; use crate::FunType; use crate::FunctionBody; use crate::FunctionClauseBody; -use crate::FunctionDefId; -use crate::InFile; use crate::ListType; use crate::Literal; -use crate::PPDirective; use crate::Pat; use crate::PatId; use crate::Record; @@ -56,7 +50,6 @@ use crate::TermId; use crate::TypeAlias; use crate::TypeExpr; use crate::TypeExprId; -use crate::db::DefDatabase; use crate::db::InternDatabase; use crate::expr::Guards; use crate::expr::MaybeExpr; @@ -339,63 +332,6 @@ pub(crate) fn print_ssr(db: &dyn InternDatabase, body: &SsrBody) -> String { printer.result() } -#[allow(dead_code)] // This is used for debugging -pub fn print_form_list(db: &dyn DefDatabase, file_id: FileId, strategy: Strategy) -> String { - let form_list = db.file_form_list(file_id); - let dbi: &dyn InternDatabase = db; - form_list - .forms() - .iter() - .flat_map(|&form_idx| -> Option { - match form_idx { - FormIdx::FunctionClause(function_id) => { - let body = - db.function_body(InFile::new(file_id, FunctionDefId::new(function_id))); - Some(body.tree_print(dbi, strategy)) - } - FormIdx::TypeAlias(type_alias_id) => { - let type_alias = &form_list[type_alias_id]; - let body = db.type_body(InFile::new(file_id, type_alias_id)); - Some(body.tree_print(dbi, type_alias)) - } - FormIdx::Spec(spec_id) => { - let spec = SpecOrCallback::Spec(form_list[spec_id].clone()); - let body = db.spec_body(InFile::new(file_id, spec_id)); - Some(body.tree_print(dbi, spec)) - } - FormIdx::Callback(callback_id) => { - let spec = SpecOrCallback::Callback(form_list[callback_id].clone()); - let body = db.callback_body(InFile::new(file_id, callback_id)); - Some(body.tree_print(dbi, spec)) - } - FormIdx::Record(record_id) => { - let body = db.record_body(InFile::new(file_id, record_id)); - Some(body.print(dbi, &form_list, record_id)) - } - FormIdx::Attribute(attribute_id) => { - let attribute = AnyAttribute::Attribute(form_list[attribute_id].clone()); - let body = db.attribute_body(InFile::new(file_id, attribute_id)); - Some(body.print(dbi, attribute)) - } - FormIdx::CompileOption(attribute_id) => { - let attribute = AnyAttribute::CompileOption(form_list[attribute_id].clone()); - let body = db.compile_body(InFile::new(file_id, attribute_id)); - Some(body.tree_print(dbi, attribute)) - } - FormIdx::PPDirective(pp) => match form_list[pp] { - PPDirective::Define(define) => { - let body = db.define_body(InFile::new(file_id, define)); - Some(body.tree_print(dbi, &form_list[define])) - } - _ => None, - }, - _ => None, - } - }) - .collect::>() - .join("") -} - struct Printer<'a> { db: &'a dyn InternDatabase, body: &'a FoldBody<'a>, @@ -1587,8 +1523,13 @@ mod tests { use expect_test::Expect; use expect_test::expect; + use crate::AnyAttribute; + use crate::FormIdx; + use crate::FunctionDefId; + use crate::InFile; + use crate::SpecOrCallback; use crate::Strategy; - use crate::body::tree_print::print_form_list; + use crate::db::DefDatabase; use crate::fold::MacroStrategy; use crate::fold::ParenStrategy; use crate::test_db::TestDB; @@ -1605,7 +1546,52 @@ mod tests { #[track_caller] fn check_with_strategy(strategy: Strategy, fixture: &str, expect: Expect) { let (db, file_id) = TestDB::with_single_file(fixture); - let pretty = print_form_list(&db, file_id, strategy); + let form_list = db.file_form_list(file_id); + let pretty = form_list + .forms() + .iter() + .flat_map(|&form_idx| -> Option { + match form_idx { + FormIdx::FunctionClause(function_id) => { + let body = + db.function_body(InFile::new(file_id, FunctionDefId::new(function_id))); + Some(body.tree_print(&db, strategy)) + } + FormIdx::TypeAlias(type_alias_id) => { + let type_alias = &form_list[type_alias_id]; + let body = db.type_body(InFile::new(file_id, type_alias_id)); + Some(body.tree_print(&db, type_alias)) + } + FormIdx::Spec(spec_id) => { + let spec = SpecOrCallback::Spec(form_list[spec_id].clone()); + let body = db.spec_body(InFile::new(file_id, spec_id)); + Some(body.tree_print(&db, spec)) + } + FormIdx::Callback(callback_id) => { + let spec = SpecOrCallback::Callback(form_list[callback_id].clone()); + let body = db.callback_body(InFile::new(file_id, callback_id)); + Some(body.tree_print(&db, spec)) + } + FormIdx::Record(record_id) => { + let body = db.record_body(InFile::new(file_id, record_id)); + Some(body.print(&db, &form_list, record_id)) + } + FormIdx::Attribute(attribute_id) => { + let attribute = AnyAttribute::Attribute(form_list[attribute_id].clone()); + let body = db.attribute_body(InFile::new(file_id, attribute_id)); + Some(body.print(&db, attribute)) + } + FormIdx::CompileOption(attribute_id) => { + let attribute = + AnyAttribute::CompileOption(form_list[attribute_id].clone()); + let body = db.compile_body(InFile::new(file_id, attribute_id)); + Some(body.tree_print(&db, attribute)) + } + _ => None, + } + }) + .collect::>() + .join(""); expect.assert_eq(pretty.trim_start()); } @@ -2013,16 +1999,6 @@ mod tests { foo() -> ?EXPR(2). "#, expect![[r#" - -define(EXPR/1, - Expr<2>:Expr::BinaryOp { - lhs - Expr<0>:Literal(Integer(1)) - rhs - Expr<1>:Expr::Var(X) - op - ArithOp(Add), - } - ). function: foo/0 Clause { pats @@ -2340,7 +2316,7 @@ mod tests { r#" foo() -> case 1 + 2 of - X when X andalso true; X =< 100, X >= 5 -> ok; + X when X andalso true; X <= 100, X >= 5 -> ok; _ -> error end. "#, @@ -2381,7 +2357,7 @@ mod tests { rhs Expr<8>:Literal(Integer(100)) op - CompOp(Ord { ordering: Less, strict: false }), + CompOp(Ord { ordering: Less, strict: true }), }, Expr<12>:Expr::BinaryOp { lhs @@ -3114,7 +3090,6 @@ mod tests { fn type_record() { check( r#" - //- expect_parse_errors -type foo1() :: #record{}. -type foo2(B) :: #record{a :: integer(), b :: B}. -type foo3() :: #record{a ::}. @@ -3445,103 +3420,4 @@ mod tests { "#]], ); } - - #[test] - fn top_level_macro() { - // Note: we currently lower a macro as an Expr only. - // We have special processing in lower_clause_or_macro_body - // to deal with top level macros, at the ast level. - check( - r#" - -define(FOO(X), baz() -> X). - -define(BAR(X), {X}). - ?FOO(42). - foo() -> ?BAR(42). - "#, - expect![[r#" - -define(FOO/1, - Expr<0>:Expr::Missing - ). - - -define(BAR/1, - Expr<1>:Expr::Tuple { - Expr<0>:Expr::Var(X), - } - ). - function: baz/0 - Clause { - pats - guards - exprs - Expr<2>:Literal(Integer(42)), - }. - function: foo/0 - Clause { - pats - guards - exprs - Expr<4>:Expr::MacroCall { - args - Expr<3>:Literal(Integer(42)), - macro_def - Some(InFile { file_id: FileId(0), value: Idx::(1) }) - expansion - Expr<2>:Expr::Tuple { - Expr<1>:Literal(Integer(42)), - } - }, - }. - "#]], - ); - } - - #[test] - fn top_level_forms() { - check( - r#" - //- expect_parse_errors - -module(main). - bug - -compile([export_all]). - -wild('foo'). - -type foo() :: ok. - -spec bar() -> ok. - bar() -> ok. - -callback baz() -> ok. - -record(rec, {f}). - "#, - expect![[r#" - -compile( - Term::List { - exprs - Literal(Atom('export_all')), - tail - } - ). - - -wild(foo). - - -type foo() :: Literal(Atom('ok')). - - -spec bar - () -> - Literal(Atom('ok')). - function: bar/0 - Clause { - pats - guards - exprs - Expr<1>:Literal(Atom('ok')), - }. - - -callback baz - () -> - Literal(Atom('ok')). - - -record(rec, { - f - }). - "#]], - ); - } } diff --git a/crates/hir/src/expr.rs b/crates/hir/src/expr.rs index 114930efe3..adf3dea349 100644 --- a/crates/hir/src/expr.rs +++ b/crates/hir/src/expr.rs @@ -581,26 +581,6 @@ impl CallTarget { } } } - - pub fn range(&self, sema: &Semantic, body: &Body) -> Option { - match self { - CallTarget::Local { name } => { - let name_any_id = AnyExprId::TypeExpr(*name); - body.range_for_any(sema, name_any_id) - } - CallTarget::Remote { module, name, .. } => { - let module_any_id = AnyExprId::TypeExpr(*module); - let name_any_id = AnyExprId::TypeExpr(*name); - - let name_range = body.range_for_any(sema, name_any_id)?; - if let Some(module_range) = body.range_for_any(sema, module_any_id) { - module_range.cover(name_range) - } else { - Some(name_range) - } - } - } - } } impl CallTarget { diff --git a/crates/hir/src/fold.rs b/crates/hir/src/fold.rs index 59b12be6fd..78cd442592 100644 --- a/crates/hir/src/fold.rs +++ b/crates/hir/src/fold.rs @@ -339,7 +339,7 @@ pub enum ParentId { #[derive(Debug)] pub struct AnyCallBackCtx<'a> { - pub in_macro: Option<(HirIdx, Option>)>, + pub in_macro: Option, pub parents: &'a Vec, pub item_id: AnyExprId, pub item: AnyExpr, @@ -426,7 +426,7 @@ pub struct FoldCtx<'a, T> { body_origin: BodyOrigin, body: &'a FoldBody<'a>, strategy: Strategy, - macro_stack: Vec<(HirIdx, Option>)>, + macro_stack: Vec, parents: Vec, callback: AnyCallBack<'a, T>, } @@ -594,7 +594,7 @@ impl<'a, T> FoldCtx<'a, T> { .do_fold_pat(pat_id, initial) } - fn in_macro(&self) -> Option<(HirIdx, Option>)> { + fn in_macro(&self) -> Option { self.macro_stack.first().copied() } @@ -752,19 +752,16 @@ impl<'a, T> FoldCtx<'a, T> { crate::Expr::MacroCall { expansion, args, - macro_def, + macro_def: _, macro_name: _, } => { if self.strategy.macros == MacroStrategy::DoNotExpand { self.do_fold_exprs(args, acc) } else { - self.macro_stack.push(( - HirIdx { - body_origin: self.body_origin, - idx: AnyExprId::Expr(expr_id), - }, - *macro_def, - )); + self.macro_stack.push(HirIdx { + body_origin: self.body_origin, + idx: AnyExprId::Expr(expr_id), + }); let e = self.do_fold_expr(*expansion, acc); self.macro_stack.pop(); e @@ -953,19 +950,16 @@ impl<'a, T> FoldCtx<'a, T> { crate::Pat::MacroCall { expansion, args, - macro_def, + macro_def: _, macro_name: _, } => { if self.strategy.macros == MacroStrategy::DoNotExpand { self.do_fold_exprs(args, acc) } else { - self.macro_stack.push(( - HirIdx { - body_origin: self.body_origin, - idx: AnyExprId::Pat(pat_id), - }, - *macro_def, - )); + self.macro_stack.push(HirIdx { + body_origin: self.body_origin, + idx: AnyExprId::Pat(pat_id), + }); let e = self.do_fold_pat(*expansion, acc); self.macro_stack.pop(); e @@ -1171,19 +1165,16 @@ impl<'a, T> FoldCtx<'a, T> { TypeExpr::MacroCall { expansion, args, - macro_def, + macro_def: _, macro_name: _, } => { if self.strategy.macros == MacroStrategy::DoNotExpand { self.do_fold_exprs(args, acc) } else { - self.macro_stack.push(( - HirIdx { - body_origin: self.body_origin, - idx: AnyExprId::TypeExpr(type_expr_id), - }, - *macro_def, - )); + self.macro_stack.push(HirIdx { + body_origin: self.body_origin, + idx: AnyExprId::TypeExpr(type_expr_id), + }); let e = self.do_fold_type_expr(*expansion, acc); self.macro_stack.pop(); e @@ -2221,9 +2212,7 @@ bar() -> #[test] fn traverse_attribute() { - // TODO: fix wild attribute parsing, T246546041, to remove expect_parse_errors let fixture_str = r#" - //- expect_parse_errors -module(foo). -wild(r1, {f1, f~oo}). "#; diff --git a/crates/hir/src/form_list.rs b/crates/hir/src/form_list.rs index a1431d7506..560befbb4b 100644 --- a/crates/hir/src/form_list.rs +++ b/crates/hir/src/form_list.rs @@ -188,11 +188,6 @@ impl FormList { self.data.type_aliases.iter() } - /// Returns the -record declarations in the file - pub fn records(&self) -> impl Iterator { - self.data.records.iter() - } - pub fn find_form(&self, form: &ast::Form) -> Option { self.map_back.get(&AstPtr::new(form)).copied() } @@ -655,23 +650,6 @@ impl IncludeAttribute { pub fn range(&self, db: &dyn DefDatabase, file_id: FileId) -> TextRange { self.form_id().get_ast(db, file_id).syntax().text_range() } - - pub fn file_range(&self, db: &dyn DefDatabase, file_id: FileId) -> TextRange { - let form = self.form_id().get_ast(db, file_id); - match form { - ast::Form::PreprocessorDirective(ast::PreprocessorDirective::PpInclude(pp_include)) => { - pp_include - .include_range() - .unwrap_or_else(|| pp_include.text_range()) - } - ast::Form::PreprocessorDirective(ast::PreprocessorDirective::PpIncludeLib( - pp_include_lib, - )) => pp_include_lib - .include_range() - .unwrap_or_else(|| pp_include_lib.text_range()), - _ => form.syntax().text_range(), - } - } } /// -deprecated diff --git a/crates/hir/src/form_list/tests.rs b/crates/hir/src/form_list/tests.rs index 79f542fd0d..00a5ec4020 100644 --- a/crates/hir/src/form_list/tests.rs +++ b/crates/hir/src/form_list/tests.rs @@ -318,7 +318,6 @@ fn export() { fn import() { check( r#" -//- expect_parse_errors -import(, []). -import(foo, []). -import(foo, [foo/1]). diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 751a2f4907..11d4b40971 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -35,7 +35,6 @@ mod test_db; pub use body::AnyAttribute; pub use body::AttributeBody; pub use body::Body; -pub use body::BodyDiagnostic; pub use body::BodyOrigin; pub use body::BodySourceMap; pub use body::DefineBody; @@ -155,7 +154,7 @@ pub use name::MacroName; pub use name::Name; pub use name::NameArity; pub use name::known; -// @fb-only: pub use name::meta_only; +// @fb-only pub use sema::AtomDef; pub use sema::CallDef; pub use sema::DefinitionOrReference; @@ -232,10 +231,6 @@ impl HirIdx { } } - pub fn file_id(&self) -> FileId { - self.body_origin.file_id() - } - /// This function is used to print a representation of the HIR AST /// corresponding to the given `HirIdx`. It is used for debugging /// and testing. diff --git a/crates/hir/src/module_data.rs b/crates/hir/src/module_data.rs index 0420e19bb6..b081cbd539 100644 --- a/crates/hir/src/module_data.rs +++ b/crates/hir/src/module_data.rs @@ -615,9 +615,8 @@ impl TypeAliasDef { } pub fn name_range(&self, db: &dyn SourceDatabase) -> Option { - let type_name = self.source(db).type_name()?; - let name = type_name.name()?; - Some(name.syntax().text_range()) + let range = self.source(db).type_name()?.syntax().text_range(); + Some(range) } /// This information is used for completion. diff --git a/crates/hir/src/name.rs b/crates/hir/src/name.rs index f94f139d38..00ce2f89f1 100644 --- a/crates/hir/src/name.rs +++ b/crates/hir/src/name.rs @@ -10,7 +10,7 @@ //! See [`Name`]. -// @fb-only: pub mod meta_only; +// @fb-only use std::borrow::Cow; use std::collections::HashSet; diff --git a/crates/hir/src/sema.rs b/crates/hir/src/sema.rs index 68577d2a2e..78a7db7c3c 100644 --- a/crates/hir/src/sema.rs +++ b/crates/hir/src/sema.rs @@ -102,7 +102,7 @@ use crate::resolver::Resolution; use crate::resolver::Resolver; mod find; -// @fb-only: pub mod meta_only; +// @fb-only pub mod to_def; pub struct ModuleIter(Arc); @@ -1006,28 +1006,6 @@ impl Semantic<'_> { // Folds end // ----------------------------------------------------------------- - pub fn bound_vars_by_function( - &self, - file_id: FileId, - ) -> FxHashMap> { - let bound_vars = self.bound_vars_in_pattern_diagnostic(file_id); - let mut bound_vars_by_function: FxHashMap> = - FxHashMap::default(); - bound_vars.iter().for_each(|(function_id, pat_id, _var)| { - bound_vars_by_function - .entry(function_id.value) - .and_modify(|vars| { - vars.insert(*pat_id); - }) - .or_insert_with(|| { - let mut vars = FxHashSet::default(); - vars.insert(*pat_id); - vars - }); - }); - bound_vars_by_function - } - pub fn bound_vars_in_pattern_diagnostic( &self, file_id: FileId, diff --git a/crates/hir/src/sema/to_def.rs b/crates/hir/src/sema/to_def.rs index 01d17278a2..5918054fc5 100644 --- a/crates/hir/src/sema/to_def.rs +++ b/crates/hir/src/sema/to_def.rs @@ -42,7 +42,7 @@ use crate::macro_exp; use crate::macro_exp::BuiltInMacro; use crate::macro_exp::MacroExpCtx; use crate::resolver::Resolver; -// @fb-only: use crate::sema::meta_only; +// @fb-only pub trait ToDef: Clone { type Def; @@ -567,7 +567,7 @@ pub fn resolve_call_target( let fn_name: Name = sema.db.lookup_atom(body[*name].as_atom()?); let mo = None; // @oss-only - // @fb-only: meta_only::resolve_handle_call_target(sema, arity, file_id, &module_name, &fn_name); + // @fb-only if let Some(r) = mo { r } else { @@ -885,183 +885,12 @@ fn add_dynamic_call_patterns(patterns: &mut FxHashMap Self { - Self { - index, - arg_type: ModuleArgType::Atom, - } - } - - /// Creates a pattern where the argument is a list of module atoms. - pub const fn list(index: usize) -> Self { - Self { - index, - arg_type: ModuleArgType::List, - } - } - - /// Creates a pattern where the argument can be either a single atom or a list. - pub const fn atom_or_list(index: usize) -> Self { - Self { - index, - arg_type: ModuleArgType::AtomOrList, - } - } - - /// Returns true if this pattern accepts a single atom. - pub const fn accepts_atom(&self) -> bool { - matches!( - self.arg_type, - ModuleArgType::Atom | ModuleArgType::AtomOrList - ) - } - - /// Returns true if this pattern accepts a list of atoms. - pub const fn accepts_list(&self) -> bool { - matches!( - self.arg_type, - ModuleArgType::List | ModuleArgType::AtomOrList - ) - } -} - -fn add_module_argument_patterns(patterns: &mut FxHashMap) { - // Each entry follows the format: - // (module, function, arity) -> ModuleArgPattern - // - // Where: - // module: Module name (Some("meck"), Some("application"), etc.) - // function: Function name as string literal (e.g., "new", "get_env") - // arity: Number of arguments this function pattern expects - // ModuleArgPattern: Contains the argument index and the expected type - // - // All indexes are 0-based. - - // meck - mocking library - // meck:new/2 accepts either a single module atom or a list of modules - patterns.insert((Some("meck"), "called", 3), ModuleArgPattern::atom(0)); - patterns.insert((Some("meck"), "called", 4), ModuleArgPattern::atom(0)); - patterns.insert((Some("meck"), "capture", 5), ModuleArgPattern::atom(1)); - patterns.insert((Some("meck"), "capture", 6), ModuleArgPattern::atom(1)); - patterns.insert( - (Some("meck"), "delete", 3), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "delete", 4), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "expect", 3), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "expect", 4), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "expects", 2), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert((Some("meck"), "history", 1), ModuleArgPattern::atom(0)); - patterns.insert((Some("meck"), "history", 2), ModuleArgPattern::atom(0)); - patterns.insert((Some("meck"), "loop", 4), ModuleArgPattern::atom_or_list(0)); - patterns.insert((Some("meck"), "new", 1), ModuleArgPattern::atom_or_list(0)); - patterns.insert((Some("meck"), "new", 2), ModuleArgPattern::atom_or_list(0)); - patterns.insert((Some("meck"), "num_calls", 3), ModuleArgPattern::atom(0)); - patterns.insert((Some("meck"), "num_calls", 4), ModuleArgPattern::atom(0)); - patterns.insert( - (Some("meck"), "reset", 1), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "sequence", 4), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "unload", 1), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "validate", 1), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert((Some("meck"), "wait", 4), ModuleArgPattern::atom(0)); - patterns.insert((Some("meck"), "wait", 5), ModuleArgPattern::atom(1)); - patterns.insert((Some("meck"), "wait", 6), ModuleArgPattern::atom(1)); - - // code module - module loading and management - // These functions from the Erlang stdlib take module() as their argument - patterns.insert((Some("code"), "load_file", 1), ModuleArgPattern::atom(0)); - patterns.insert( - (Some("code"), "ensure_loaded", 1), - ModuleArgPattern::atom(0), - ); - patterns.insert((Some("code"), "delete", 1), ModuleArgPattern::atom(0)); - patterns.insert((Some("code"), "purge", 1), ModuleArgPattern::atom(0)); - patterns.insert((Some("code"), "soft_purge", 1), ModuleArgPattern::atom(0)); - patterns.insert((Some("code"), "is_loaded", 1), ModuleArgPattern::atom(0)); - patterns.insert( - (Some("code"), "get_object_code", 1), - ModuleArgPattern::atom(0), - ); - patterns.insert((Some("code"), "module_md5", 1), ModuleArgPattern::atom(0)); - patterns.insert((Some("code"), "is_sticky", 1), ModuleArgPattern::atom(0)); -} - -// Lazy static initialization for the patterns maps +// Lazy static initialization for the patterns map lazy_static! { static ref DYNAMIC_CALL_PATTERNS: FxHashMap = { let mut patterns = FxHashMap::default(); add_dynamic_call_patterns(&mut patterns); - // @fb-only: meta_only::add_dynamic_call_patterns(&mut patterns); - patterns - }; - static ref MODULE_ARGUMENT_PATTERNS: FxHashMap = { - let mut patterns = FxHashMap::default(); - add_module_argument_patterns(&mut patterns); - // @fb-only: meta_only::add_module_argument_patterns(&mut patterns); - patterns - }; - /// Combined patterns for module argument positions. - /// Merges dynamic call patterns (that have module_arg_index) with simple module argument patterns. - /// Used by rename operations where we only care about the module argument position. - static ref COMBINED_MODULE_ARG_PATTERNS: FxHashMap = { - let mut patterns: FxHashMap = FxHashMap::default(); - // Add module_arg_index from dynamic call patterns (where present) - for (key, pattern) in DYNAMIC_CALL_PATTERNS.iter() { - if let Some(module_idx) = pattern.module_arg_index { - patterns.insert(*key, ModuleArgPattern::atom(module_idx)); - } - } - // Add from simple module argument patterns - for (key, module_arg_pattern) in MODULE_ARGUMENT_PATTERNS.iter() { - patterns.insert(*key, *module_arg_pattern); - } + // @fb-only patterns }; } @@ -1070,10 +899,6 @@ fn get_dynamic_call_patterns() -> &'static FxHashMap &'static FxHashMap { - &COMBINED_MODULE_ARG_PATTERNS -} - fn look_for_dynamic_call( sema: &Semantic, file_id: FileId, diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index acba8ef642..aba9731379 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml @@ -10,11 +10,12 @@ workspace = true elp_eqwalizer.workspace = true elp_erlang_service.workspace = true elp_ide_assists.workspace = true -elp_ide_db.workspace = true elp_ide_completion.workspace = true +elp_ide_db.workspace = true elp_ide_ssr.workspace = true elp_project_model.workspace = true elp_syntax.workspace = true +elp_text_edit.workspace = true elp_types_db.workspace = true hir.workspace = true diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index d0ae18c158..6cbdd3469c 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs @@ -17,7 +17,7 @@ use elp_syntax::TextRange; use fxhash::FxHashMap; use fxhash::FxHashSet; -// @fb-only: use crate::meta_only; +// @fb-only use crate::runnables::Runnable; use crate::runnables::runnables; @@ -57,11 +57,11 @@ pub struct Link { } #[rustfmt::skip] -// @fb-only: pub(crate) fn annotations(db: &RootDatabase, file_id: FileId) -> Vec { +// @fb-only pub(crate) fn annotations(_db: &RootDatabase, _file_id: FileId) -> Vec { // @oss-only - // @fb-only: let mut annotations = Vec::default(); + // @fb-only let annotations = Vec::default(); // @oss-only - // @fb-only: meta_only::annotations(db, file_id, &mut annotations); + // @fb-only annotations } diff --git a/crates/ide/src/codemod_helpers.rs b/crates/ide/src/codemod_helpers.rs index 2ecd21e82c..e06ceafd61 100644 --- a/crates/ide/src/codemod_helpers.rs +++ b/crates/ide/src/codemod_helpers.rs @@ -573,8 +573,8 @@ pub(crate) fn find_call_in_function( }; if let Some(extra) = check_call(context) { // Got one. - let call_expr_id = if let Some((hir_idx, _macro_def)) = ctx.in_macro { - hir_idx.idx + let call_expr_id = if let Some(expr_id) = ctx.in_macro { + expr_id.idx } else { ctx.item_id }; diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index eb6bae611b..2078335dc3 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs @@ -11,7 +11,6 @@ use std::borrow::Cow; use std::collections::BTreeSet; use std::fmt; -use std::path::Path; use std::sync::Arc; use anyhow::Result; @@ -39,18 +38,15 @@ use elp_ide_db::elp_base_db::FileId; use elp_ide_db::elp_base_db::FileKind; use elp_ide_db::elp_base_db::FileRange; use elp_ide_db::elp_base_db::ProjectId; -use elp_ide_db::elp_base_db::VfsPath; use elp_ide_db::erlang_service::DiagnosticLocation; use elp_ide_db::erlang_service::ParseError; use elp_ide_db::metadata::Kind; use elp_ide_db::metadata::Metadata; use elp_ide_db::metadata::Source; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; use elp_ide_ssr::Match; use elp_ide_ssr::SsrSearchScope; use elp_ide_ssr::match_pattern; -use elp_project_model::AppName; use elp_syntax::NodeOrToken; use elp_syntax::Parse; use elp_syntax::SourceFile; @@ -67,12 +63,11 @@ use elp_syntax::ast::edit::IndentLevel; use elp_syntax::ast::edit::start_of_line; use elp_syntax::label::Label; use elp_syntax::ted::Element; +use elp_text_edit::TextEdit; use elp_types_db::TypedSemantic; use fxhash::FxHashMap; use fxhash::FxHashSet; -use hir::FormIdx; use hir::InFile; -use hir::PPDirective; use hir::Semantic; use hir::db::DefDatabase; use hir::fold::MacroStrategy; @@ -97,13 +92,13 @@ mod application_env; mod atoms_exhaustion; mod binary_string_to_sigil; mod boolean_precedence; -mod bound_variable; mod could_be_a_string_literal; mod cross_node_eval; mod debugging_function; mod dependent_header; mod deprecated_function; mod duplicate_module; +mod edoc; mod effect_free_statement; mod equality_check_with_unnecessary_operator; mod eqwalizer_assists; @@ -113,14 +108,12 @@ mod head_mismatch; mod inefficient_enumerate; mod inefficient_flatlength; mod inefficient_last; -mod lists_reverse_append; mod macro_precedence_suprise; mod map_find_to_syntax; mod map_insertion_to_syntax; mod meck; -// @fb-only: mod meta_only; +// @fb-only mod missing_compile_warn_missing_spec; -mod missing_module; mod missing_separator; mod misspelled_attribute; mod module_mismatch; @@ -132,7 +125,6 @@ mod no_garbage_collect; mod no_nowarn_suppressions; mod no_size; mod nonstandard_integer_formatting; -mod old_edoc_syntax; mod record_tuple_match; mod redundant_assignment; mod replace_call; @@ -140,7 +132,6 @@ mod replace_in_spec; mod sets_version_2; mod simplify_negation; mod trivial_match; -mod unavailable_type; mod undefined_function; mod undefined_macro; mod undocumented_function; @@ -233,9 +224,8 @@ impl Diagnostic { self } - pub(crate) fn as_related(&self, file_id: FileId) -> RelatedInformation { + pub(crate) fn as_related(&self) -> RelatedInformation { RelatedInformation { - file_id, range: self.range, message: self.message.clone(), } @@ -386,10 +376,10 @@ impl Diagnostic { format!( "{}:{}-{}:{}::[{:?}] [{}] {}", - start.line + 1, - start.col_utf16 + 1, - end.line + 1, - end.col_utf16 + 1, + start.line, + start.col_utf16, + end.line, + end.col_utf16, self.severity(use_cli_severity), self.code, self.message @@ -454,7 +444,6 @@ impl Diagnostic { #[derive(Debug, Clone)] pub struct RelatedInformation { - pub file_id: FileId, pub range: TextRange, pub message: String, } @@ -469,10 +458,9 @@ impl fmt::Display for Diagnostic { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Severity { Error, - #[default] Warning, // `WeakWarning` maps onto a Notice warning when used in the LSP // environment, and in VS Code this means it does not show up in @@ -482,6 +470,12 @@ pub enum Severity { Information, } +impl Default for Severity { + fn default() -> Self { + Self::Warning // Pick one + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Category { Experimental, @@ -511,13 +505,13 @@ pub(crate) trait Linter { fn description(&self) -> &'static str; // The severity for the lint issue. It defaults to `Warning`. - fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { + fn severity(&self) -> Severity { Severity::Warning } // For CLI, when using the --use-cli-severity flag. It defaults to `severity()` - fn cli_severity(&self, sema: &Semantic, file_id: FileId) -> Severity { - self.severity(sema, file_id) + fn cli_severity(&self) -> Severity { + self.severity() } // Specify if the linter issues can be suppressed via a `% elp:ignore` comment. @@ -551,37 +545,12 @@ pub(crate) trait Linter { } } -fn should_process_app( - app_name: &Option, - config: &DiagnosticsConfig, - diagnostic_code: &DiagnosticCode, -) -> bool { - let app = match app_name { - Some(app) => app.to_string(), - None => return true, - }; - - if let Some(lint_config) = config.lint_config.as_ref() - && let Some(linter_config) = lint_config.linters.get(diagnostic_code) - && let Some(ref excluded) = linter_config.exclude_apps - && excluded.contains(&app) - { - return false; - } - - true -} - fn should_run( linter: &dyn Linter, config: &DiagnosticsConfig, - app_name: &Option, is_generated: bool, is_test: bool, ) -> bool { - if !should_process_app(app_name, config, &linter.id()) { - return false; - } let is_enabled = if let Some(lint_config) = config.lint_config.as_ref() { lint_config .get_is_enabled_override(&linter.id()) @@ -892,7 +861,6 @@ pub(crate) trait GenericLinter: Linter { fn fixes( &self, _context: &Self::Context, - _range: TextRange, _sema: &Semantic, _file_id: FileId, ) -> Option> { @@ -926,7 +894,7 @@ impl GenericDiagnostics for T { if let Some(matches) = self.matches(sema, file_id) { for matched in matches { let message = self.match_description(&matched.context); - let fixes = self.fixes(&matched.context, matched.range, sema, file_id); + let fixes = self.fixes(&matched.context, sema, file_id); let tag = self.tag(&matched.context); let mut d = Diagnostic::new(self.id(), message, matched.range) .with_fixes(fixes) @@ -1081,7 +1049,7 @@ impl DiagnosticsConfig { let diagnostic_filter = DiagnosticCode::from(diagnostic_filter.as_str()); // Make sure we do not mask the one we explicitly asked for disabled_diagnostics.remove(&diagnostic_filter); - allowed_diagnostics.insert(diagnostic_filter.clone()); + allowed_diagnostics.insert(diagnostic_filter); } // Make sure the enabled ones win out over disabled if a lint appears in both @@ -1099,13 +1067,6 @@ impl DiagnosticsConfig { } self.lints_from_config = lint_config.ad_hoc_lints.clone(); self.lint_config = Some(lint_config.clone()); - - // If a diagnostic_filter is specified, enable the corresponding linter in lint_config - if let Some(diagnostic_filter) = diagnostic_filter { - let diagnostic_filter_code = DiagnosticCode::from(diagnostic_filter.as_str()); - self.set_linter_enabled(diagnostic_filter_code, true); - } - self.request_erlang_service_diagnostics = self.request_erlang_service_diagnostics(); Ok(self) } @@ -1142,31 +1103,15 @@ impl DiagnosticsConfig { } pub fn enable(mut self, code: DiagnosticCode) -> DiagnosticsConfig { - self.enabled.enable(code.clone()); - self.set_linter_enabled(code, true); + self.enabled.enable(code); self } pub fn disable(mut self, code: DiagnosticCode) -> DiagnosticsConfig { - self.disabled.insert(code.clone()); - self.set_linter_enabled(code, false); + self.disabled.insert(code); self } - fn set_linter_enabled(&mut self, code: DiagnosticCode, is_enabled: bool) { - let lint_config = self.lint_config.get_or_insert_with(LintConfig::default); - lint_config - .linters - .entry(code) - .and_modify(|linter_config| { - linter_config.is_enabled = Some(is_enabled); - }) - .or_insert_with(|| LinterConfig { - is_enabled: Some(is_enabled), - ..Default::default() - }); - } - pub fn set_lints_from_config( mut self, lints_from_config: &LintsFromConfig, @@ -1196,29 +1141,6 @@ impl DiagnosticsConfig { } impl LintConfig { - /// Merges this LintConfig with another, with the other config taking precedence. - pub fn merge(mut self, other: LintConfig) -> LintConfig { - self.enabled_lints.extend(other.enabled_lints); - self.disabled_lints.extend(other.disabled_lints); - - if other.erlang_service.warnings_as_errors { - self.erlang_service.warnings_as_errors = true; - } - - self.ad_hoc_lints.lints.extend(other.ad_hoc_lints.lints); - - for (key, other_linter_config) in other.linters { - self.linters - .entry(key) - .and_modify(|existing| { - *existing = existing.clone().merge(other_linter_config.clone()) - }) - .or_insert(other_linter_config); - } - - self - } - /// Get the is_enabled override for a linter based on its diagnostic code pub fn get_is_enabled_override(&self, diagnostic_code: &DiagnosticCode) -> Option { self.linters.get(diagnostic_code)?.is_enabled @@ -1244,16 +1166,6 @@ impl LintConfig { self.linters.get(diagnostic_code)?.experimental } - /// Get the exclude_apps override for a linter based on its diagnostic code. - pub fn get_exclude_apps_override( - &self, - diagnostic_code: &DiagnosticCode, - ) -> Option> { - self.linters - .get(diagnostic_code) - .and_then(|c| c.exclude_apps.clone()) - } - pub fn get_function_call_linter_config( &self, diagnostic_code: &DiagnosticCode, @@ -1305,43 +1217,9 @@ pub struct FunctionCallLinterConfig { exclude: Option>, } -impl FunctionCallLinterConfig { - /// Merges this FunctionCallLinterConfig with another, extending the include and exclude lists. - pub fn merge(self, other: FunctionCallLinterConfig) -> FunctionCallLinterConfig { - let mut merged_include = self.include.unwrap_or_default(); - if let Some(other_include) = other.include { - merged_include.extend(other_include); - } - let include = if merged_include.is_empty() { - None - } else { - Some(merged_include) - }; - - let mut merged_exclude = self.exclude.unwrap_or_default(); - if let Some(other_exclude) = other.exclude { - merged_exclude.extend(other_exclude); - } - let exclude = if merged_exclude.is_empty() { - None - } else { - Some(merged_exclude) - }; - - FunctionCallLinterConfig { include, exclude } - } -} - #[derive(Deserialize, Serialize, Default, Debug, Clone)] pub struct SsrPatternsLinterConfig {} -impl SsrPatternsLinterConfig { - /// Merges this SsrPatternsLinterConfig with another (trivial since it's empty). - pub fn merge(self, _other: SsrPatternsLinterConfig) -> SsrPatternsLinterConfig { - self - } -} - #[derive(Deserialize, Serialize, Debug, Clone)] #[serde(untagged)] pub enum LinterTraitConfig { @@ -1349,25 +1227,6 @@ pub enum LinterTraitConfig { SsrPatternsLinterConfig(SsrPatternsLinterConfig), } -impl LinterTraitConfig { - /// Merges this LinterTraitConfig with another. Only merges if both are the same variant. - /// If variants differ, returns the other config. - pub fn merge(self, other: LinterTraitConfig) -> LinterTraitConfig { - match (self, other) { - ( - LinterTraitConfig::FunctionCallLinterConfig(self_config), - LinterTraitConfig::FunctionCallLinterConfig(other_config), - ) => LinterTraitConfig::FunctionCallLinterConfig(self_config.merge(other_config)), - ( - LinterTraitConfig::SsrPatternsLinterConfig(self_config), - LinterTraitConfig::SsrPatternsLinterConfig(other_config), - ) => LinterTraitConfig::SsrPatternsLinterConfig(self_config.merge(other_config)), - // If variants differ, other takes precedence - (_, other) => other, - } - } -} - /// Configuration for a specific linter that allows overriding default settings #[derive(Deserialize, Serialize, Debug, Clone, Default)] pub struct LinterConfig { @@ -1377,33 +1236,10 @@ pub struct LinterConfig { pub include_tests: Option, pub include_generated: Option, pub experimental: Option, - pub exclude_apps: Option>, #[serde(flatten)] pub config: Option, } -impl LinterConfig { - /// Merges this LinterConfig with another, with the other config taking precedence - /// for any fields that are Some. - pub fn merge(self, other: LinterConfig) -> LinterConfig { - let merged_config = match (self.config, other.config) { - (Some(self_cfg), Some(other_cfg)) => Some(self_cfg.merge(other_cfg)), - (None, some_cfg) => some_cfg, - (some_cfg, None) => some_cfg, - }; - - LinterConfig { - is_enabled: other.is_enabled.or(self.is_enabled), - severity: other.severity.or(self.severity), - include_tests: other.include_tests.or(self.include_tests), - include_generated: other.include_generated.or(self.include_generated), - experimental: other.experimental.or(self.experimental), - exclude_apps: other.exclude_apps.or(self.exclude_apps), - config: merged_config, - } - } -} - impl<'de> Deserialize<'de> for Severity { fn deserialize(deserializer: D) -> Result where @@ -1555,8 +1391,14 @@ pub fn native_diagnostics( let labeled_syntax_errors = if report_diagnostics { let sema = Semantic::new(db); + if file_kind.is_module() { + no_module_definition_diagnostic(&mut res, &parse); + if config.include_generated || !db.is_generated(file_id) { + unused_include::unused_includes(&sema, db, &mut res, file_id); + } + } + res.append(&mut form_missing_separator_diagnostics(&parse)); - res.extend(get_hir_diagnostics(db, file_id)); adhoc_semantic_diagnostics .iter() @@ -1564,7 +1406,7 @@ pub fn native_diagnostics( config .lints_from_config .get_diagnostics(&mut res, &sema, file_id); - // @fb-only: meta_only::diagnostics(&mut res, &sema, file_id, file_kind, config); + // @fb-only syntax_diagnostics(&sema, &parse, &mut res, file_id); diagnostics_from_descriptors( &mut res, @@ -1593,7 +1435,6 @@ pub fn native_diagnostics( } else { FxHashMap::default() }; - let app_name = db.file_app_name(file_id); let metadata = db.elp_metadata(file_id); // TODO: can we ever disable DiagnosticCode::SyntaxError? // In which case we must check labeled_syntax_errors @@ -1602,7 +1443,6 @@ pub fn native_diagnostics( && (config.experimental && d.has_category(Category::Experimental) || !d.has_category(Category::Experimental)) && !d.should_be_suppressed(&metadata, config) - && should_process_app(&app_name, config, &d.code) }); LabeledDiagnostics { @@ -1631,12 +1471,22 @@ pub fn diagnostics_descriptors<'a>() -> Vec<&'a DiagnosticDescriptor<'a>> { &map_find_to_syntax::DESCRIPTOR, &expression_can_be_simplified::DESCRIPTOR, &application_env::DESCRIPTOR, + &missing_compile_warn_missing_spec::DESCRIPTOR, &dependent_header::DESCRIPTOR, &deprecated_function::DESCRIPTOR, &head_mismatch::DESCRIPTOR_SEMANTIC, &missing_separator::DESCRIPTOR, + &boolean_precedence::DESCRIPTOR, &record_tuple_match::DESCRIPTOR, &unspecific_include::DESCRIPTOR, + &edoc::DESCRIPTOR, + ¯o_precedence_suprise::DESCRIPTOR, + &undocumented_function::DESCRIPTOR, + &duplicate_module::DESCRIPTOR, + &undocumented_module::DESCRIPTOR, + &no_dialyzer_attribute::DESCRIPTOR, + &no_catch::DESCRIPTOR, + &no_nowarn_suppressions::DESCRIPTOR, ] } @@ -1653,20 +1503,20 @@ pub fn diagnostics_from_descriptors( .db .is_test_suite_or_test_helper(file_id) .unwrap_or(false); - let app_name = sema.db.file_app_name(file_id); descriptors.iter().for_each(|descriptor| { if descriptor.conditions.enabled(config, is_generated, is_test) { - let mut diags: Vec = Vec::default(); - (descriptor.checker)(&mut diags, sema, file_id, file_kind); - for diag in diags { - // Check if this diagnostic is enabled (for default_disabled descriptors) - // and if the app is not excluded for this diagnostic code - let is_enabled = - !descriptor.conditions.default_disabled || config.enabled.contains(&diag.code); - let app_allowed = should_process_app(&app_name, config, &diag.code); - if is_enabled && app_allowed { - res.push(diag); + if descriptor.conditions.default_disabled { + // Filter the returned diagnostics to ensure they are + // enabled + let mut diags: Vec = Vec::default(); + (descriptor.checker)(&mut diags, sema, file_id, file_kind); + for diag in diags { + if config.enabled.contains(&diag.code) { + res.push(diag); + } } + } else { + (descriptor.checker)(res, sema, file_id, file_kind); } } }); @@ -1708,28 +1558,10 @@ const SSR_PATTERN_LINTERS: &[&dyn SsrPatternsDiagnostics] = &[ &binary_string_to_sigil::LINTER, &unnecessary_map_to_list_in_comprehension::LINTER, &could_be_a_string_literal::LINTER, - &lists_reverse_append::LINTER, ]; /// Generic linters -const GENERIC_LINTERS: &[&dyn GenericDiagnostics] = &[ - &unused_macro::LINTER, - &missing_compile_warn_missing_spec::LINTER, - &undocumented_module::LINTER, - &undocumented_function::LINTER, - &no_catch::LINTER, - &unavailable_type::LINTER, - &no_dialyzer_attribute::LINTER, - &duplicate_module::LINTER, - &no_nowarn_suppressions::LINTER, - ¯o_precedence_suprise::LINTER, - &old_edoc_syntax::LINTER, - &missing_module::LINTER, - &unused_include::LINTER, - &misspelled_attribute::LINTER, - &boolean_precedence::LINTER, - &bound_variable::LINTER, -]; +const GENERIC_LINTERS: &[&dyn GenericDiagnostics] = &[&unused_macro::LINTER]; /// Unified registry for all types of linters pub(crate) fn linters() -> Vec { @@ -1757,7 +1589,7 @@ pub(crate) fn linters() -> Vec { ); // Add meta-only linters - // @fb-only: all_linters.extend(meta_only::linters()); + // @fb-only all_linters } @@ -1774,26 +1606,25 @@ fn diagnostics_from_linters( .db .is_test_suite_or_test_helper(file_id) .unwrap_or(false); - let app_name = sema.db.file_app_name(file_id); for l in linters { let linter = l.as_linter(); if linter.should_process_file_id(sema, file_id) - && should_run(linter, config, &app_name, is_generated, is_test) + && should_run(linter, config, is_generated, is_test) { let severity = if let Some(lint_config) = config.lint_config.as_ref() { lint_config .get_severity_override(&linter.id()) - .unwrap_or_else(|| linter.severity(sema, file_id)) + .unwrap_or_else(|| linter.severity()) } else { - linter.severity(sema, file_id) + linter.severity() }; let cli_severity = if let Some(lint_config) = config.lint_config.as_ref() { lint_config .get_severity_override(&linter.id()) - .unwrap_or_else(|| linter.cli_severity(sema, file_id)) + .unwrap_or_else(|| linter.cli_severity()) } else { - linter.cli_severity(sema, file_id) + linter.cli_severity() }; match l { DiagnosticLinter::FunctionCall(function_linter) => { @@ -1893,12 +1724,13 @@ fn widen_range(range: TextRange) -> TextRange { } } -fn syntax_diagnostics( +pub fn syntax_diagnostics( sema: &Semantic, parse: &Parse, res: &mut Vec, file_id: FileId, ) { + misspelled_attribute::misspelled_attribute(sema, res, file_id); for node in parse.tree().syntax().descendants() { head_mismatch::head_mismatch(res, file_id, &node); module_mismatch::module_mismatch(sema, res, file_id, &node); @@ -1909,180 +1741,32 @@ pub fn filter_diagnostics(diagnostics: Vec, code: DiagnosticCode) -> diagnostics.into_iter().filter(|d| d.code == code).collect() } -/// Retrieve all BodyDiagnostic values from the BodySourceMaps from lowering -/// all the bodies for a given FileId. -/// -/// This function iterates through all forms in the file and collects diagnostics -/// from the BodySourceMaps associated with each form's body. -pub fn collect_body_diagnostics(db: &RootDatabase, file_id: FileId) -> Vec { - let sema = Semantic::new(db); - let form_list = sema.form_list(file_id); - let mut diagnostics = Vec::new(); - - for form_idx in form_list.forms().iter() { - let body_map = match form_idx { - FormIdx::FunctionClause(function_clause_id) => { - let (_, body_map) = sema - .db - .function_clause_body_with_source(InFile::new(file_id, *function_clause_id)); - Some(body_map) +fn no_module_definition_diagnostic( + diagnostics: &mut Vec, + parse: &Parse, +) { + let mut report = |range| { + let diagnostic = + Diagnostic::new(DiagnosticCode::MissingModule, "no module definition", range); + diagnostics.push(diagnostic); + }; + for form in parse.tree().forms() { + match form { + ast::Form::PreprocessorDirective(_) => { + continue; // skip any directives } - FormIdx::TypeAlias(type_alias_id) => { - let (_, body_map) = sema - .db - .type_body_with_source(InFile::new(file_id, *type_alias_id)); - Some(body_map) + ast::Form::FileAttribute(_) => { + continue; // skip } - FormIdx::Spec(spec_id) => { - let (_, body_map) = sema - .db - .spec_body_with_source(InFile::new(file_id, *spec_id)); - Some(body_map) + ast::Form::ModuleAttribute(_) => { + break; } - FormIdx::Callback(callback_id) => { - let (_, body_map) = sema - .db - .callback_body_with_source(InFile::new(file_id, *callback_id)); - Some(body_map) + other_form => { + report(other_form.syntax().text_range()); + break; } - FormIdx::Record(record_id) => { - let (_, body_map) = sema - .db - .record_body_with_source(InFile::new(file_id, *record_id)); - Some(body_map) - } - FormIdx::Attribute(attribute_id) => { - let (_, body_map) = sema - .db - .attribute_body_with_source(InFile::new(file_id, *attribute_id)); - Some(body_map) - } - FormIdx::CompileOption(compile_option_id) => { - let (_, body_map) = sema - .db - .compile_body_with_source(InFile::new(file_id, *compile_option_id)); - Some(body_map) - } - FormIdx::PPDirective(idx) => { - match &form_list[*idx] { - PPDirective::Define(define_id) => { - let (_, body_map) = sema - .db - .define_body_with_source(InFile::new(file_id, *define_id)); - Some(body_map) - } - PPDirective::Include(include_id) => { - // Try to resolve the include - if sema - .db - .resolve_include(InFile::new(file_id, *include_id)) - .is_none() - { - // Include resolution failed, create a diagnostic - diagnostics.push(hir::BodyDiagnostic::UnresolvedInclude(InFile::new( - file_id, - *include_id, - ))); - } - None - } - _ => None, - } - } - _ => None, - }; - - if let Some(body_map) = body_map { - diagnostics.extend_from_slice(body_map.diagnostics()); } } - - diagnostics -} - -/// Convert HIR body diagnostics to IDE Diagnostics. -/// This function takes the diagnostics collected during HIR lowering and converts -/// them to the IDE Diagnostic format for display to users. -pub fn get_hir_diagnostics(db: &RootDatabase, file_id: FileId) -> Vec { - let body_diagnostics = collect_body_diagnostics(db, file_id); - - body_diagnostics - .into_iter() - .filter_map(|body_diag| { - // Only include diagnostics for the requested file - if body_diag.file_id() != file_id { - return None; - } - - let (code, message, range) = match &body_diag { - hir::BodyDiagnostic::UnresolvedMacro(macro_source) => { - // Determine range for UnresolvedMacro - let full_range = macro_source.range(); - - // Get the macro call AST node to extract name and arity - let macro_call = macro_source.to_ast(db); - let macro_name = macro_call - .name() - .map(|name| name.to_string()) - .unwrap_or_else(|| "?".to_string()); - - let message = match macro_call.arity() { - Some(arity) => format!("undefined macro '{}/{}'", macro_name, arity), - None => format!("undefined macro '{}'", macro_name), - }; - - // For macros with arguments, only highlight the name part, not the full call - let range = macro_call - .name() - .map(|name| { - // Get the syntax range of just the macro name - let name_range = name.syntax().text_range(); - // Include the '?' prefix by extending one character to the left - if name_range.start() > 0.into() { - TextRange::new( - name_range.start() - TextSize::from(1), - name_range.end(), - ) - } else { - name_range - } - }) - .unwrap_or(full_range.range); - - (DiagnosticCode::HirUnresolvedMacro, message, range) - } - hir::BodyDiagnostic::UnresolvedInclude(include) => { - // Get the include attribute from the form_list - let sema = Semantic::new(db); - let form_list = sema.form_list(file_id); - let include_attr = &form_list[include.value]; - - // Extract path and range from IncludeAttribute - let path = include_attr.path().to_string(); - let range = include_attr.file_range(db, file_id); - - // Use appropriate message based on include type - let message = match include_attr { - hir::IncludeAttribute::Include { .. } => { - format!("can't find include file \"{}\"", path) - } - hir::IncludeAttribute::IncludeLib { .. } => { - format!("can't find include lib \"{}\"", path) - } - }; - - (DiagnosticCode::HirUnresolvedInclude, message, range) - } - }; - - Some( - Diagnostic::new(code, message, range) - // We set the severity to Warning for now, until we have cleaned - // up the code base from this diagnostic - .with_severity(Severity::Warning), - ) - }) - .collect() } fn form_missing_separator_diagnostics(parse: &Parse) -> Vec { @@ -2277,54 +1961,51 @@ pub fn erlang_service_diagnostics( let mut warning_info: BTreeSet<(FileId, TextSize, TextSize, String, String)> = BTreeSet::default(); - // Track related information for L0000 diagnostics from included files - let mut related_info_map: FxHashMap<(FileId, TextSize, TextSize), Vec> = - FxHashMap::default(); - res.errors .iter() - .filter_map(|d| parse_error_to_diagnostic_info(db, file_id, d, &mut related_info_map)) + .filter_map(|d| parse_error_to_diagnostic_info(db, file_id, d)) .for_each(|val| { error_info.insert(val); }); res.warnings .iter() - .filter_map(|d| parse_error_to_diagnostic_info(db, file_id, d, &mut related_info_map)) + .filter_map(|d| parse_error_to_diagnostic_info(db, file_id, d)) .for_each(|val| { warning_info.insert(val); }); let warning_severity = config.erlang_service_warning_severity(); - let to_diagnostic = |file_id: FileId, - start: TextSize, - end: TextSize, - code: String, - msg: String, - severity: Severity| { - let range = TextRange::new(start, end); - let mut diagnostic = tag_erlang_service_diagnostic( - Diagnostic::new(DiagnosticCode::ErlangService(code.clone()), msg, range) - .with_severity(severity), - ); - if code == "L0000" - && let Some(related) = related_info_map.get(&(file_id, start, end)) - { - diagnostic = diagnostic.with_related(Some(related.clone())); - } - (file_id, diagnostic) - }; - let diags: Vec<(FileId, Diagnostic)> = error_info .into_iter() .map(|(file_id, start, end, code, msg)| { - to_diagnostic(file_id, start, end, code, msg, Severity::Error) + ( + file_id, + tag_erlang_service_diagnostic( + Diagnostic::new( + DiagnosticCode::ErlangService(code), + msg, + TextRange::new(start, end), + ) + .with_severity(Severity::Error), + ), + ) }) .chain( warning_info .into_iter() .map(|(file_id, start, end, code, msg)| { - to_diagnostic(file_id, start, end, code, msg, warning_severity) + ( + file_id, + tag_erlang_service_diagnostic( + Diagnostic::new( + DiagnosticCode::ErlangService(code), + msg, + TextRange::new(start, end), + ) + .with_severity(warning_severity), + ), + ) }), ) .collect(); @@ -2341,14 +2022,11 @@ pub fn erlang_service_diagnostics( diags }; - let app_name = db.file_app_name(file_id); let metadata = db.elp_metadata(file_id); let diags = diags .into_iter() .filter(|(_file_id, d)| { - !d.should_be_suppressed(&metadata, config) - && !config.disabled.contains(&d.code) - && should_process_app(&app_name, config, &d.code) + !d.should_be_suppressed(&metadata, config) && !config.disabled.contains(&d.code) }) .map(|(file_id, d)| { ( @@ -2639,7 +2317,7 @@ pub fn ct_diagnostics( CommonTestInfo::Result { all, groups } => { let testcases = common_test::runnable_names(&sema, file_id, all, groups).ok(); common_test::unreachable_test(&mut res, &sema, file_id, &testcases); - // @fb-only: meta_only::ct_diagnostics(&mut res, &sema, file_id, testcases); + // @fb-only } CommonTestInfo::EvalError(_error) => { // The error currently does not contain anything useful, so we ignore it @@ -2716,68 +2394,20 @@ fn parse_error_to_diagnostic_info( db: &RootDatabase, file_id: FileId, parse_error: &ParseError, - related_info_map: &mut FxHashMap<(FileId, TextSize, TextSize), Vec>, ) -> Option<(FileId, TextSize, TextSize, String, String)> { - match &parse_error.location { + match parse_error.location { Some(DiagnosticLocation::Included { - file_attribute_location, - error_path, + directive_location, error_location, - }) => { - // Get the FileId for the file containing the error by searching through source roots - - // Note: we can have our .erl file which includes A.hrl which includes B.hrl, and B.hrl has an error. - // In this case, the error location will be in B.hrl, but the file_attribute_location will be 1..1, for the entry into B.hrl. - // The parse_error.path will correctly refer to B.hrl - // In this case, we need to report the error in the .erl file, at the include directive location. - // But how do we detemine that? We need to find an include chain from the .erl file to the included - // file. The A->B chain can be arbitrarily long. - // So, in the erlang service, we must report the chain of `file` attributes seen. - - // For errors in included files, report L0000 at the include directive location - // and add the actual error as related information - if let Some(directive_range) = - include_directive_range(db, file_id, *file_attribute_location) - { - // Store related info about the actual error in the included file - if let Some(error_file_id) = related_file_id(db, file_id, error_path) { - let related_info = RelatedInformation { - file_id: error_file_id, - range: *error_location, - message: format!("{}: {}", parse_error.code, parse_error.msg), - }; - related_info_map - .entry((file_id, directive_range.start(), directive_range.end())) - .or_default() - .push(related_info); - } else { - log::warn!("Could not find file for path {}", error_path.display()); - } - - // Return diagnostic at the include directive with code L0000 - Some(( - file_id, - directive_range.start(), - directive_range.end(), - "L0000".to_string(), - "Issue in included file".to_string(), - )) - } else { - // Fallback: if we can't find the include directive range, try to report - // at the included file itself - included_file_file_id(db, file_id, *file_attribute_location).map( - |included_file_id| { - ( - included_file_id, - error_location.start(), - error_location.end(), - parse_error.code.clone(), - parse_error.msg.clone(), - ) - }, - ) - } - } + }) => included_file_file_id(db, file_id, directive_location).map(|included_file_id| { + ( + included_file_id, + error_location.start(), + error_location.end(), + parse_error.code.clone(), + parse_error.msg.clone(), + ) + }), Some(DiagnosticLocation::Normal(range)) => { let default_range = ( file_id, @@ -2787,13 +2417,11 @@ fn parse_error_to_diagnostic_info( parse_error.msg.clone(), ); match parse_error.code.as_str() { - // Do not report L0000, it is already reported via a DiagnosticLocation::Included parse error - "L0000" => None, // For certain warnings, OTP returns a diagnostic with a wide range (e.g. a full record definition) // That can be very verbose and distracting, so we try restricting the range to the relevant parts only. "L1227" => { let name = function_undefined_from_message(&parse_error.msg); - match exported_function_name_range(db, file_id, name, *range) { + match exported_function_name_range(db, file_id, name, range) { Some(name_range) => Some(( file_id, name_range.start(), @@ -2806,7 +2434,7 @@ fn parse_error_to_diagnostic_info( } "L1295" => { let name = type_undefined_from_message(&parse_error.msg); - match exported_type_name_range(db, file_id, name, *range) { + match exported_type_name_range(db, file_id, name, range) { Some(name_range) => Some(( file_id, name_range.start(), @@ -2817,7 +2445,7 @@ fn parse_error_to_diagnostic_info( None => Some(default_range), } } - "L1230" | "L1309" => match function_name_range(db, file_id, *range) { + "L1230" | "L1309" => match function_name_range(db, file_id, range) { Some(name_range) => Some(( file_id, name_range.start(), @@ -2827,7 +2455,7 @@ fn parse_error_to_diagnostic_info( )), None => Some(default_range), }, - "L1296" => match type_alias_name_range(db, file_id, *range) { + "L1296" => match type_alias_name_range(db, file_id, range) { Some(name_range) => Some(( file_id, name_range.start(), @@ -2837,7 +2465,7 @@ fn parse_error_to_diagnostic_info( )), None => Some(default_range), }, - "L1308" => match spec_name_range(db, file_id, *range) { + "L1308" => match spec_name_range(db, file_id, range) { Some(name_range) => Some(( file_id, name_range.start(), @@ -2847,7 +2475,7 @@ fn parse_error_to_diagnostic_info( )), None => Some(default_range), }, - "L1260" => match record_name_range(db, file_id, *range) { + "L1260" => match record_name_range(db, file_id, range) { Some(name_range) => Some(( file_id, name_range.start(), @@ -2870,22 +2498,6 @@ fn parse_error_to_diagnostic_info( } } -fn related_file_id(db: &RootDatabase, file_id: FileId, path: &Path) -> Option { - db.file_project_id(file_id).and_then(|project_id| { - let vfs_path = VfsPath::new_real_path(path.to_string_lossy().as_ref().to_string()); - - let project_data = db.project_data(project_id); - // Search through all source roots in the project to find the file - project_data - .source_roots - .iter() - .find_map(|&source_root_id| { - let source_root = db.source_root(source_root_id); - source_root.file_for_path(&vfs_path) - }) - }) -} - fn exported_function_name_range( db: &RootDatabase, file_id: FileId, @@ -2970,13 +2582,13 @@ fn type_alias_name_range( pub fn included_file_file_id( db: &RootDatabase, file_id: FileId, - file_attribute_location: TextRange, + directive_range: TextRange, ) -> Option { let parsed = db.parse(file_id); let form_list = db.file_form_list(file_id); let include = form_list.includes().find_map(|(idx, include)| { let form = include.form_id().get(&parsed.tree()); - if form.syntax().text_range().start() >= file_attribute_location.start() { + if form.syntax().text_range().contains(directive_range.start()) { db.resolve_include(InFile::new(file_id, idx)) } else { None @@ -2985,30 +2597,6 @@ pub fn included_file_file_id( Some(include) } -/// For an error in an included file, find the next form occurring after `file_attribute_location` -/// in the file, and return its full syntax range provided it is an include or include_lib -fn include_directive_range( - db: &RootDatabase, - file_id: FileId, - file_attribute_location: TextRange, -) -> Option { - let parsed = db.parse(file_id); - let form_list = db.file_form_list(file_id); - - form_list.includes().find_map(|(_, include)| { - let form = include.form_id().get(&parsed.tree()); - let form_range = form.syntax().text_range(); - - // Check if this form starts after directive_location - if form_range.start() >= file_attribute_location.start() { - // Return the full syntax range of the include directive - Some(form_range) - } else { - None - } - }) -} - /// Given syntax errors from ELP native and erlang service, combine /// them by discarding any erlang service syntax errors for a form if /// ELP has reported any too. This is done by merging labels, with @@ -3031,7 +2619,6 @@ fn combine_syntax_errors(native: &Labeled, erlang_service: &Labeled) -> Labeled /// Combine the ELP and erlang_service diagnostics. In particular, /// flatten any cascading diagnostics if possible. pub fn attach_related_diagnostics( - file_id: FileId, native: LabeledDiagnostics, erlang_service: LabeledDiagnostics, ) -> Vec { @@ -3067,7 +2654,7 @@ pub fn attach_related_diagnostics( .flat_map(|(mfa_label, syntax_error_diags)| { if let Some(related) = erlang_service.labeled_undefined_errors.get(mfa_label) { undefineds_to_remove.insert(mfa_label); - let related_info = related.iter().map(|d| d.as_related(file_id)).collect_vec(); + let related_info = related.iter().map(|d| d.as_related()).collect_vec(); syntax_error_diags .iter() .map(|d| d.clone().with_related(Some(related_info.clone()))) @@ -3088,90 +2675,10 @@ pub fn attach_related_diagnostics( .filter(|(k, _)| !undefineds_to_remove.contains(k)) .flat_map(|(_, v)| v); - // Step 4. - // Split erlang service normal diagnostics into undefined macro diagnostics (E1507/E1508), - // unresolved include diagnostics (E1516), and other diagnostics in a single pass - let mut erlang_service_undefined_macros = Vec::new(); - let mut erlang_service_unresolved_includes = Vec::new(); - let mut erlang_service_other = Vec::new(); - - for d in erlang_service.normal { - match &d.code { - DiagnosticCode::ErlangService(code) if code == "E1507" || code == "E1508" => { - erlang_service_undefined_macros.push(d); - } - DiagnosticCode::ErlangService(code) if code == "E1516" => { - erlang_service_unresolved_includes.push(d); - } - _ => { - erlang_service_other.push(d); - } - } - } - - // Collect E1507/E1508 from labeled_undefined_errors for filtering - let undefined_macros_from_labeled: Vec<_> = erlang_service_undefined_not_related - .clone() - .filter(|d| { - matches!(&d.code, DiagnosticCode::ErlangService(code) if code == "E1507" || code == "E1508") - }) - .cloned() - .collect(); - - // Collect E1516 from labeled_undefined_errors for filtering - let unresolved_includes_from_labeled: Vec<_> = erlang_service_undefined_not_related - .clone() - .filter(|d| matches!(&d.code, DiagnosticCode::ErlangService(code) if code == "E1516")) - .cloned() - .collect(); - - // Combine all E1507/E1508 diagnostics for filtering (clone to avoid borrow issues) - let all_undefined_macros: Vec<_> = erlang_service_undefined_macros - .iter() - .cloned() - .chain(undefined_macros_from_labeled) - .collect(); - - // Combine all E1516 diagnostics for filtering - let all_unresolved_includes: Vec<_> = erlang_service_unresolved_includes - .iter() - .cloned() - .chain(unresolved_includes_from_labeled) - .collect(); - - // Step 5. - // Filter out W0056 diagnostics if there's a matching E1507/E1508 for the same macro - // Filter out W0057 diagnostics if there's a matching E1516 for the same include - let filtered_native_normal = native.normal.into_iter().filter(|d| { - if d.code == DiagnosticCode::HirUnresolvedMacro { - // Check if there's a matching E1507/E1508 diagnostic - let has_matching_erlang_service = all_undefined_macros.iter().any(|es_diag| { - // Check if ranges overlap - d.range.intersect(es_diag.range).is_some() - }); - - // Keep W0056 only if there's no matching E1507/E1508 - return !has_matching_erlang_service; - } - - if d.code == DiagnosticCode::HirUnresolvedInclude { - // Check if there's a matching E1516 diagnostic - let has_matching_erlang_service = all_unresolved_includes.iter().any(|es_diag| { - // Check if ranges overlap - d.range.intersect(es_diag.range).is_some() - }); - - // Keep W0057 only if there's no matching E1516 - return !has_matching_erlang_service; - } - - true // Keep all other diagnostics - }); - - filtered_native_normal - .chain(erlang_service_other) - .chain(erlang_service_undefined_macros) - .chain(erlang_service_unresolved_includes) + native + .normal + .into_iter() + .chain(erlang_service.normal) .chain(syntax_errors_with_related) .chain(erlang_service_undefined_not_related.cloned()) // TODO:AZ: consider returning an iterator @@ -3236,7 +2743,6 @@ mod tests { fn syntax_error() { check_diagnostics( r#" -//- expect_parse_errors -module(main). foo() -> XX 3.0. %% ^^ error: P1711: Syntax Error @@ -3326,6 +2832,53 @@ main(X) -> // ) // } + #[test] + fn fun_decl_module_decl_ok() { + check_diagnostics( + r#" +-file("main.erl",1). +-define(baz,4). +-module(main). +foo(2)->?baz. +"#, + ); + } + + #[test] + fn fun_decl_module_decl_missing() { + check_diagnostics( + r#" + -file("foo.erl",1). + -define(baz,4). + foo(2)->?baz. +%%^^^^^^^^^^^^^ error: L1201: no module definition +"#, + ); + } + + #[test] + fn fun_decl_module_decl_missing_2() { + check_diagnostics( + r#" + baz(1)->4. +%%^^^^^^^^^^ error: L1201: no module definition + foo(2)->3. +"#, + ); + } + + #[test] + fn fun_decl_module_decl_after_preprocessor() { + check_diagnostics( + r#" +-ifndef(snmpm_net_if_mt). +-module(main). +-endif. +baz(1)->4. +"#, + ); + } + #[test] fn filter_diagnostics() { let diag1 = DiagnosticCode::ErlangService("P1700".to_string()); @@ -3414,7 +2967,6 @@ main(X) -> #[test] fn label_syntax_error_not_function() { let fixture_str = r#" - //- expect_parse_errors -module(main). -record(person, {(name + XXX)}). %% ^^^^^^^ error: P1711: Syntax Error @@ -3430,7 +2982,7 @@ main(X) -> expect![[r#" Some( Range( - 5..45, + 24..56, ), ) "#]] @@ -3442,7 +2994,7 @@ main(X) -> check_diagnostics( r#" baz(1)->4. -%%^^^^^^^^^^ 💡 error: L1201: no module definition +%%^^^^^^^^^^ error: L1201: no module definition foo(2)->3. "#, ); @@ -3466,7 +3018,7 @@ main(X) -> %% elp:ignore L1201 baz(1)->4. -%%^^^^^^^^^^ 💡 error: L1201: no module definition +%%^^^^^^^^^^ error: L1201: no module definition foo(2)->3. "#, ); @@ -3589,7 +3141,6 @@ main(X) -> config, &extra_diags, r#" - //- expect_parse_errors -module(main). -export([foo/0,bar/0]). @@ -3600,9 +3151,6 @@ main(X) -> -spec foo() -> ok. foo( -> ok. %% %% ^ error: W0004: Missing ')' - %% | Related info: 0:21-43 function foo/0 undefined - %% | Related info: 0:74-79 function foo/0 undefined - %% | Related info: 0:82-99 spec for undefined function foo/0 "#, ); } @@ -3610,7 +3158,7 @@ main(X) -> #[test] fn group_related_diagnostics_elp_only() { // Demonstrate that ELP does not pick up a syntax error in the - // spec, same code as in test/test_projects/diagnostics/app_a/src/syntax.erl + // spec, same code as in test_projects/diagnostics/app_a/src/syntax.erl check_diagnostics( r#" -module(main). @@ -3627,14 +3175,12 @@ main(X) -> check_diagnostics( r#" //- erlang_service - //- expect_parse_errors //- /src/a_mod.erl app:app_a -module(a_mod). -export([foo/0]). foo() -> syntax error oops. %% ^^^^^ error: P1711: syntax error before: error - %% | Related info: 0:25-30 function foo/0 undefined "#, ); } @@ -3646,7 +3192,6 @@ main(X) -> check_diagnostics( r#" //- erlang_service - //- expect_parse_errors //- native //- /src/a_mod.erl app:app_a -module(a_mod). @@ -3725,7 +3270,6 @@ main(X) -> fn test_nested_syntax_errors() { check_diagnostics( r#" - //- expect_parse_errors -module(main). run() -> ExitCode = @@ -3908,37 +3452,6 @@ main(X) -> ); } - #[test] - fn erlang_service_nested_include_resolution() { - check_diagnostics( - r#" - //- erlang_service - //- /src/app_a_include.erl - -module(app_a_include). - -export([test/0]). - %% ^^^^^^ error: L1227: function test/0 undefined - - -include("first.hrl"). - %% ^^^^^^^^^^^^^^^^^^^^^^ error: L0000: Issue in included file - %% | Related info: 1:13-30 E1516: can't find include file "second_typo.hrl" - - test() -> - ?FIRST_MACRO, - ?SECOND_MACRO. - %% ^^^^^^^^^^^^^ error: E1507: undefined macro 'SECOND_MACRO' - - //- /src/first.hrl - -include("second_typo.hrl"). - %% ^^^^^^^^^^^^^^^^^ error: E1516: can't find include file "second_typo.hrl" - - -define(FIRST_MACRO, 1). - - //- /src/second.hrl - -define(SECOND_MACRO, "Hello from nested header"). - "#, - ); - } - #[test] fn erlang_service_include_resolution_doc() { check_diagnostics( @@ -3971,7 +3484,6 @@ main(X) -> \~"\"\\µA\"" = \~/"\\µA"/ X = 3. %% ^ error: P1711: syntax error before: X - %% | Related info: 0:32-37 function foo/0 undefined "#, ); } @@ -4039,7 +3551,6 @@ main(X) -> include_tests: None, include_generated: None, experimental: None, - exclude_apps: None, config: None, }, ); @@ -4082,7 +3593,6 @@ main(X) -> include_tests: Some(true), include_generated: None, experimental: None, - exclude_apps: None, config: None, }, ); @@ -4124,7 +3634,6 @@ main(X) -> include_tests: None, include_generated: Some(true), experimental: None, - exclude_apps: None, config: None, }, ); @@ -4167,7 +3676,6 @@ main(X) -> include_tests: None, include_generated: None, experimental: Some(true), - exclude_apps: None, config: None, }, ); @@ -4212,7 +3720,6 @@ main(X) -> include_tests: None, include_generated: None, experimental: None, - exclude_apps: None, config: None, }, ); @@ -4234,7 +3741,6 @@ main(X) -> warning() -> erlang:garbage_collect(). - %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0047: Avoid forcing garbage collection. //- /opt/lib/stdlib-3.17/src/erlang.erl otp_app:/opt/lib/stdlib-3.17 -module(erlang). -export([garbage_collect/0]). @@ -4242,203 +3748,4 @@ main(X) -> "#, ); } - - #[test] - fn test_linter_exclude_apps_override() { - let mut lint_config = LintConfig::default(); - lint_config.linters.insert( - DiagnosticCode::NoGarbageCollect, - LinterConfig { - is_enabled: Some(false), - severity: None, - include_tests: None, - include_generated: None, - experimental: None, - exclude_apps: Some(vec!["my_app".to_string()]), - config: None, - }, - ); - - let config = DiagnosticsConfig::default() - .configure_diagnostics( - &lint_config, - &Some("no_garbage_collect".to_string()), - &None, - FallBackToAll::No, - ) - .unwrap(); - check_diagnostics_with_config( - config, - r#" - //- /src/main.erl app:my_app - -module(main). - -export([warning/0]). - - warning() -> - erlang:garbage_collect(). - //- /opt/lib/stdlib-3.17/src/erlang.erl otp_app:/opt/lib/stdlib-3.17 - -module(erlang). - -export([garbage_collect/0]). - garbage_collect() -> ok. - "#, - ); - } - - #[test] - fn no_unused_macro_in_macro_rhs_for_function_name() { - let config = DiagnosticsConfig::default() - .set_experimental(true) - .disable(DiagnosticCode::UnspecificInclude) - .disable(DiagnosticCode::BinaryStringToSigil); - check_diagnostics_with_config( - config, - r#" - //- /my_app/src/a_file.erl - -module(a_file). - -define(A_MACRO, ?FUNCTION_NAME). - foo() -> ?A_MACRO. - - "#, - ); - } - - #[test] - fn test_lint_config_merge() { - let code1 = DiagnosticCode::from("W0001"); - let code2 = DiagnosticCode::from("W0002"); - let code3 = DiagnosticCode::from("W0003"); - - let mut config1 = LintConfig { - enabled_lints: vec![code1.clone()], - disabled_lints: vec![code2.clone()], - ..Default::default() - }; - config1.erlang_service.warnings_as_errors = false; - - config1 - .ad_hoc_lints - .lints - .push(Lint::ReplaceCall(ReplaceCall { - matcher: FunctionMatch::mf("mod1", "func1"), - action: ReplaceCallAction::Replace(Replacement::UseOk), - })); - - config1.linters.insert( - code1.clone(), - LinterConfig { - is_enabled: Some(true), - severity: Some(Severity::Error), - include_tests: None, - include_generated: None, - experimental: None, - exclude_apps: None, - config: Some(LinterTraitConfig::FunctionCallLinterConfig( - FunctionCallLinterConfig { - include: Some(vec![FunctionMatch::mf("mod_a", "func_a")]), - exclude: None, - }, - )), - }, - ); - - let mut config2 = LintConfig { - enabled_lints: vec![code3.clone()], - disabled_lints: vec![code1.clone()], - ..Default::default() - }; - config2.erlang_service.warnings_as_errors = true; - - config2 - .ad_hoc_lints - .lints - .push(Lint::ReplaceCall(ReplaceCall { - matcher: FunctionMatch::mf("mod2", "func2"), - action: ReplaceCallAction::Replace(Replacement::UseOk), - })); - - config2.linters.insert( - code1.clone(), - LinterConfig { - is_enabled: Some(false), - severity: Some(Severity::Warning), - include_tests: Some(true), - include_generated: None, - experimental: None, - exclude_apps: None, - config: Some(LinterTraitConfig::FunctionCallLinterConfig( - FunctionCallLinterConfig { - include: Some(vec![FunctionMatch::mf("mod_b", "func_b")]), - exclude: Some(vec![FunctionMatch::mf("mod_c", "func_c")]), - }, - )), - }, - ); - - config2.linters.insert( - code2.clone(), - LinterConfig { - is_enabled: Some(true), - severity: None, - include_tests: None, - include_generated: Some(true), - experimental: None, - exclude_apps: None, - config: None, - }, - ); - - let merged = config1.merge(config2); - - assert_eq!(merged.enabled_lints.len(), 2); - assert!(merged.enabled_lints.contains(&code1)); - assert!(merged.enabled_lints.contains(&code3)); - - assert_eq!(merged.disabled_lints.len(), 2); - assert!(merged.disabled_lints.contains(&code2)); - assert!(merged.disabled_lints.contains(&code1)); - - assert!(merged.erlang_service.warnings_as_errors); - - assert_eq!(merged.ad_hoc_lints.lints.len(), 2); - - assert_eq!(merged.linters.len(), 2); - let linter_config1 = merged.linters.get(&code1).unwrap(); - assert_eq!(linter_config1.is_enabled, Some(false)); - assert_eq!(linter_config1.severity, Some(Severity::Warning)); - assert_eq!(linter_config1.include_tests, Some(true)); - - if let Some(LinterTraitConfig::FunctionCallLinterConfig(function_config)) = - &linter_config1.config - { - assert_eq!(function_config.include.as_ref().unwrap().len(), 2); - assert!( - function_config - .include - .as_ref() - .unwrap() - .contains(&FunctionMatch::mf("mod_a", "func_a")) - ); - assert!( - function_config - .include - .as_ref() - .unwrap() - .contains(&FunctionMatch::mf("mod_b", "func_b")) - ); - assert_eq!(function_config.exclude.as_ref().unwrap().len(), 1); - assert!( - function_config - .exclude - .as_ref() - .unwrap() - .contains(&FunctionMatch::mf("mod_c", "func_c")) - ); - } else { - panic!("Expected FunctionCallLinterConfig"); - } - - let linter_config2 = merged.linters.get(&code2).unwrap(); - assert_eq!(linter_config2.is_enabled, Some(true)); - assert_eq!(linter_config2.include_generated, Some(true)); - } } diff --git a/crates/ide/src/diagnostics/application_env.rs b/crates/ide/src/diagnostics/application_env.rs index 615b7801f9..1e4fe7c4cf 100644 --- a/crates/ide/src/diagnostics/application_env.rs +++ b/crates/ide/src/diagnostics/application_env.rs @@ -28,7 +28,7 @@ use crate::codemod_helpers::CheckCallCtx; use crate::codemod_helpers::FunctionMatch; use crate::codemod_helpers::MatchCtx; use crate::codemod_helpers::find_call_in_function; -// @fb-only: use crate::diagnostics; +// @fb-only use crate::diagnostics::DiagnosticCode; use crate::diagnostics::Severity; @@ -36,7 +36,7 @@ pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { conditions: DiagnosticConditions { experimental: false, include_generated: true, - include_tests: false, + include_tests: true, default_disabled: false, }, checker: &|diags, sema, file_id, _ext| { @@ -108,7 +108,7 @@ fn check_function(diags: &mut Vec, sema: &Semantic, def: &FunctionDe vec![2, 3], BadEnvCallAction::AppArg(0), ), - // @fb-only: diagnostics::meta_only::application_env_bad_matches(), + // @fb-only ] .into_iter() .flatten() diff --git a/crates/ide/src/diagnostics/atoms_exhaustion.rs b/crates/ide/src/diagnostics/atoms_exhaustion.rs index 56a43a50ca..4708e35b1f 100644 --- a/crates/ide/src/diagnostics/atoms_exhaustion.rs +++ b/crates/ide/src/diagnostics/atoms_exhaustion.rs @@ -13,7 +13,7 @@ use hir::Semantic; use crate::FunctionMatch; use crate::codemod_helpers::CheckCallCtx; -// @fb-only: use crate::diagnostics; +// @fb-only use crate::diagnostics::DiagnosticCode; use crate::diagnostics::FunctionCallLinter; use crate::diagnostics::Linter; @@ -35,9 +35,9 @@ impl Linter for AtomsExhaustionLinter { false } #[rustfmt::skip] - // @fb-only: fn should_process_file_id(&self, sema: &Semantic, file_id: FileId) -> bool { + // @fb-only fn should_process_file_id(&self, _sema: &Semantic, _file_id: FileId) -> bool { // @oss-only - // @fb-only: diagnostics::meta_only::is_relevant_file(sema.db.upcast(), file_id) + // @fb-only true // @oss-only } } @@ -56,16 +56,16 @@ impl FunctionCallLinter for AtomsExhaustionLinter { // FunctionMatch::mfa("erlang", "binary_to_term", 2), ] .into_iter() - // @fb-only: .chain(diagnostics::meta_only::atoms_exhaustion_matches().into_iter()) + // @fb-only .collect::>() ] } fn check_match(&self, context: &CheckCallCtx<'_, ()>) -> Option { #[rustfmt::skip] - // @fb-only: let sema = context.in_clause.sema; - // @fb-only: let is_safe = - // @fb-only: diagnostics::meta_only::atoms_exhaustion_is_safe(sema, context.in_clause, context.parents); + // @fb-only + // @fb-only + // @fb-only let is_safe = false; // @oss-only if !is_safe { match context.args.as_slice() { diff --git a/crates/ide/src/diagnostics/binary_string_to_sigil.rs b/crates/ide/src/diagnostics/binary_string_to_sigil.rs index 91b08f9d1d..60a18aa7e1 100644 --- a/crates/ide/src/diagnostics/binary_string_to_sigil.rs +++ b/crates/ide/src/diagnostics/binary_string_to_sigil.rs @@ -38,7 +38,7 @@ impl Linter for BinaryStringToSigilLinter { "Binary string can be written using sigil syntax." } - fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { + fn severity(&self) -> Severity { Severity::WeakWarning } diff --git a/crates/ide/src/diagnostics/boolean_precedence.rs b/crates/ide/src/diagnostics/boolean_precedence.rs index f8f7851f8a..affbdf9b1d 100644 --- a/crates/ide/src/diagnostics/boolean_precedence.rs +++ b/crates/ide/src/diagnostics/boolean_precedence.rs @@ -15,7 +15,6 @@ // https://www.erlang.org/doc/system/expressions.html#operator-precedence // So this often results in incorrect or buggy code. -use std::borrow::Cow; use std::fmt; use std::fmt::Display; @@ -25,11 +24,11 @@ use elp_ide_assists::helpers::unwrap_parens; use elp_ide_db::DiagnosticCode; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; -use elp_ide_db::text_edit::TextRange; use elp_syntax::ast; use elp_syntax::ast::BinaryOp; use elp_syntax::ast::LogicOp; +use elp_text_edit::TextEdit; +use elp_text_edit::TextRange; use hir::AnyExpr; use hir::AnyExprId; use hir::AnyExprRef; @@ -46,107 +45,29 @@ use hir::fold::MacroStrategy; use hir::fold::ParenStrategy; use hir::fold::ParentId; -use super::GenericLinter; -use super::GenericLinterMatchContext; -use super::Linter; -use crate::Assist; +use super::Diagnostic; +use super::DiagnosticConditions; +use super::DiagnosticDescriptor; +use super::Severity; use crate::fix; -pub(crate) struct BooleanPrecedenceLinter; +pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { + conditions: DiagnosticConditions { + experimental: false, + include_generated: false, + include_tests: true, + default_disabled: false, + }, + checker: &|diags, sema, file_id, _ext| { + boolean_precedence(diags, sema, file_id); + }, +}; -impl Linter for BooleanPrecedenceLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::BooleanPrecedence - } - - fn description(&self) -> &'static str { - "boolean precedence" - } +fn boolean_precedence(diagnostics: &mut Vec, sema: &Semantic, file_id: FileId) { + sema.for_each_function(file_id, |def| check_function(diagnostics, sema, def)); } -#[derive(Debug, Clone, PartialEq, Eq, Default)] -pub struct Context { - preceding_ws_range: TextRange, - op: Op, - lhs_complex: bool, - rhs_complex: bool, - add_parens_range: TextRange, -} - -impl GenericLinter for BooleanPrecedenceLinter { - type Context = Context; - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let mut res = Vec::new(); - sema.for_each_function(file_id, |def| { - check_function(&mut res, sema, def); - }); - Some(res) - } - - fn match_description(&self, context: &Self::Context) -> Cow<'_, str> { - format!( - "Consider using the short-circuit expression '{}' instead of '{}'.\nOr add parentheses to avoid potential ambiguity.", - context.op.preferred(), - context.op, - ) - .into() - } - - fn fixes( - &self, - context: &Self::Context, - range: TextRange, - _sema: &Semantic, - file_id: FileId, - ) -> Option> { - let mut fixes = Vec::new(); - - // Add "replace with preferred operator" fix - let assist_message = format!("Replace '{}' with '{}'", context.op, context.op.preferred()); - let edit = TextEdit::replace( - context.op.range(range, context.preceding_ws_range), - context.op.preferred().to_string(), - ); - fixes.push(fix( - "replace_boolean_operator", - &assist_message, - SourceChange::from_text_edit(file_id, edit), - range, - )); - - // Add "add parens" fixes if applicable - if context.lhs_complex { - fixes.push(parens_fix("LHS", file_id, context, range)); - } - if context.rhs_complex { - fixes.push(parens_fix("RHS", file_id, context, range)); - } - - Some(fixes) - } -} - -fn parens_fix(side: &str, file_id: FileId, context: &Context, range: TextRange) -> Assist { - let assist_message = format!("Add parens to {side}"); - let edit = add_parens_edit(&context.add_parens_range); - fix( - "replace_boolean_operator_add_parens", - &assist_message, - SourceChange::from_text_edit(file_id, edit), - range, - ) -} - -fn check_function( - matches: &mut Vec>, - sema: &Semantic, - def: &FunctionDef, -) { +fn check_function(diagnostics: &mut Vec, sema: &Semantic, def: &FunctionDef) { let def_fb = def.in_function_body(sema, def); def_fb.clone().fold_function( Strategy { @@ -170,20 +91,28 @@ fn check_function( _ => None, }; if let Some(op) = op { - collect_match(matches, sema, &def_fb, def.file.file_id, clause_id, ctx, op); + report( + sema, + &def_fb, + def.file.file_id, + clause_id, + ctx, + op, + diagnostics, + ); } }, ) } -fn collect_match( - matches: &mut Vec>, +fn report( sema: &Semantic, def_fb: &InFunctionBody<&FunctionDef>, file_id: FileId, clause_id: ClauseId, ctx: AnyCallBackCtx, binop: (Op, ExprId, ExprId), + diagnostics: &mut Vec, ) -> Option<()> { /* we have (inserting parens for tree) @@ -227,25 +156,39 @@ fn collect_match( let (_op, token) = binop_ast.op()?; let range = token.text_range(); let preceding_ws_range = include_preceding_whitespace(&token); - - matches.push(GenericLinterMatchContext { - range, - context: Context { - preceding_ws_range, - op: binop, - lhs_complex, - rhs_complex, - add_parens_range, - }, - }); + let mut d = make_diagnostic(file_id, range, preceding_ws_range, binop) + .with_ignore_fix(sema, def_fb.file_id()); + if lhs_complex { + add_parens_fix(file_id, &range, add_parens_range, "LHS", &mut d); + } + if rhs_complex { + add_parens_fix(file_id, &range, add_parens_range, "RHS", &mut d); + } + diagnostics.push(d); } }; Some(()) } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +fn add_parens_fix( + file_id: FileId, + range: &TextRange, + expr_range: TextRange, + where_str: &str, + diag: &mut Diagnostic, +) { + let assist_message = format!("Add parens to {where_str}"); + let edit = add_parens_edit(&expr_range); + diag.add_fix(fix( + "replace_boolean_operator_add_parens", + &assist_message, + SourceChange::from_text_edit(file_id, edit.clone()), + *range, + )); +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Op { - #[default] And, AndInGuard, Or, @@ -280,7 +223,31 @@ impl Op { } } -pub static LINTER: BooleanPrecedenceLinter = BooleanPrecedenceLinter; +fn make_diagnostic( + file_id: FileId, + range: TextRange, + preceding_ws_range: TextRange, + op: Op, +) -> Diagnostic { + let message = format!( + "Consider using the short-circuit expression '{}' instead of '{}'.\nOr add parentheses to avoid potential ambiguity.", + op.preferred(), + op, + ); + let assist_message = format!("Replace '{}' with '{}'", op, op.preferred()); + let edit = TextEdit::replace( + op.range(range, preceding_ws_range), + op.preferred().to_string(), + ); + Diagnostic::new(DiagnosticCode::BooleanPrecedence, message, range) + .with_severity(Severity::Warning) + .with_fixes(Some(vec![fix( + "replace_boolean_operator", + &assist_message, + SourceChange::from_text_edit(file_id, edit.clone()), + range, + )])) +} #[cfg(test)] mod tests { diff --git a/crates/ide/src/diagnostics/bound_variable.rs b/crates/ide/src/diagnostics/bound_variable.rs deleted file mode 100644 index 92f0edadfa..0000000000 --- a/crates/ide/src/diagnostics/bound_variable.rs +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is dual-licensed under either the MIT license found in the - * LICENSE-MIT file in the root directory of this source tree or the Apache - * License, Version 2.0 found in the LICENSE-APACHE file in the root directory - * of this source tree. You may select, at your option, one of the - * above-listed licenses. - */ - -// Diagnostic: bound_variable -// -// Return a warning if the LHS of a match already contains a bound variable. -// - -use elp_ide_db::elp_base_db::FileId; -use hir::AnyExpr; -use hir::Expr; -use hir::Semantic; -use hir::Strategy; -use hir::fold::MacroStrategy; -use hir::fold::ParenStrategy; - -use crate::diagnostics::DiagnosticCode; -use crate::diagnostics::GenericLinter; -use crate::diagnostics::GenericLinterMatchContext; -use crate::diagnostics::Linter; - -pub(crate) struct BoundVariableLinter; - -impl Linter for BoundVariableLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::BoundVarInLhs - } - - fn description(&self) -> &'static str { - "Match on a bound variable" - } -} - -impl GenericLinter for BoundVariableLinter { - type Context = (); - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let bound_vars_by_function = sema.bound_vars_by_function(file_id); - let mut res = Vec::new(); - sema.def_map(file_id) - .get_function_clauses() - .for_each(|(_, def)| { - if def.file.file_id == file_id - && let Some(bound_vars) = bound_vars_by_function.get(&def.function_clause_id) - { - let in_clause = def.in_clause(sema, def); - in_clause.fold_clause( - Strategy { - macros: MacroStrategy::ExpandButIncludeMacroCall, - parens: ParenStrategy::InvisibleParens, - }, - (), - &mut |acc, ctx| { - if let AnyExpr::Expr(Expr::Match { lhs, rhs: _ }) = ctx.item - && bound_vars.contains(&lhs) - && let Some(range) = in_clause.range_for_pat(lhs) - && range.file_id == def.file.file_id - && ctx.in_macro.is_none() - { - res.push(GenericLinterMatchContext { - range: range.range, - context: (), - }); - }; - acc - }, - ); - } - }); - - Some(res) - } -} - -pub static LINTER: BoundVariableLinter = BoundVariableLinter; - -#[cfg(test)] -mod test { - use elp_ide_db::DiagnosticCode; - use expect_test::Expect; - - use crate::diagnostics::DiagnosticsConfig; - use crate::tests::check_diagnostics_with_config; - use crate::tests::check_fix_with_config; - - #[track_caller] - pub(crate) fn check_diagnostics(fixture: &str) { - let config = DiagnosticsConfig::default().disable(DiagnosticCode::UndefinedFunction); - check_diagnostics_with_config(config, fixture) - } - - #[track_caller] - pub(crate) fn check_fix(fixture_before: &str, fixture_after: Expect) { - let config = DiagnosticsConfig::default().disable(DiagnosticCode::UndefinedFunction); - check_fix_with_config(config, fixture_before, fixture_after) - } - #[test] - fn bound_variable() { - check_diagnostics( - r#" - //- /src/bound.erl - -module(bound). - - foo() -> - AA = bar(), - AA = bar(). - %% ^^ 💡 warning: W0060: Match on a bound variable - - "#, - ) - } - - #[test] - fn bound_variable_not_reported_in_case() { - check_diagnostics( - r#" - //- /src/bound.erl - -module(bound). - - foo(Val) -> - case Val of - undefined -> ok; - Val when is_list(Val) -> ok - end. - - "#, - ) - } - - #[test] - fn bound_variable_not_reported_in_macro() { - check_diagnostics( - r#" - //- /src/bound.erl - -module(bound). - -include("inc.hrl"). - - foo(Val) -> - ?A_MACRO(Val). - //- /src/inc.hrl - -define(A_MACRO(X), X=X). - "#, - ) - } - - #[test] - fn bound_variable_ignore_fix() { - check_fix( - r#" - //- /src/bound.erl - -module(bound). - - foo() -> - AA = bar(), - A~A = bar(). - "#, - expect_test::expect![[r#" - -module(bound). - - foo() -> - AA = bar(), - % elp:ignore W0060 (bound_var_in_lhs) - AA = bar(). - "#]], - ) - } -} diff --git a/crates/ide/src/diagnostics/could_be_a_string_literal.rs b/crates/ide/src/diagnostics/could_be_a_string_literal.rs index 03ea0e6274..d939163222 100644 --- a/crates/ide/src/diagnostics/could_be_a_string_literal.rs +++ b/crates/ide/src/diagnostics/could_be_a_string_literal.rs @@ -39,7 +39,7 @@ impl Linter for CouldBeAStringLiteralLinter { "Could be rewritten as a literal." } - fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { + fn severity(&self) -> Severity { Severity::Information } } diff --git a/crates/ide/src/diagnostics/cross_node_eval.rs b/crates/ide/src/diagnostics/cross_node_eval.rs index f50ca663e3..56cf2e1299 100644 --- a/crates/ide/src/diagnostics/cross_node_eval.rs +++ b/crates/ide/src/diagnostics/cross_node_eval.rs @@ -12,9 +12,6 @@ //! //! Return a diagnostic for rpc calls to remote nodes. -use elp_ide_db::elp_base_db::FileId; -use hir::Semantic; - use crate::codemod_helpers::FunctionMatch; use crate::diagnostics::DiagnosticCode; use crate::diagnostics::FunctionCallLinter; @@ -31,7 +28,7 @@ impl Linter for CrossNodeEvalLinter { fn description(&self) -> &'static str { "Production code must not use cross node eval (e.g. `rpc:call()`)" } - fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { + fn severity(&self) -> Severity { Severity::Error } fn should_process_test_files(&self) -> bool { diff --git a/crates/ide/src/diagnostics/debugging_function.rs b/crates/ide/src/diagnostics/debugging_function.rs index 1f0099781d..904ebe3098 100644 --- a/crates/ide/src/diagnostics/debugging_function.rs +++ b/crates/ide/src/diagnostics/debugging_function.rs @@ -11,7 +11,7 @@ use elp_ide_assists::Assist; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChangeBuilder; -use elp_ide_db::text_edit::TextRange; +use elp_text_edit::TextRange; use hir::Semantic; use crate::FunctionMatch; @@ -22,7 +22,7 @@ use crate::diagnostics::DiagnosticCode; use crate::diagnostics::FunctionCallLinter; use crate::diagnostics::Linter; use crate::diagnostics::Severity; -// @fb-only: use crate::diagnostics::meta_only; +// @fb-only use crate::lazy_function_matches; pub(crate) struct NoDebuggingFunctionLinter; @@ -34,10 +34,10 @@ impl Linter for NoDebuggingFunctionLinter { fn description(&self) -> &'static str { "Debugging functions should only be used during local debugging and usages should not be checked in." } - fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { + fn severity(&self) -> Severity { Severity::WeakWarning } - fn cli_severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { + fn cli_severity(&self) -> Severity { Severity::Error } fn should_process_generated_files(&self) -> bool { @@ -52,7 +52,7 @@ impl FunctionCallLinter for NoDebuggingFunctionLinter { lazy_function_matches![ vec![FunctionMatch::m("redbug")] .into_iter() - // @fb-only: .chain(meta_only::debugging_function_matches().into_iter()) + // @fb-only .collect::>() ] } diff --git a/crates/ide/src/diagnostics/dependent_header.rs b/crates/ide/src/diagnostics/dependent_header.rs index 4729f05872..e0b4d11652 100644 --- a/crates/ide/src/diagnostics/dependent_header.rs +++ b/crates/ide/src/diagnostics/dependent_header.rs @@ -14,10 +14,10 @@ use elp_ide_db::elp_base_db::FileId; use elp_ide_db::elp_base_db::FileKind; -use elp_ide_db::text_edit::TextRange; use elp_syntax::AstNode; use elp_syntax::ast; use elp_syntax::ast::RecordName; +use elp_text_edit::TextRange; use hir::AnyExpr; use hir::InFile; use hir::Name; diff --git a/crates/ide/src/diagnostics/deprecated_function.rs b/crates/ide/src/diagnostics/deprecated_function.rs index b353d824d2..3956282c45 100644 --- a/crates/ide/src/diagnostics/deprecated_function.rs +++ b/crates/ide/src/diagnostics/deprecated_function.rs @@ -21,10 +21,10 @@ use elp_ide_assists::Assist; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; -use elp_ide_db::text_edit::TextRange; -use elp_ide_db::text_edit::TextSize; use elp_syntax::AstNode; +use elp_text_edit::TextEdit; +use elp_text_edit::TextRange; +use elp_text_edit::TextSize; use hir::AnyExpr; use hir::Expr; use hir::FunctionDef; @@ -41,7 +41,7 @@ use super::DiagnosticDescriptor; use super::Severity; use crate::codemod_helpers::FunctionMatch; use crate::codemod_helpers::FunctionMatcher; -// @fb-only: use crate::diagnostics; +// @fb-only use crate::fix; pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { @@ -88,7 +88,7 @@ fn deprecated_function(diagnostics: &mut Vec, sema: &Semantic, file_ lazy_static! { static ref DEPRECATED_FUNCTIONS: Vec<(FunctionMatch, DeprecationDetails)> = { let matches: Vec> = vec![ - // @fb-only: diagnostics::meta_only::deprecated_function_matches(), + // @fb-only ]; matches.into_iter() .flatten() @@ -134,8 +134,8 @@ fn check_function( ); let details = match_result.map(|(_match, details)| details.clone()); if target_def.deprecated || match_result.is_some() { - let expr_id = if let Some((hir_idx, _macro_def)) = ctx.in_macro { - hir_idx.idx + let expr_id = if let Some(expr_id) = ctx.in_macro { + expr_id.idx } else { ctx.item_id }; diff --git a/crates/ide/src/diagnostics/duplicate_module.rs b/crates/ide/src/diagnostics/duplicate_module.rs index 09eb548b31..d9e01ecc53 100644 --- a/crates/ide/src/diagnostics/duplicate_module.rs +++ b/crates/ide/src/diagnostics/duplicate_module.rs @@ -12,58 +12,51 @@ // // Return a warning if more than one module has the same name +use elp_ide_db::DiagnosticCode; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::elp_base_db::ModuleName; use elp_syntax::AstNode; use hir::Semantic; -use crate::diagnostics::DiagnosticCode; -use crate::diagnostics::GenericLinter; -use crate::diagnostics::GenericLinterMatchContext; -use crate::diagnostics::Linter; +use super::Diagnostic; +use super::DiagnosticConditions; +use super::DiagnosticDescriptor; +use crate::diagnostics::Severity; -pub(crate) struct DuplicateModuleLinter; +pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { + conditions: DiagnosticConditions { + experimental: false, + include_generated: false, + include_tests: false, // Allow duplication in test fixtures + default_disabled: false, + }, + checker: &|diags, sema, file_id, _file_kind| { + check_file(diags, sema, &file_id); + }, +}; -impl Linter for DuplicateModuleLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::DuplicateModule - } - - fn description(&self) -> &'static str { - "A module with this name exists elsewhere" - } - - fn should_process_test_files(&self) -> bool { - false // Allow duplication in test fixtures +fn check_file(acc: &mut Vec, sema: &Semantic, file_id: &FileId) -> Option<()> { + // We cannot ask for the module name from the module_index, as + // this file_id may be discarded as a duplicate + let module_name_ast = sema.module_attribute_name(*file_id)?; + let module_name = ModuleName::new(module_name_ast.text()?.as_str()); + + let app_data = sema.db.file_app_data(*file_id)?; + let module_index = sema.db.module_index(app_data.project_id); + if let Some(_dups) = module_index.duplicates(&module_name) { + let range = module_name_ast.syntax().text_range(); + acc.push( + Diagnostic::new( + DiagnosticCode::DuplicateModule, + "Duplicate module name", + range, + ) + .with_severity(Severity::Warning), + ); } + Some(()) } -impl GenericLinter for DuplicateModuleLinter { - type Context = (); - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let mut res = Vec::new(); - // We cannot ask for the module name from the module_index, as - // this file_id may be discarded as a duplicate - let module_name_ast = sema.module_attribute_name(file_id)?; - let module_name = ModuleName::new(module_name_ast.text()?.as_str()); - - let app_data = sema.db.file_app_data(file_id)?; - let module_index = sema.db.module_index(app_data.project_id); - if let Some(_dups) = module_index.duplicates(&module_name) { - let range = module_name_ast.syntax().text_range(); - res.push(GenericLinterMatchContext { range, context: () }); - } - Some(res) - } -} - -pub static LINTER: DuplicateModuleLinter = DuplicateModuleLinter; - #[cfg(test)] mod test { use crate::tests::check_diagnostics; @@ -74,11 +67,11 @@ mod test { r#" //- /src/dup_mod.erl -module(dup_mod). - %% ^^^^^^^ 💡 warning: W0045: A module with this name exists elsewhere + %% ^^^^^^^ warning: W0045: Duplicate module name //- /src/sub/dup_mod.erl -module(dup_mod). - %% ^^^^^^^ 💡 warning: W0045: A module with this name exists elsewhere + %% ^^^^^^^ warning: W0045: Duplicate module name "#, ) } diff --git a/crates/ide/src/diagnostics/old_edoc_syntax.rs b/crates/ide/src/diagnostics/edoc.rs similarity index 92% rename from crates/ide/src/diagnostics/old_edoc_syntax.rs rename to crates/ide/src/diagnostics/edoc.rs index da4c3f2430..53858e7cca 100644 --- a/crates/ide/src/diagnostics/old_edoc_syntax.rs +++ b/crates/ide/src/diagnostics/edoc.rs @@ -8,138 +8,96 @@ * above-listed licenses. */ -// Diagnostic: old_edoc_syntax +// Diagnostic: edoc -use elp_ide_assists::Assist; use elp_ide_assists::helpers; use elp_ide_assists::helpers::extend_range; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChangeBuilder; -use elp_ide_db::text_edit::TextRange; -use elp_ide_db::text_edit::TextSize; use elp_syntax::AstNode; -use elp_syntax::ast; +use elp_text_edit::TextRange; +use elp_text_edit::TextSize; use fxhash::FxHashSet; use hir::Attribute; -use hir::InFileAstPtr; use hir::Semantic; use hir::edoc::EdocHeader; use hir::edoc::EdocHeaderKind; use hir::known; +use super::Diagnostic; use super::DiagnosticCode; -use super::GenericLinter; -use super::GenericLinterMatchContext; -use super::Linter; +use super::DiagnosticConditions; +use super::DiagnosticDescriptor; +use super::Severity; -pub(crate) struct OldEdocSyntaxLinter; +const DIAGNOSTIC_CODE: DiagnosticCode = DiagnosticCode::OldEdocSyntax; +const DIAGNOSTIC_MESSAGE: &str = "EDoc style comments are deprecated. Please use Markdown instead."; +const CONVERT_FIX_ID: &str = "convert_to_markdown"; +const CONVERT_FIX_LABEL: &str = "Convert to Markdown"; -impl Linter for OldEdocSyntaxLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::OldEdocSyntax - } +pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { + conditions: DiagnosticConditions { + experimental: false, + include_generated: false, + include_tests: true, + default_disabled: false, + }, + checker: &|diags, sema, file_id, _ext| { + check(diags, sema, file_id); + }, +}; - fn description(&self) -> &'static str { - "EDoc style comments are deprecated. Please use Markdown instead." - } - - fn should_process_test_files(&self) -> bool { - false - } -} - -#[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct Context { - header_ptr: Option>, - doc_start: TextSize, -} - -impl GenericLinter for OldEdocSyntaxLinter { - type Context = Context; - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let mut res = Vec::new(); - if let Some(comments) = sema.file_edoc_comments(file_id) { - for (header_ptr, header) in comments.iter() { - if let Some(doc) = &header.doc { - if let Some(doc_start) = header.start() { - res.push(GenericLinterMatchContext { - range: doc.range, - context: Context { - header_ptr: Some(*header_ptr), - doc_start, - }, - }); - } - } else if let Some(equiv) = &header.equiv { - if let Some(doc_start) = header.start() { - res.push(GenericLinterMatchContext { - range: equiv.range, - context: Context { - header_ptr: Some(*header_ptr), - doc_start, - }, - }); - } - } else if let Some(deprecated) = &header.deprecated { - if let Some(doc_start) = header.start() { - res.push(GenericLinterMatchContext { - range: deprecated.range, - context: Context { - header_ptr: Some(*header_ptr), - doc_start, - }, - }); - } - } else if let Some(hidden) = &header.hidden - && let Some(doc_start) = header.start() - { - res.push(GenericLinterMatchContext { - range: hidden.range, - context: Context { - header_ptr: Some(*header_ptr), - doc_start, - }, - }); +fn check(diagnostics: &mut Vec, sema: &Semantic, file_id: FileId) { + if let Some(comments) = sema.file_edoc_comments(file_id) { + for header in comments.values() { + if let Some(doc) = &header.doc { + if let Some(doc_start) = header.start() { + diagnostics.push(old_edoc_syntax_diagnostic( + sema, file_id, doc.range, header, doc_start, + )); } + } else if let Some(equiv) = &header.equiv { + if let Some(doc_start) = header.start() { + diagnostics.push(old_edoc_syntax_diagnostic( + sema, + file_id, + equiv.range, + header, + doc_start, + )); + } + } else if let Some(deprecated) = &header.deprecated { + if let Some(doc_start) = header.start() { + diagnostics.push(old_edoc_syntax_diagnostic( + sema, + file_id, + deprecated.range, + header, + doc_start, + )); + } + } else if let Some(hidden) = &header.hidden + && let Some(doc_start) = header.start() + { + diagnostics.push(old_edoc_syntax_diagnostic( + sema, + file_id, + hidden.range, + header, + doc_start, + )); } } - Some(res) - } - - fn fixes( - &self, - context: &Self::Context, - range: TextRange, - sema: &Semantic, - file_id: FileId, - ) -> Option> { - let comments = sema.file_edoc_comments(file_id)?; - let header_ptr = context.header_ptr.as_ref()?; - let header = comments.get(header_ptr)?; - Some(vec![old_edoc_syntax_fix( - sema, - file_id, - header, - context.doc_start, - range, - )]) } } -pub static LINTER: OldEdocSyntaxLinter = OldEdocSyntaxLinter; - -fn old_edoc_syntax_fix( +fn old_edoc_syntax_diagnostic( sema: &Semantic, file_id: FileId, + show_range: TextRange, header: &EdocHeader, start_offset: TextSize, - range: TextRange, -) -> Assist { +) -> Diagnostic { let eep59_insert_offset = match header.kind { EdocHeaderKind::Module => { helpers::moduledoc_insert_offset(sema, file_id).unwrap_or(start_offset) @@ -177,12 +135,17 @@ fn old_edoc_syntax_fix( } builder.insert(eep59_insert_offset, header.to_eep59()); let source_change = builder.finish(); - crate::fix( - "convert_to_markdown", - "Convert to Markdown", - source_change, - range, - ) + let fix = crate::fix(CONVERT_FIX_ID, CONVERT_FIX_LABEL, source_change, show_range); + Diagnostic::new(DIAGNOSTIC_CODE, DIAGNOSTIC_MESSAGE, show_range) + .with_severity(severity(sema, file_id)) + .with_fixes(Some(vec![fix])) +} + +fn severity(sema: &Semantic, file_id: FileId) -> Severity { + match sema.db.is_test_suite_or_test_helper(file_id) { + Some(true) => Severity::WeakWarning, + _ => Severity::Warning, + } } fn author_exists(author: &str, authors: &FxHashSet) -> bool { @@ -294,6 +257,22 @@ mod tests { ) } + #[test] + fn test_function_doc_in_test_file() { + check_diagnostics( + r#" + //- /test/main_SUITE.erl extra:test + -module(main_SUITE). + %% @doc This is the main function documentation. + %% ^^^^ 💡 weak: W0038: EDoc style comments are deprecated. Please use Markdown instead. + main() -> + dep(). + + dep() -> ok. + "#, + ) + } + #[test] fn test_function_doc_different_arities() { check_diagnostics( diff --git a/crates/ide/src/diagnostics/effect_free_statement.rs b/crates/ide/src/diagnostics/effect_free_statement.rs index 9aec815fbb..72d6c8eb8d 100644 --- a/crates/ide/src/diagnostics/effect_free_statement.rs +++ b/crates/ide/src/diagnostics/effect_free_statement.rs @@ -17,11 +17,11 @@ use std::iter; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; use elp_syntax::AstNode; use elp_syntax::SyntaxElement; use elp_syntax::SyntaxKind; use elp_syntax::ast; +use elp_text_edit::TextEdit; use hir::AnyExprId; use hir::Expr; use hir::ExprId; diff --git a/crates/ide/src/diagnostics/eqwalizer_assists/expected_type.rs b/crates/ide/src/diagnostics/eqwalizer_assists/expected_type.rs index 081f6e43ae..ee655d2f8c 100644 --- a/crates/ide/src/diagnostics/eqwalizer_assists/expected_type.rs +++ b/crates/ide/src/diagnostics/eqwalizer_assists/expected_type.rs @@ -15,8 +15,8 @@ use elp_ide_db::elp_base_db::FileId; use elp_ide_db::elp_base_db::FilePosition; use elp_ide_db::find_best_token; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; -use elp_ide_db::text_edit::TextSize; +use elp_text_edit::TextEdit; +use elp_text_edit::TextSize; use elp_types_db::eqwalizer::StructuredDiagnostic; use elp_types_db::eqwalizer::tc_diagnostics::ExpectedSubtype; use elp_types_db::eqwalizer::tc_diagnostics::TypeError; diff --git a/crates/ide/src/diagnostics/expression_can_be_simplified.rs b/crates/ide/src/diagnostics/expression_can_be_simplified.rs index 4c9144e5c0..4f3ce6ac57 100644 --- a/crates/ide/src/diagnostics/expression_can_be_simplified.rs +++ b/crates/ide/src/diagnostics/expression_can_be_simplified.rs @@ -261,19 +261,10 @@ fn as_expr_id(any_expre_id: hir::AnyExprId) -> Option { #[cfg(test)] mod tests { - use elp_ide_db::DiagnosticCode; - use expect_test::Expect; use expect_test::expect; - use crate::diagnostics::DiagnosticsConfig; use crate::tests::check_diagnostics; - use crate::tests::check_fix_with_config; - - #[track_caller] - fn check_fix(fixture_before: &str, fixture_after: Expect) { - let config = DiagnosticsConfig::default().disable(DiagnosticCode::MissingModule); - check_fix_with_config(config, fixture_before, fixture_after); - } + use crate::tests::check_fix; #[test] fn test_generates_diagnostics() { diff --git a/crates/ide/src/diagnostics/from_config.rs b/crates/ide/src/diagnostics/from_config.rs index 250fa4422d..678ffbd369 100644 --- a/crates/ide/src/diagnostics/from_config.rs +++ b/crates/ide/src/diagnostics/from_config.rs @@ -131,7 +131,6 @@ pub struct MatchSsr { pub ssr_pattern: String, pub message: Option, pub strategy: Option, - pub severity: Option, } impl Serialize for MatchSsr { @@ -141,14 +140,11 @@ impl Serialize for MatchSsr { { use serde::ser::SerializeStruct; - let mut state = serializer.serialize_struct("MatchSsr", 5)?; + let mut state = serializer.serialize_struct("MatchSsr", 4)?; state.serialize_field("ssr_pattern", &self.ssr_pattern)?; if let Some(ref message) = self.message { state.serialize_field("message", message)?; } - if let Some(ref severity) = self.severity { - state.serialize_field("severity", severity)?; - } if let Some(strategy) = self.strategy { // Default strategy is Expand and InvisibleParens let is_default = strategy.macros == MacroStrategy::Expand @@ -189,8 +185,6 @@ impl<'de> Deserialize<'de> for MatchSsr { #[serde(default)] message: Option, #[serde(default)] - severity: Option, - #[serde(default)] macro_strategy: Option, #[serde(default)] paren_strategy: Option, @@ -242,7 +236,6 @@ impl<'de> Deserialize<'de> for MatchSsr { ssr_pattern: helper.ssr_pattern, message: helper.message, strategy, - severity: helper.severity, }) } } @@ -263,13 +256,12 @@ impl MatchSsr { .clone() .unwrap_or_else(|| format!("SSR pattern matched: {}", self.ssr_pattern)); - let severity = self.severity.unwrap_or(Severity::WeakWarning); let diag = Diagnostic::new( DiagnosticCode::AdHoc("ssr-match".to_string()), message, matched.range.range, ) - .with_severity(severity); + .with_severity(Severity::WeakWarning); acc.push(diag); } } @@ -665,7 +657,6 @@ mod tests { ssr_pattern: "ssr: _@A = 10.".to_string(), message: Some("Found pattern".to_string()), strategy: None, - severity: None, }) .unwrap(); expect![[r#" @@ -692,7 +683,6 @@ mod tests { "Found pattern", ), strategy: None, - severity: None, } "#]] .assert_debug_eq(&match_ssr); @@ -705,7 +695,6 @@ mod tests { ssr_pattern: "ssr: _@A = 10.".to_string(), message: Some("Found pattern".to_string()), strategy: None, - severity: None, })], }) .unwrap(); @@ -728,7 +717,6 @@ mod tests { macros: MacroStrategy::Expand, parens: ParenStrategy::InvisibleParens, }), - severity: None, })], }) .unwrap(); @@ -751,7 +739,6 @@ mod tests { macros: MacroStrategy::DoNotExpand, parens: ParenStrategy::VisibleParens, }), - severity: None, })], }) .unwrap(); @@ -795,7 +782,6 @@ mod tests { parens: VisibleParens, }, ), - severity: None, }, ), ], @@ -803,181 +789,4 @@ mod tests { "#]] .assert_debug_eq(&match_ssr); } - - #[test] - fn serde_serialize_match_ssr_with_severity_error() { - use crate::diagnostics::Severity; - let result = toml::to_string::(&MatchSsr { - ssr_pattern: "ssr: _@A = 10.".to_string(), - message: Some("Found pattern".to_string()), - strategy: None, - severity: Some(Severity::Error), - }) - .unwrap(); - expect![[r#" - ssr_pattern = "ssr: _@A = 10." - message = "Found pattern" - severity = "error" - "#]] - .assert_eq(&result); - } - - #[test] - fn serde_serialize_match_ssr_with_severity_warning() { - use crate::diagnostics::Severity; - let result = toml::to_string::(&MatchSsr { - ssr_pattern: "ssr: _@A = 10.".to_string(), - message: Some("Found pattern".to_string()), - strategy: None, - severity: Some(Severity::Warning), - }) - .unwrap(); - expect![[r#" - ssr_pattern = "ssr: _@A = 10." - message = "Found pattern" - severity = "warning" - "#]] - .assert_eq(&result); - } - - #[test] - fn serde_serialize_match_ssr_with_severity_weak() { - use crate::diagnostics::Severity; - let result = toml::to_string::(&MatchSsr { - ssr_pattern: "ssr: _@A = 10.".to_string(), - message: Some("Found pattern".to_string()), - strategy: None, - severity: Some(Severity::WeakWarning), - }) - .unwrap(); - expect![[r#" - ssr_pattern = "ssr: _@A = 10." - message = "Found pattern" - severity = "weak" - "#]] - .assert_eq(&result); - } - - #[test] - fn serde_serialize_match_ssr_with_severity_info() { - use crate::diagnostics::Severity; - let result = toml::to_string::(&MatchSsr { - ssr_pattern: "ssr: _@A = 10.".to_string(), - message: Some("Found pattern".to_string()), - strategy: None, - severity: Some(Severity::Information), - }) - .unwrap(); - expect![[r#" - ssr_pattern = "ssr: _@A = 10." - message = "Found pattern" - severity = "info" - "#]] - .assert_eq(&result); - } - - #[test] - fn serde_deserialize_match_ssr_with_severity() { - use crate::diagnostics::Severity; - let match_ssr: MatchSsr = toml::from_str( - r#" - ssr_pattern = "ssr: _@A = 10." - message = "Found pattern" - severity = "error" - "#, - ) - .unwrap(); - - assert_eq!(match_ssr.severity, Some(Severity::Error)); - } - - #[test] - fn serde_deserialize_lint_match_ssr_with_severity() { - use crate::diagnostics::Severity; - let lints: LintsFromConfig = toml::from_str( - r#" - [[lints]] - type = "LintMatchSsr" - ssr_pattern = "ssr: _@A = 10." - message = "Found pattern" - severity = "warning" - "#, - ) - .unwrap(); - - match &lints.lints[0] { - Lint::LintMatchSsr(match_ssr) => { - assert_eq!(match_ssr.severity, Some(Severity::Warning)); - } - _ => panic!("Expected LintMatchSsr"), - } - } - - #[test] - fn serde_serialize_lint_match_ssr_with_severity_and_strategy() { - use crate::diagnostics::Severity; - let result = toml::to_string::(&LintsFromConfig { - lints: vec![Lint::LintMatchSsr(MatchSsr { - ssr_pattern: "ssr: _@A = 10.".to_string(), - message: Some("Found pattern".to_string()), - strategy: Some(Strategy { - macros: MacroStrategy::DoNotExpand, - parens: ParenStrategy::VisibleParens, - }), - severity: Some(Severity::Error), - })], - }) - .unwrap(); - expect![[r#" - [[lints]] - type = "LintMatchSsr" - ssr_pattern = "ssr: _@A = 10." - message = "Found pattern" - severity = "error" - macro_strategy = "no-expand" - paren_strategy = "visible" - "#]] - .assert_eq(&result); - } - - #[test] - fn serde_deserialize_lint_match_ssr_with_severity_and_strategy() { - let lints: LintsFromConfig = toml::from_str( - r#" - [[lints]] - type = "LintMatchSsr" - ssr_pattern = "ssr: _@A = 10." - message = "Found pattern" - severity = "error" - macro_strategy = "no-expand" - paren_strategy = "visible" - "#, - ) - .unwrap(); - - expect![[r#" - LintsFromConfig { - lints: [ - LintMatchSsr( - MatchSsr { - ssr_pattern: "ssr: _@A = 10.", - message: Some( - "Found pattern", - ), - strategy: Some( - Strategy { - macros: DoNotExpand, - parens: VisibleParens, - }, - ), - severity: Some( - Error, - ), - }, - ), - ], - } - "#]] - .assert_debug_eq(&lints); - } } diff --git a/crates/ide/src/diagnostics/head_mismatch.rs b/crates/ide/src/diagnostics/head_mismatch.rs index edfb1d8518..425ed09e6d 100644 --- a/crates/ide/src/diagnostics/head_mismatch.rs +++ b/crates/ide/src/diagnostics/head_mismatch.rs @@ -13,13 +13,13 @@ use std::hash::Hash; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; use elp_syntax::SyntaxToken; use elp_syntax::TextRange; use elp_syntax::ast; use elp_syntax::ast::AstNode; use elp_syntax::ast::ClauseSeparator; use elp_syntax::syntax_node::SyntaxNode; +use elp_text_edit::TextEdit; use fxhash::FxHashMap; use hir::Semantic; @@ -270,7 +270,6 @@ impl Validate for Name { attr_loc, ) .with_related(Some(vec![RelatedInformation { - file_id, range: ref_loc, message: "Mismatched clause name".to_string(), }])) @@ -294,7 +293,7 @@ impl Validate for Arity { fn make_diagnostic( self, - file_id: FileId, + _file_id: FileId, attr: &usize, hattr: &usize, attr_loc: TextRange, @@ -306,7 +305,6 @@ impl Validate for Arity { attr_loc, ) .with_related(Some(vec![RelatedInformation { - file_id, range: ref_loc, message: "Mismatched clause".to_string(), }])) @@ -396,7 +394,6 @@ mod tests { foo(0) -> 1; boo(1) -> 2. %% ^^^ 💡 error: P1700: head mismatch 'boo' vs 'foo' - %% | Related info: 0:21-24 Mismatched clause name "#, ); check_fix( @@ -422,7 +419,6 @@ mod tests { ok; fooX(_X) -> %% ^^^^ 💡 error: P1700: head mismatch 'fooX' vs 'food' - %% | Related info: 0:21-25 Mismatched clause name no. bar() -> @@ -452,7 +448,6 @@ mod tests { -module(main). foo(0) -> 1; %% ^^^ 💡 error: P1700: head mismatch 'foo' vs 'boo' - %% | Related info: 0:37-40 Mismatched clause name boo(1) -> 2; boo(2) -> 3. "#, @@ -481,7 +476,6 @@ mod tests { foo(0) -> 1; foo(1,0) -> 2. %% ^^^^^^^^^^^^^ error: P1700: head arity mismatch 2 vs 1 - %% | Related info: 0:21-32 Mismatched clause "#, ); } @@ -494,7 +488,6 @@ mod tests { foo(2,0) -> 3; foo(0) -> 1; %% ^^^^^^^^^^^ error: P1700: head arity mismatch 1 vs 2 - %% | Related info: 0:21-34 Mismatched clause foo(1,0) -> 2. "#, ); @@ -521,7 +514,6 @@ mod tests { (0) -> ok; A(N) -> ok %% ^ 💡 error: P1700: head mismatch 'A' vs '' - %% | Related info: 0:44-53 Mismatched clause name end, F(). "#, diff --git a/crates/ide/src/diagnostics/inefficient_last.rs b/crates/ide/src/diagnostics/inefficient_last.rs index c120d7ca7f..5c1f6af896 100644 --- a/crates/ide/src/diagnostics/inefficient_last.rs +++ b/crates/ide/src/diagnostics/inefficient_last.rs @@ -38,7 +38,6 @@ pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { }, checker: &|acc, sema, file_id, _ext| { inefficient_last_hd_ssr(acc, sema, file_id); - inefficient_last_nth_ssr(acc, sema, file_id); inefficient_last_pat_ssr(acc, sema, file_id); }, }; @@ -63,24 +62,6 @@ fn inefficient_last_hd_ssr(diags: &mut Vec, sema: &Semantic, file_id }); } -// lists:nth(1, L) is functionally equivalent to hd(L) -fn inefficient_last_nth_ssr(diags: &mut Vec, sema: &Semantic, file_id: FileId) { - let matches = match_pattern_in_file_functions( - sema, - Strategy { - macros: MacroStrategy::Expand, - parens: ParenStrategy::InvisibleParens, - }, - file_id, - format!("ssr: lists:nth(1, lists:reverse({LIST_VAR})).").as_str(), - ); - matches.matches.iter().for_each(|m| { - if let Some(diagnostic) = make_diagnostic_hd(sema, file_id, m) { - diags.push(diagnostic) - } - }); -} - fn inefficient_last_pat_ssr(diags: &mut Vec, sema: &Semantic, file_id: FileId) { let matches = match_pattern_in_file_functions( sema, @@ -267,50 +248,4 @@ mod tests { "#]], ) } - - #[test] - fn ignores_inefficient_last_via_nth_when_index_is_not_one() { - check_diagnostics( - r#" - //- /src/inefficient_last.erl - -module(inefficient_last). - - % elp:ignore W0017 (undefined_function) - fn(List) -> lists:nth(3, lists:reverse(List)). - "#, - ) - } - - #[test] - fn detects_inefficient_last_via_nth() { - check_diagnostics( - r#" - //- /src/inefficient_last.erl - -module(inefficient_last). - - % elp:ignore W0017 (undefined_function) - fn(List) -> lists:nth(1, lists:reverse(List)). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0029: Unnecessary intermediate reverse list allocated. - "#, - ) - } - - #[test] - fn fixes_inefficient_last_via_nth() { - check_fix( - r#" - //- /src/inefficient_last.erl - -module(inefficient_last). - - % elp:ignore W0017 (undefined_function) - fn(List) -> lists:nth(1, lists:re~verse(List)). - "#, - expect![[r#" - -module(inefficient_last). - - % elp:ignore W0017 (undefined_function) - fn(List) -> lists:last(List). - "#]], - ) - } } diff --git a/crates/ide/src/diagnostics/lists_reverse_append.rs b/crates/ide/src/diagnostics/lists_reverse_append.rs deleted file mode 100644 index 96743b6f28..0000000000 --- a/crates/ide/src/diagnostics/lists_reverse_append.rs +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is dual-licensed under either the MIT license found in the - * LICENSE-MIT file in the root directory of this source tree or the Apache - * License, Version 2.0 found in the LICENSE-APACHE file in the root directory - * of this source tree. You may select, at your option, one of the - * above-listed licenses. - */ - -//! Lint: lists_reverse_append -//! -//! Detect patterns of the form `lists:reverse(_@L) ++ _@T` and suggest `lists:reverse(_@L, _@T)` - -use elp_ide_assists::Assist; -use elp_ide_db::DiagnosticCode; -use elp_ide_db::elp_base_db::FileId; -use elp_ide_db::source_change::SourceChangeBuilder; -use hir::Semantic; - -use crate::diagnostics::Linter; -use crate::diagnostics::SsrPatternsLinter; -use crate::fix; - -pub(crate) struct ListsReverseAppendLinter; - -impl Linter for ListsReverseAppendLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::ListsReverseAppend - } - - fn description(&self) -> &'static str { - "Use `lists:reverse/2` instead of `lists:reverse/1 ++ Tail` for better performance." - } -} - -impl SsrPatternsLinter for ListsReverseAppendLinter { - type Context = (); - - fn patterns(&self) -> Vec<(String, Self::Context)> { - vec![(format!("ssr: lists:reverse({LIST_VAR}) ++ {TAIL_VAR}."), ())] - } - - fn fixes( - &self, - _context: &Self::Context, - matched: &elp_ide_ssr::Match, - sema: &Semantic, - _file_id: FileId, - ) -> Option> { - let list_match = matched.placeholder_text(sema, LIST_VAR)?; - let tail_match = matched.placeholder_text(sema, TAIL_VAR)?; - let mut builder = SourceChangeBuilder::new(matched.range.file_id); - let replacement = format!("lists:reverse({list_match}, {tail_match})"); - let range = matched.range.range; - builder.replace(range, replacement); - let fixes = vec![fix( - "lists_reverse_append", - "Use lists:reverse/2", - builder.finish(), - range, - )]; - Some(fixes) - } -} - -pub(crate) static LINTER: ListsReverseAppendLinter = ListsReverseAppendLinter; - -static LIST_VAR: &str = "_@L"; -static TAIL_VAR: &str = "_@T"; - -#[cfg(test)] -mod tests { - - use expect_test::Expect; - use expect_test::expect; - - use crate::diagnostics::Diagnostic; - use crate::diagnostics::DiagnosticCode; - use crate::tests; - - fn filter(d: &Diagnostic) -> bool { - d.code == DiagnosticCode::ListsReverseAppend - } - - #[track_caller] - fn check_diagnostics(fixture: &str) { - tests::check_filtered_diagnostics(fixture, &filter) - } - - #[track_caller] - fn check_fix(fixture_before: &str, fixture_after: Expect) { - tests::check_fix(fixture_before, fixture_after) - } - - #[test] - fn detects_lists_reverse_append() { - check_diagnostics( - r#" - //- /src/lists_reverse_append.erl - -module(lists_reverse_append). - - reverse_and_append(List, Tail) -> - lists:reverse(List) ++ Tail. - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0056: Use `lists:reverse/2` instead of `lists:reverse/1 ++ Tail` for better performance. - "#, - ) - } - - #[test] - fn detects_lists_reverse_append_with_variables() { - check_diagnostics( - r#" - //- /src/lists_reverse_append.erl - -module(lists_reverse_append). - - process(Items, Acc) -> - lists:reverse(Items) ++ Acc. - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0056: Use `lists:reverse/2` instead of `lists:reverse/1 ++ Tail` for better performance. - "#, - ) - } - - #[test] - fn ignores_regular_reverse() { - check_diagnostics( - r#" - //- /src/lists_reverse_append.erl - -module(lists_reverse_append). - - reverse_only(List) -> - lists:reverse(List). - "#, - ) - } - - #[test] - fn ignores_regular_append() { - check_diagnostics( - r#" - //- /src/lists_reverse_append.erl - -module(lists_reverse_append). - - append_only(A, B) -> - A ++ B. - "#, - ) - } - - #[test] - fn fixes_lists_reverse_append() { - check_fix( - r#" - //- /src/lists_reverse_append.erl - -module(lists_reverse_append). - - reverse_and_append(List, Tail) -> - lists:re~verse(List) ++ Tail. - "#, - expect![[r#" - -module(lists_reverse_append). - - reverse_and_append(List, Tail) -> - lists:reverse(List, Tail). - "#]], - ) - } - - #[test] - fn fixes_lists_reverse_append_with_complex_expressions() { - check_fix( - r#" - //- /src/lists_reverse_append.erl - -module(lists_reverse_append). - - process([H|T], Acc) -> - lists:rev~erse([H|T]) ++ [1, 2, 3]. - "#, - expect![[r#" - -module(lists_reverse_append). - - process([H|T], Acc) -> - lists:reverse([H|T], [1, 2, 3]). - "#]], - ) - } -} diff --git a/crates/ide/src/diagnostics/macro_precedence_suprise.rs b/crates/ide/src/diagnostics/macro_precedence_suprise.rs index 6cd5fe2429..49c627da28 100644 --- a/crates/ide/src/diagnostics/macro_precedence_suprise.rs +++ b/crates/ide/src/diagnostics/macro_precedence_suprise.rs @@ -15,12 +15,14 @@ use elp_ide_assists::Assist; use elp_ide_assists::helpers::add_parens_edit; +use elp_ide_db::DiagnosticCode; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextRange; +use elp_text_edit::TextRange; use hir::AnyExpr; use hir::AnyExprRef; use hir::Expr; +use hir::ExprSource; use hir::Semantic; use hir::Strategy; use hir::fold::MacroStrategy; @@ -28,105 +30,91 @@ use hir::fold::ParenStrategy; use hir::fold::ParentId; use hir::fold::fold_file_functions; -use crate::diagnostics::DiagnosticCode; -use crate::diagnostics::GenericLinter; -use crate::diagnostics::GenericLinterMatchContext; -use crate::diagnostics::Linter; +use super::Diagnostic; +use super::DiagnosticConditions; +use super::DiagnosticDescriptor; +use super::Severity; use crate::fix; -#[derive(Debug, Default, Clone, PartialEq)] -pub(crate) struct MacroPrecedenceContext; +pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { + conditions: DiagnosticConditions { + experimental: false, + include_generated: true, + include_tests: true, + default_disabled: false, + }, + checker: &|diags, sema, file_id, _file_kind| { + check_file(diags, sema, &file_id); + }, +}; -pub(crate) struct MacroPrecedenceSupriseLinter; +/// Look for macro expansions. If we find one, check what the top-level expansion gives us. +fn check_file(acc: &mut Vec, sema: &Semantic, file_id: &FileId) { + let fold_strategy = Strategy { + macros: MacroStrategy::ExpandButIncludeMacroCall, + parens: ParenStrategy::VisibleParens, + }; + let index_strategy = Strategy { + macros: MacroStrategy::Expand, + parens: ParenStrategy::VisibleParens, + }; -impl Linter for MacroPrecedenceSupriseLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::MacroPrecedenceEscape - } - - fn description(&self) -> &'static str { - "The macro expansion can have unexpected precedence here" - } - - fn should_process_generated_files(&self) -> bool { - true - } -} - -impl GenericLinter for MacroPrecedenceSupriseLinter { - type Context = MacroPrecedenceContext; - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let fold_strategy = Strategy { - macros: MacroStrategy::ExpandButIncludeMacroCall, - parens: ParenStrategy::VisibleParens, - }; - let index_strategy = Strategy { - macros: MacroStrategy::Expand, - parens: ParenStrategy::VisibleParens, - }; - - let mut res = Vec::new(); - fold_file_functions(sema, fold_strategy, file_id, (), &mut |_acc, ctx| { - if let AnyExpr::Expr(Expr::MacroCall { expansion, .. }) = &ctx.item - && let Some((body, _body_map, ast)) = ctx.body_with_expr_source(sema) + fold_file_functions(sema, fold_strategy, *file_id, (), &mut |_acc, ctx| { + if let AnyExpr::Expr(Expr::MacroCall { expansion, .. }) = &ctx.item + && let Some((body, _body_map, ast)) = ctx.body_with_expr_source(sema) + { + let visible_parens_body = body.index_with_strategy(index_strategy); + if let Expr::BinaryOp { .. } = &visible_parens_body[*expansion] + && let ParentId::HirIdx(hir_idx) = ctx.parent() + && hir_idx.body_origin == ctx.body_origin { - let visible_parens_body = body.index_with_strategy(index_strategy); - if let Expr::BinaryOp { .. } = &visible_parens_body[*expansion] - && let ParentId::HirIdx(hir_idx) = ctx.parent() - && hir_idx.body_origin == ctx.body_origin - { - // We can have nested macro - // calls, which are not - // visible in the - // visible_parens_body. Report - // on the top-level one only. - let fold_body = body.index_with_strategy(fold_strategy); - match &fold_body.get_any(hir_idx.idx) { - AnyExprRef::Expr(Expr::MacroCall { .. }) => {} - _ => { - if let AnyExprRef::Expr(Expr::BinaryOp { .. }) = - &visible_parens_body.get_any(hir_idx.idx) - { - let range = ast.range(); - if range.file_id == file_id { - res.push(GenericLinterMatchContext { - range: range.range, - context: MacroPrecedenceContext, - }); - } - } + // We can have nested macro + // calls, which are not + // visible in the + // visible_parens_body. Report + // on the top-level one only. + let fold_body = body.index_with_strategy(fold_strategy); + match &fold_body.get_any(hir_idx.idx) { + AnyExprRef::Expr(Expr::MacroCall { .. }) => {} + _ => { + if let AnyExprRef::Expr(Expr::BinaryOp { .. }) = + &visible_parens_body.get_any(hir_idx.idx) + { + make_diagnostic(acc, file_id, ast); } - }; + } }; - } - }); - Some(res) - } + }; + } + }); +} - fn fixes( - &self, - _context: &Self::Context, - range: TextRange, - _sema: &Semantic, - file_id: FileId, - ) -> Option> { - let edit = add_parens_edit(&range); - let fix = fix( - "macro_precedence_add_parens", - "Add parens to macro call", - SourceChange::from_text_edit(file_id, edit), - range, +fn make_diagnostic(acc: &mut Vec, file_id: &FileId, ast: ExprSource) { + let range = ast.range(); + if range.file_id == *file_id { + let fix = add_parens_fix(*file_id, &range.range); + acc.push( + Diagnostic::new( + DiagnosticCode::MacroPrecedenceEscape, + "The macro expansion can have unexpected precedence here", + range.range, + ) + .with_severity(Severity::Warning) + .with_fixes(Some(vec![fix])), ); - Some(vec![fix]) } } -pub static LINTER: MacroPrecedenceSupriseLinter = MacroPrecedenceSupriseLinter; +fn add_parens_fix(file_id: FileId, range: &TextRange) -> Assist { + let assist_message = "Add parens to macro call".to_string(); + let edit = add_parens_edit(range); + fix( + "macro_precedence_add_parens", + &assist_message, + SourceChange::from_text_edit(file_id, edit.clone()), + *range, + ) +} #[cfg(test)] mod tests { diff --git a/crates/ide/src/diagnostics/meck.rs b/crates/ide/src/diagnostics/meck.rs index 8919ddb770..1fc115638d 100644 --- a/crates/ide/src/diagnostics/meck.rs +++ b/crates/ide/src/diagnostics/meck.rs @@ -10,8 +10,8 @@ use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChangeBuilder; -use elp_ide_db::text_edit::TextRange; -use elp_ide_db::text_edit::TextSize; +use elp_text_edit::TextRange; +use elp_text_edit::TextSize; use hir::AnyExprId; use hir::Expr; use hir::FunctionDef; diff --git a/crates/ide/src/diagnostics/missing_compile_warn_missing_spec.rs b/crates/ide/src/diagnostics/missing_compile_warn_missing_spec.rs index dd0b677dce..6114658bf2 100644 --- a/crates/ide/src/diagnostics/missing_compile_warn_missing_spec.rs +++ b/crates/ide/src/diagnostics/missing_compile_warn_missing_spec.rs @@ -1,11 +1,10 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * - * This source code is dual-licensed under either the MIT license found in the - * LICENSE-MIT file in the root directory of this source tree or the Apache + * This source code is licensed under both the MIT license found in the + * LICENSE-MIT file in the root directory of this source tree and the Apache * License, Version 2.0 found in the LICENSE-APACHE file in the root directory - * of this source tree. You may select, at your option, one of the - * above-listed licenses. + * of this source tree. */ //! Lint/fix: missing_compile_warn_missing_spec @@ -16,12 +15,11 @@ use elp_ide_assists::helpers::add_compile_option; use elp_ide_assists::helpers::rename_atom_in_compile_attribute; -use elp_ide_db::DiagnosticCode; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::elp_base_db::FileKind; use elp_ide_db::source_change::SourceChangeBuilder; -use elp_ide_db::text_edit::TextRange; use elp_syntax::AstNode; +use elp_text_edit::TextRange; use fxhash::FxHashSet; use hir::AnyExpr; use hir::CompileOptionId; @@ -38,160 +36,94 @@ use hir::known; use lazy_static::lazy_static; use super::DIAGNOSTIC_WHOLE_FILE_RANGE; -use crate::diagnostics::GenericLinter; -use crate::diagnostics::GenericLinterMatchContext; -use crate::diagnostics::Linter; -use crate::diagnostics::Severity; +use super::Diagnostic; +use super::DiagnosticConditions; +use super::DiagnosticDescriptor; use crate::fix; -pub(crate) struct MissingCompileWarnMissingSpec; +pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { + conditions: DiagnosticConditions { + experimental: false, + include_generated: false, + include_tests: false, + default_disabled: true, + }, + checker: &|diags, sema, file_id, file_kind| { + missing_compile_warn_missing_spec(diags, sema, file_id, file_kind); + }, +}; -impl Linter for MissingCompileWarnMissingSpec { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::MissingCompileWarnMissingSpec - } - fn description(&self) -> &'static str { - "Please add \"-compile(warn_missing_spec_all).\" to the module. If exported functions are not all specced, they need to be specced." - } - fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { - Severity::Error - } - fn should_process_test_files(&self) -> bool { - false - } - fn is_enabled(&self) -> bool { - false - } - fn should_process_file_id(&self, sema: &Semantic, file_id: FileId) -> bool { - let file_kind = sema.db.file_kind(file_id); - match file_kind { - FileKind::Header | FileKind::Other | FileKind::OutsideProjectModel => false, - _ => true, +fn missing_compile_warn_missing_spec( + diags: &mut Vec, + sema: &Semantic, + file_id: FileId, + file_kind: FileKind, +) { + match file_kind { + FileKind::Header | FileKind::Other | FileKind::OutsideProjectModel => { + return; } + _ => {} } -} -#[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct Context { - found: Found, - compile_option_id: Option, -} - -impl GenericLinter for MissingCompileWarnMissingSpec { - type Context = Context; - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let mut res = Vec::new(); - let form_list = sema.form_list(file_id); - if form_list.compile_attributes().next().is_none() { - res.push(GenericLinterMatchContext { - range: DIAGNOSTIC_WHOLE_FILE_RANGE, - context: Context { - found: Found::No, - compile_option_id: None, + let form_list = sema.form_list(file_id); + if form_list.compile_attributes().next().is_none() { + report_diagnostic(sema, None, file_id, (Found::No, None), diags); + } + let attributes = form_list + .compile_attributes() + .map(|(idx, compile_attribute)| { + let co = sema.db.compile_body(InFile::new(file_id, idx)); + let is_present = FoldCtx::fold_term( + Strategy { + macros: MacroStrategy::Expand, + parens: ParenStrategy::InvisibleParens, }, - }); - } - let attributes = form_list - .compile_attributes() - .map(|(idx, compile_attribute)| { - let co = sema.db.compile_body(InFile::new(file_id, idx)); - let is_present = FoldCtx::fold_term( - Strategy { - macros: MacroStrategy::Expand, - parens: ParenStrategy::InvisibleParens, - }, - &co.body, - co.value, - (Found::No, None), - &mut |acc, ctx| match &ctx.item { - AnyExpr::Term(Term::Literal(Literal::Atom(atom))) => { - let name = sema.db.lookup_atom(*atom); - if MISSING_SPEC_ALL_OPTIONS.contains(&name) { - (Found::WarnMissingSpecAll, Some(idx)) - } else if MISSING_SPEC_OPTIONS.contains(&name) { - (Found::WarnMissingSpec, Some(idx)) - } else { - acc - } + &co.body, + co.value, + (Found::No, None), + &mut |acc, ctx| match &ctx.item { + AnyExpr::Term(Term::Literal(Literal::Atom(atom))) => { + let name = sema.db.lookup_atom(*atom); + if MISSING_SPEC_ALL_OPTIONS.contains(&name) { + (Found::WarnMissingSpecAll, Some(idx)) + } else if MISSING_SPEC_OPTIONS.contains(&name) { + (Found::WarnMissingSpec, Some(idx)) + } else { + acc } - _ => acc, - }, - ); - (is_present, compile_attribute) - }) - .collect::>(); - let what = attributes - .iter() - .fold((Found::No, None), |acc, ((present, idx), _)| { - if acc.0 == Found::No { - (*present, *idx) - } else { - acc - } - }); - if what.0 != Found::WarnMissingSpecAll { - // Report on first compile attribute only - if let Some((_, compile_attribute)) = attributes.first() { - let range = compile_attribute - .form_id - .get_ast(sema.db, file_id) - .syntax() - .text_range(); - res.push(GenericLinterMatchContext { - range, - context: Context { - found: what.0, - compile_option_id: what.1, - }, - }); - } - } - Some(res) - } + } + _ => acc, + }, + ); + (is_present, compile_attribute) + }) + .collect::>(); - fn fixes( - &self, - context: &Self::Context, - range: TextRange, - sema: &Semantic, - file_id: FileId, - ) -> Option> { - let mut builder = SourceChangeBuilder::new(file_id); - if context.found == Found::No { - add_compile_option(sema, file_id, "warn_missing_spec_all", None, &mut builder); - } else { - // We already have warn_missing_spec, upgrade it to warn_missing_spec_all - if let Some(co_id) = context.compile_option_id { - rename_atom_in_compile_attribute( - sema, - file_id, - &co_id, - "warn_missing_spec", - "warn_missing_spec_all", - &mut builder, - ); + let what = attributes + .iter() + .fold((Found::No, None), |acc, ((present, idx), _)| { + if acc.0 == Found::No { + (*present, *idx) + } else { + acc } + }); + if what.0 != Found::WarnMissingSpecAll { + // Report on first compile attribute only + if let Some((_, compile_attribute)) = attributes.first() { + let range = compile_attribute + .form_id + .get_ast(sema.db, file_id) + .syntax() + .text_range(); + report_diagnostic(sema, Some(range), file_id, what, diags) } - let edit = builder.finish(); - Some(vec![fix( - "add_warn_missing_spec_all", - "Add compile option 'warn_missing_spec_all'", - edit, - range, - )]) } } -pub static LINTER: MissingCompileWarnMissingSpec = MissingCompileWarnMissingSpec; - -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] +#[derive(Debug, Clone, Copy, Eq, PartialEq)] enum Found { - #[default] No, WarnMissingSpec, WarnMissingSpecAll, @@ -214,6 +146,43 @@ lazy_static! { }; } +fn report_diagnostic( + sema: &Semantic, + range: Option, + file_id: FileId, + what: (Found, Option), + diags: &mut Vec, +) { + let range = range.unwrap_or(DIAGNOSTIC_WHOLE_FILE_RANGE); + + let mut builder = SourceChangeBuilder::new(file_id); + if what.0 == Found::No { + add_compile_option(sema, file_id, "warn_missing_spec_all", None, &mut builder); + } else { + // We already have warn_missing_spec, upgrade it to warn_missing_spec_all + if let Some(co_id) = what.1 { + rename_atom_in_compile_attribute( + sema, + file_id, + &co_id, + "warn_missing_spec", + "warn_missing_spec_all", + &mut builder, + ); + } + } + let edit = builder.finish(); + let d = Diagnostic::new( + crate::diagnostics::DiagnosticCode::MissingCompileWarnMissingSpec, + "Please add \"-compile(warn_missing_spec_all).\" to the module. If exported functions are not all specced, they need to be specced.".to_string(), + range, + ).with_fixes(Some(vec![fix("add_warn_missing_spec_all", + "Add compile option 'warn_missing_spec_all'", + edit, range)])) + .with_ignore_fix(sema, file_id); + diags.push(d); +} + #[cfg(test)] mod tests { @@ -228,9 +197,8 @@ mod tests { #[track_caller] pub(crate) fn check_fix(fixture_before: &str, fixture_after: Expect) { - let config = DiagnosticsConfig::default() - .disable(DiagnosticCode::NoNoWarnSuppressions) - .enable(DiagnosticCode::MissingCompileWarnMissingSpec); + let config = + DiagnosticsConfig::default().enable(DiagnosticCode::MissingCompileWarnMissingSpec); check_fix_with_config(config, fixture_before, fixture_after) } @@ -240,17 +208,17 @@ mod tests { fixture_before: &str, fixture_after: Expect, ) { - let config = DiagnosticsConfig::default() - .disable(DiagnosticCode::NoNoWarnSuppressions) - .enable(DiagnosticCode::MissingCompileWarnMissingSpec); + let config = + DiagnosticsConfig::default().enable(DiagnosticCode::MissingCompileWarnMissingSpec); check_specific_fix_with_config(Some(assist_label), fixture_before, fixture_after, config) } #[track_caller] pub(crate) fn check_diagnostics(fixture: &str) { let config = DiagnosticsConfig::default() + .enable(DiagnosticCode::MissingCompileWarnMissingSpec) .disable(DiagnosticCode::NoNoWarnSuppressions) - .enable(DiagnosticCode::MissingCompileWarnMissingSpec); + .disable(DiagnosticCode::UnspecificInclude); check_diagnostics_with_config(config, fixture) } @@ -399,20 +367,19 @@ mod tests { #[test] fn not_in_generated_file() { - check_diagnostics(&format!( + check_diagnostics( r#" //- /erl/my_app/src/main.erl %% -*- coding: utf-8 -*- %% Automatically generated, do not edit - %% @{} from blah + %% @generated from blah %% To generate, see targets and instructions in local Makefile %% Version source: git -module(main). -eqwalizer(ignore). "#, - "generated" // Separate string, to avoid to mark this module itself as generated - )) + ) } #[test] diff --git a/crates/ide/src/diagnostics/missing_module.rs b/crates/ide/src/diagnostics/missing_module.rs deleted file mode 100644 index 3fcbbf0fb7..0000000000 --- a/crates/ide/src/diagnostics/missing_module.rs +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is dual-licensed under either the MIT license found in the - * LICENSE-MIT file in the root directory of this source tree or the Apache - * License, Version 2.0 found in the LICENSE-APACHE file in the root directory - * of this source tree. You may select, at your option, one of the - * above-listed licenses. - */ - -// Diagnostic: missing-module -// -// Return a diagnostic if a module does not have a module definition - -use elp_ide_db::elp_base_db::FileId; -use elp_syntax::AstNode; -use elp_syntax::ast; -use hir::Semantic; - -use crate::diagnostics::DiagnosticCode; -use crate::diagnostics::GenericLinter; -use crate::diagnostics::GenericLinterMatchContext; -use crate::diagnostics::Linter; -use crate::diagnostics::Severity; - -pub(crate) struct MissingModuleLinter; - -impl Linter for MissingModuleLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::MissingModule - } - - fn description(&self) -> &'static str { - "no module definition" - } - - fn severity(&self, _sema: &Semantic, _file_id: FileId) -> super::Severity { - Severity::Error - } - - fn should_process_file_id(&self, sema: &Semantic, file_id: FileId) -> bool { - let file_kind = sema.db.file_kind(file_id); - file_kind.is_module() - } -} - -impl GenericLinter for MissingModuleLinter { - type Context = (); - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let parse = sema.db.parse(file_id); - let mut res = Vec::new(); - - for form in parse.tree().forms() { - match form { - ast::Form::PreprocessorDirective(_) => { - continue; // skip any directives - } - ast::Form::FileAttribute(_) => { - continue; // skip - } - ast::Form::ModuleAttribute(_) => { - break; - } - other_form => { - let range = other_form.syntax().text_range(); - res.push(GenericLinterMatchContext { range, context: () }); - break; - } - } - } - Some(res) - } -} - -pub static LINTER: MissingModuleLinter = MissingModuleLinter; - -#[cfg(test)] -mod tests { - use crate::tests::check_diagnostics; - - #[test] - fn fun_decl_module_decl_ok() { - check_diagnostics( - r#" --file("main.erl",1). --define(baz,4). --module(main). -foo(2)->?baz. -"#, - ); - } - - #[test] - fn fun_decl_module_decl_missing() { - check_diagnostics( - r#" - -file("foo.erl",1). - -define(baz,4). - foo(2)->?baz. -%%^^^^^^^^^^^^^💡 error: L1201: no module definition -"#, - ); - } - - #[test] - fn fun_decl_module_decl_missing_2() { - check_diagnostics( - r#" - baz(1)->4. -%%^^^^^^^^^^💡 error: L1201: no module definition - foo(2)->3. -"#, - ); - } - - #[test] - fn fun_decl_module_decl_after_preprocessor() { - check_diagnostics( - r#" --ifndef(snmpm_net_if_mt). --module(main). --endif. -baz(1)->4. -"#, - ); - } -} diff --git a/crates/ide/src/diagnostics/misspelled_attribute.rs b/crates/ide/src/diagnostics/misspelled_attribute.rs index 15ad1dd9d8..b3939bc9cf 100644 --- a/crates/ide/src/diagnostics/misspelled_attribute.rs +++ b/crates/ide/src/diagnostics/misspelled_attribute.rs @@ -10,18 +10,16 @@ use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; use elp_syntax::ast::AstNode; +use elp_syntax::ast::WildAttribute; +use elp_text_edit::TextEdit; +use hir::Attribute; use hir::Semantic; -use super::DiagnosticCode; -use super::GenericLinter; -use super::GenericLinterMatchContext; -use super::Linter; -use crate::Assist; +use super::Diagnostic; use crate::TextRange; use crate::TextSize; -use crate::diagnostics::Severity; +use crate::diagnostics::RelatedInformation; use crate::fix; // Diagnostic: misspelled_attribute @@ -36,91 +34,26 @@ use crate::fix; // ``` // -include_lib("/foo/bar/baz.hrl"). // ``` - -pub(crate) struct MisspelledAttributeLinter; - -impl Linter for MisspelledAttributeLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::MisspelledAttribute - } - - fn description(&self) -> &'static str { - "misspelled attribute" - } - - fn severity(&self, _sema: &Semantic, _file_id: FileId) -> super::Severity { - Severity::Error - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Default)] -pub struct Context { - attr_name: String, - suggested_rename: String, -} - -impl GenericLinter for MisspelledAttributeLinter { - type Context = Context; - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let form_list = sema.db.file_form_list(file_id); +pub(crate) fn misspelled_attribute( + sema: &Semantic, + diagnostics: &mut Vec, + file_id: FileId, +) { + let form_list = sema.db.file_form_list(file_id); + let potential_misspellings = form_list.attributes().filter_map(|(id, attr)| { + looks_like_misspelling(attr).map(|suggested_rename| (id, attr, suggested_rename)) + }); + potential_misspellings.for_each(|(_id, attr, suggested_rename)| { let parsed_file = sema.db.parse(file_id); - let mut res = Vec::new(); - - for (_id, attr) in form_list.attributes() { - if let Some(suggested_rename) = looks_like_misspelling(attr) { - let attr_form = attr.form_id.get(&parsed_file.tree()); - if let Some(attr_name_node) = attr_form.name() { - let attr_name_range_with_hyphen = attr_name_node.syntax().text_range(); - let attr_name_range = TextRange::new( - attr_name_range_with_hyphen - .start() - .checked_add(TextSize::of('-')) - .unwrap(), - attr_name_range_with_hyphen.end(), - ); - - res.push(GenericLinterMatchContext { - range: attr_name_range, - context: Context { - attr_name: attr.name.to_string(), - suggested_rename: suggested_rename.to_string(), - }, - }); - } - } - } - Some(res) - } - - fn match_description(&self, context: &Self::Context) -> std::borrow::Cow<'_, str> { - format!( - "misspelled attribute, saw '{}' but expected '{}'", - context.attr_name, context.suggested_rename - ) - .into() - } - - fn fixes( - &self, - context: &Self::Context, - range: TextRange, - _sema: &Semantic, - file_id: FileId, - ) -> Option> { - let edit = TextEdit::replace(range, context.suggested_rename.clone()); - let msg = format!("Change to '{}'", context.suggested_rename); - Some(vec![fix( - "fix_misspelled_attribute", - &msg, - SourceChange::from_text_edit(file_id, edit), - range, - )]) - } + let attr_form = attr.form_id.get(&parsed_file.tree()); + diagnostics.push(make_diagnostic( + sema, + file_id, + attr, + attr_form, + suggested_rename, + )) + }) } const KNOWN_ATTRIBUTES: &[&str] = &[ @@ -152,7 +85,7 @@ const KNOWN_ATTRIBUTES: &[&str] = &[ "doc", ]; -fn looks_like_misspelling(attr: &hir::Attribute) -> Option<&str> { +fn looks_like_misspelling(attr: &Attribute) -> Option<&str> { let mut suggestions: Vec<(&str, f64)> = KNOWN_ATTRIBUTES .iter() .filter(|&known| &attr.name != known) @@ -170,7 +103,47 @@ fn looks_like_misspelling(attr: &hir::Attribute) -> Option<&str> { .copied() } -pub static LINTER: MisspelledAttributeLinter = MisspelledAttributeLinter; +fn make_diagnostic( + sema: &Semantic, + file_id: FileId, + attr: &Attribute, + attr_form: WildAttribute, + suggested_rename: &str, +) -> Diagnostic { + // Includes the '-', e.g. "-dialyzer" from `-dialyzer([]).`, but we don't + // want to apply another `.name()`, because for attributes with special + // meanings like `-record(foo, ...).` we would get "foo" + let attr_name_range_with_hyphen = attr_form.name().unwrap().syntax().text_range(); + let attr_name_range = TextRange::new( + attr_name_range_with_hyphen + .start() + .checked_add(TextSize::of('-')) + .unwrap(), + attr_name_range_with_hyphen.end(), + ); + + let edit = TextEdit::replace(attr_name_range, suggested_rename.to_string()); + + Diagnostic::new( + super::DiagnosticCode::MisspelledAttribute, + format!( + "misspelled attribute, saw '{}' but expected '{}'", + attr.name, suggested_rename + ), + attr_name_range, + ) + .with_related(Some(vec![RelatedInformation { + range: attr_name_range, + message: "Misspelled attribute".to_string(), + }])) + .with_fixes(Some(vec![fix( + "fix_misspelled_attribute", + format!("Change misspelled attribute to '{suggested_rename}'").as_str(), + SourceChange::from_text_edit(file_id, edit), + attr_name_range, + )])) + .with_ignore_fix(sema, file_id) +} // To run the tests via cargo // cargo test --package elp_ide --lib diff --git a/crates/ide/src/diagnostics/module_mismatch.rs b/crates/ide/src/diagnostics/module_mismatch.rs index 77181b55ef..c1a57dfbd9 100644 --- a/crates/ide/src/diagnostics/module_mismatch.rs +++ b/crates/ide/src/diagnostics/module_mismatch.rs @@ -15,11 +15,11 @@ use elp_ide_assists::Assist; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; use elp_syntax::AstNode; use elp_syntax::SyntaxNode; use elp_syntax::TextRange; use elp_syntax::ast; +use elp_text_edit::TextEdit; use hir::Semantic; use crate::Diagnostic; diff --git a/crates/ide/src/diagnostics/mutable_variable.rs b/crates/ide/src/diagnostics/mutable_variable.rs index 6878c90d57..52fe32eccf 100644 --- a/crates/ide/src/diagnostics/mutable_variable.rs +++ b/crates/ide/src/diagnostics/mutable_variable.rs @@ -27,8 +27,12 @@ // use elp_ide_db::elp_base_db::FileId; +use fxhash::FxHashMap; +use fxhash::FxHashSet; use hir::AnyExpr; use hir::Expr; +use hir::FunctionClauseId; +use hir::PatId; use hir::Semantic; use hir::Strategy; use hir::fold::MacroStrategy; @@ -56,7 +60,21 @@ fn mutable_variable_bug( sema: &Semantic, file_id: FileId, ) -> Option<()> { - let bound_vars_by_function = sema.bound_vars_by_function(file_id); + let mut bound_vars_by_function: FxHashMap> = + FxHashMap::default(); + let bound_vars = sema.bound_vars_in_pattern_diagnostic(file_id); + bound_vars.iter().for_each(|(function_id, pat_id, _var)| { + bound_vars_by_function + .entry(function_id.value) + .and_modify(|vars| { + vars.insert(pat_id); + }) + .or_insert_with(|| { + let mut vars = FxHashSet::default(); + vars.insert(pat_id); + vars + }); + }); sema.def_map(file_id) .get_function_clauses() .for_each(|(_, def)| { diff --git a/crates/ide/src/diagnostics/no_catch.rs b/crates/ide/src/diagnostics/no_catch.rs index a804f248bd..3823131724 100644 --- a/crates/ide/src/diagnostics/no_catch.rs +++ b/crates/ide/src/diagnostics/no_catch.rs @@ -8,8 +8,7 @@ * above-listed licenses. */ -// Diagnostic: no-catch -use elp_ide_db::elp_base_db::FileId; +use elp_ide_db::DiagnosticCode; use elp_syntax::AstNode; use hir::AnyExpr; use hir::AnyExprId; @@ -21,48 +20,28 @@ use hir::Strategy; use hir::fold::MacroStrategy; use hir::fold::ParenStrategy; -use crate::diagnostics::DiagnosticCode; -use crate::diagnostics::GenericLinter; -use crate::diagnostics::GenericLinterMatchContext; -use crate::diagnostics::Linter; +use super::DiagnosticConditions; +use super::DiagnosticDescriptor; +use crate::diagnostics::Diagnostic; +use crate::diagnostics::Severity; -pub(crate) struct NoCatchLinter; +const DIAGNOSTIC_CODE: DiagnosticCode = DiagnosticCode::NoCatch; +const DIAGNOSTIC_MESSAGE: &str = "Avoid `catch`."; +const DIAGNOSTIC_SEVERITY: Severity = Severity::Warning; -impl Linter for NoCatchLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::NoCatch - } +pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { + conditions: DiagnosticConditions { + experimental: false, + include_generated: false, + include_tests: true, + default_disabled: false, + }, + checker: &|diagnostics, sema, file_id, _ext| { + sema.for_each_function(file_id, |def| check_function(diagnostics, sema, def)); + }, +}; - fn description(&self) -> &'static str { - "Avoid `catch`." - } -} - -impl GenericLinter for NoCatchLinter { - type Context = (); - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let mut res = Vec::new(); - sema.def_map_local(file_id) - .get_functions() - .for_each(|(_, def)| { - check_function(&mut res, sema, def); - }); - Some(res) - } -} - -pub static LINTER: NoCatchLinter = NoCatchLinter; - -fn check_function( - matches: &mut Vec>, - sema: &Semantic, - def: &FunctionDef, -) { +fn check_function(diagnostics: &mut Vec, sema: &Semantic, def: &FunctionDef) { let def_fb = def.in_function_body(sema, def); def_fb.fold_function( Strategy { @@ -73,19 +52,15 @@ fn check_function( &mut |_acc, clause_id, ctx| { if let AnyExpr::Expr(Expr::Catch { expr: _ }) = ctx.item { let map = def_fb.get_body_map(clause_id); - if let Some(match_context) = make_match_context(sema, &map, ctx.item_id) { - matches.push(match_context); + if let Some(diagnostic) = make_diagnostic(sema, &map, ctx.item_id) { + diagnostics.push(diagnostic); } }; }, ) } -fn make_match_context( - sema: &Semantic, - map: &BodySourceMap, - item_id: AnyExprId, -) -> Option> { +fn make_diagnostic(sema: &Semantic, map: &BodySourceMap, item_id: AnyExprId) -> Option { match item_id { AnyExprId::Expr(expr_id) => { let ast_ptr = map.expr(expr_id)?; @@ -93,7 +68,9 @@ fn make_match_context( elp_syntax::ast::Expr::CatchExpr(catch_expr) => { let catch_keyword = catch_expr.syntax().first_token()?; let range = catch_keyword.text_range(); - Some(GenericLinterMatchContext { range, context: () }) + let diagnostic = Diagnostic::new(DIAGNOSTIC_CODE, DIAGNOSTIC_MESSAGE, range) + .with_severity(DIAGNOSTIC_SEVERITY); + Some(diagnostic) } _ => None, } @@ -116,7 +93,7 @@ mod tests { catcher(X,Y) -> case catch X/Y of - %% ^^^^^ 💡 warning: W0052: Avoid `catch`. + %% ^^^^^ warning: W0052: Avoid `catch`. {'EXIT', {badarith,_}} -> "uh oh"; N -> N end. diff --git a/crates/ide/src/diagnostics/no_dialyzer_attribute.rs b/crates/ide/src/diagnostics/no_dialyzer_attribute.rs index 9a671e6c65..4c501c5ad5 100644 --- a/crates/ide/src/diagnostics/no_dialyzer_attribute.rs +++ b/crates/ide/src/diagnostics/no_dialyzer_attribute.rs @@ -8,55 +8,50 @@ * above-listed licenses. */ -// Diagnostic: no-dialyzer-attribute +use elp_ide_db::DiagnosticCode; use elp_ide_db::elp_base_db::FileId; use hir::Semantic; use hir::known; -use crate::diagnostics::DiagnosticCode; -use crate::diagnostics::GenericLinter; -use crate::diagnostics::GenericLinterMatchContext; -use crate::diagnostics::Linter; +use crate::diagnostics::Diagnostic; +use crate::diagnostics::DiagnosticConditions; +use crate::diagnostics::DiagnosticDescriptor; +use crate::diagnostics::Severity; -pub(crate) struct NoDialyzerAttributeLinter; +const DIAGNOSTIC_CODE: DiagnosticCode = DiagnosticCode::NoDialyzerAttribute; +const DIAGNOSTIC_MESSAGE: &str = "Avoid -dialyzer attribute."; +const DIAGNOSTIC_SEVERITY: Severity = Severity::Warning; -impl Linter for NoDialyzerAttributeLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::NoDialyzerAttribute - } +pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { + conditions: DiagnosticConditions { + experimental: false, + include_generated: false, + include_tests: false, + default_disabled: false, + }, + checker: &|diags, sema, file_id, _ext| { + no_dialyzer_attribute(diags, sema, file_id); + }, +}; - fn description(&self) -> &'static str { - "Avoid using the -dialyzer attribute." - } - - fn should_process_test_files(&self) -> bool { - false - } +fn no_dialyzer_attribute(diagnostics: &mut Vec, sema: &Semantic, file_id: FileId) { + let form_list = sema.db.file_form_list(file_id); + form_list.attributes().for_each(|(_idx, attr)| { + if attr.name == known::dialyzer + && let Some(diagnostic) = make_diagnostic(sema, file_id, attr) + { + diagnostics.push(diagnostic); + } + }); } -impl GenericLinter for NoDialyzerAttributeLinter { - type Context = (); - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let mut res = Vec::new(); - let form_list = sema.db.file_form_list(file_id); - form_list.attributes().for_each(|(_idx, attr)| { - if attr.name == known::dialyzer - && let Some(range) = attr.name_range(sema.db, file_id) - { - res.push(GenericLinterMatchContext { range, context: () }) - } - }); - Some(res) - } +fn make_diagnostic(sema: &Semantic, file_id: FileId, attr: &hir::Attribute) -> Option { + let range = attr.name_range(sema.db, file_id)?; + let diagnostic = Diagnostic::new(DIAGNOSTIC_CODE, DIAGNOSTIC_MESSAGE, range) + .with_severity(DIAGNOSTIC_SEVERITY); + Some(diagnostic) } -pub static LINTER: NoDialyzerAttributeLinter = NoDialyzerAttributeLinter; - #[cfg(test)] mod tests { @@ -68,7 +63,7 @@ mod tests { r#" -module(main). -dialyzer({nowarn_function, foo/0}). - %% ^^^^^^^^^ 💡 warning: W0048: Avoid using the -dialyzer attribute. + %% ^^^^^^^^^ warning: W0048: Avoid -dialyzer attribute. "#, ) } diff --git a/crates/ide/src/diagnostics/no_error_logger.rs b/crates/ide/src/diagnostics/no_error_logger.rs index 46f3d15e3e..08e94133d0 100644 --- a/crates/ide/src/diagnostics/no_error_logger.rs +++ b/crates/ide/src/diagnostics/no_error_logger.rs @@ -8,9 +8,6 @@ * above-listed licenses. */ -use elp_ide_db::elp_base_db::FileId; -use hir::Semantic; - use crate::codemod_helpers::FunctionMatch; use crate::diagnostics::DiagnosticCode; use crate::diagnostics::FunctionCallLinter; @@ -26,12 +23,9 @@ impl Linter for NoErrorLoggerLinter { fn description(&self) -> &'static str { "The `error_logger` module is deprecated." } - fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { + fn severity(&self) -> Severity { Severity::Error } - fn should_process_test_files(&self) -> bool { - false - } } impl FunctionCallLinter for NoErrorLoggerLinter { diff --git a/crates/ide/src/diagnostics/no_nowarn_suppressions.rs b/crates/ide/src/diagnostics/no_nowarn_suppressions.rs index a0b36f87b8..ef258779cd 100644 --- a/crates/ide/src/diagnostics/no_nowarn_suppressions.rs +++ b/crates/ide/src/diagnostics/no_nowarn_suppressions.rs @@ -16,63 +16,62 @@ use hir::Semantic; use lazy_static::lazy_static; use regex::Regex; +use crate::diagnostics::Diagnostic; use crate::diagnostics::DiagnosticCode; -use crate::diagnostics::GenericLinter; -use crate::diagnostics::GenericLinterMatchContext; -use crate::diagnostics::Linter; +use crate::diagnostics::DiagnosticConditions; +use crate::diagnostics::DiagnosticDescriptor; +use crate::diagnostics::Severity; -pub(crate) struct NoNoWarnSuppressionsLinter; +const DIAGNOSTIC_CODE: DiagnosticCode = DiagnosticCode::NoNoWarnSuppressions; +const DIAGNOSTIC_MESSAGE: &str = "Do not suppress compiler warnings at module level."; +const DIAGNOSTIC_SEVERITY: Severity = Severity::Warning; -impl Linter for NoNoWarnSuppressionsLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::NoNoWarnSuppressions +pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { + conditions: DiagnosticConditions { + experimental: false, + include_generated: false, + include_tests: true, + default_disabled: false, + }, + checker: &|diags, sema, file_id, _ext| { + no_warn_suppression(diags, sema, file_id); + }, +}; + +fn no_warn_suppression(diagnostics: &mut Vec, sema: &Semantic, file_id: FileId) { + lazy_static! { + static ref NOWARN_REGEX: Regex = Regex::new(r"^nowarn_").unwrap(); } - fn description(&self) -> &'static str { - "Do not suppress compiler warnings at module level." - } -} - -impl GenericLinter for NoNoWarnSuppressionsLinter { - type Context = (); - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - lazy_static! { - static ref NOWARN_REGEX: Regex = Regex::new(r"^nowarn_").unwrap(); - } - - let mut res = Vec::new(); - let form_list = sema.db.file_form_list(file_id); - for (_compile_option_idx, compile_option) in form_list.compile_attributes() { - let attr = compile_option.form_id.get_ast(sema.db, file_id); - if let Some(expr) = attr.options() { - // Blindly search for any atom matching the nowarn_ prefix - for n in expr.syntax().descendants() { - match_ast! { - match n { - ast::Atom(atom) => { - if let Some(atom_text) = atom.text() - && NOWARN_REGEX.is_match(&atom_text) { - let range = atom.syntax().text_range(); - res.push(GenericLinterMatchContext { range, context: () }); - } - }, - _ => {} - } + let form_list = sema.db.file_form_list(file_id); + for (_compile_option_idx, compile_option) in form_list.compile_attributes() { + let attr = compile_option.form_id.get_ast(sema.db, file_id); + if let Some(expr) = attr.options() { + // Blindly search for any atom matching the nowarn_ prefix + for n in expr.syntax().descendants() { + match_ast! { + match n { + ast::Atom(atom) => { + if let Some(atom_text) = atom.text() + && NOWARN_REGEX.is_match(&atom_text) { + let diagnostic = Diagnostic::new( + DIAGNOSTIC_CODE, + DIAGNOSTIC_MESSAGE, + atom.syntax().text_range(), + ) + .with_ignore_fix(sema, file_id) + .with_severity(DIAGNOSTIC_SEVERITY); + diagnostics.push(diagnostic); + } + }, + _ => {} } } } } - Some(res) } } -pub static LINTER: NoNoWarnSuppressionsLinter = NoNoWarnSuppressionsLinter; - #[cfg(test)] mod tests { use crate::tests; diff --git a/crates/ide/src/diagnostics/nonstandard_integer_formatting.rs b/crates/ide/src/diagnostics/nonstandard_integer_formatting.rs index 63b0a450cb..d80751c946 100644 --- a/crates/ide/src/diagnostics/nonstandard_integer_formatting.rs +++ b/crates/ide/src/diagnostics/nonstandard_integer_formatting.rs @@ -15,8 +15,8 @@ use elp_ide_db::DiagnosticCode; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChangeBuilder; -use elp_ide_db::text_edit::TextRange; use elp_syntax::AstNode; +use elp_text_edit::TextRange; use hir::AnyExpr; use hir::BasedInteger; use hir::Expr; diff --git a/crates/ide/src/diagnostics/record_tuple_match.rs b/crates/ide/src/diagnostics/record_tuple_match.rs index 9756bfeb73..5606dce89a 100644 --- a/crates/ide/src/diagnostics/record_tuple_match.rs +++ b/crates/ide/src/diagnostics/record_tuple_match.rs @@ -15,7 +15,7 @@ use elp_ide_db::DiagnosticCode; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::elp_base_db::FileRange; -use elp_ide_db::text_edit::TextRange; +use elp_text_edit::TextRange; use hir::AnyExpr; use hir::FunctionDef; use hir::Literal; diff --git a/crates/ide/src/diagnostics/replace_call.rs b/crates/ide/src/diagnostics/replace_call.rs index fa16acf356..e83afcb985 100644 --- a/crates/ide/src/diagnostics/replace_call.rs +++ b/crates/ide/src/diagnostics/replace_call.rs @@ -15,9 +15,9 @@ use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; use elp_syntax::TextRange; use elp_syntax::ast; +use elp_text_edit::TextEdit; use hir::AnyExprId; use hir::CallTarget; use hir::Expr; diff --git a/crates/ide/src/diagnostics/replace_in_spec.rs b/crates/ide/src/diagnostics/replace_in_spec.rs index a5df5217e2..12d8aa3f64 100644 --- a/crates/ide/src/diagnostics/replace_in_spec.rs +++ b/crates/ide/src/diagnostics/replace_in_spec.rs @@ -16,8 +16,8 @@ use elp_ide_db::DiagnosticCode; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; use elp_syntax::SmolStr; +use elp_text_edit::TextEdit; use fxhash::FxHashSet; use hir::AnyExpr; use hir::InFile; diff --git a/crates/ide/src/diagnostics/trivial_match.rs b/crates/ide/src/diagnostics/trivial_match.rs index 705cc22d7e..56d3881a9a 100644 --- a/crates/ide/src/diagnostics/trivial_match.rs +++ b/crates/ide/src/diagnostics/trivial_match.rs @@ -17,9 +17,9 @@ use std::collections::HashMap; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; use elp_syntax::TextRange; use elp_syntax::ast; +use elp_text_edit::TextEdit; use hir::AnyExpr; use hir::AnyExprId; use hir::BinarySeg; diff --git a/crates/ide/src/diagnostics/unavailable_type.rs b/crates/ide/src/diagnostics/unavailable_type.rs deleted file mode 100644 index 6f2f52c122..0000000000 --- a/crates/ide/src/diagnostics/unavailable_type.rs +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is dual-licensed under either the MIT license found in the - * LICENSE-MIT file in the root directory of this source tree or the Apache - * License, Version 2.0 found in the LICENSE-APACHE file in the root directory - * of this source tree. You may select, at your option, one of the - * above-listed licenses. - */ - -// Diagnostic: unavailable-type -// -// Return a warning when referring to a type which is not defined in the module's dependencies. -// This diagnostic checks if a type referenced in specs, type definitions, or opaque types exists in: -// 1. The current module (local types) -// 2. Built-in Erlang types -// 3. Types from the module's application dependencies (including OTP apps) - -use std::borrow::Cow; - -use elp_ide_db::elp_base_db::AppData; -use elp_ide_db::elp_base_db::FileId; -use elp_project_model::AppName; -use hir::AnyExpr; -use hir::Callback; -use hir::InFile; -use hir::Record; -use hir::Semantic; -use hir::Spec; -use hir::Strategy; -use hir::TypeAlias; -use hir::TypeExpr; -use hir::fold::Fold; -use hir::fold::MacroStrategy; -use hir::fold::ParenStrategy; - -use super::DiagnosticCode; -use crate::diagnostics::GenericLinter; -use crate::diagnostics::GenericLinterMatchContext; -use crate::diagnostics::Linter; - -pub(crate) struct UnavailableTypeLinter; - -impl Linter for UnavailableTypeLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::UnavailableType - } - fn description(&self) -> &'static str { - "Type is not available through dependencies." - } - fn is_enabled(&self) -> bool { - false - } -} - -#[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct Context { - type_label: String, - defining_app: String, - referencing_app: String, - referencing_target: String, -} - -impl GenericLinter for UnavailableTypeLinter { - type Context = Context; - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - // Early return if we don't have app data - can't determine type availability - let referencing_app_data = sema.db.file_app_data(file_id)?; - - // Extract target once here - if not available, can't create diagnostics anyway - let referencing_target = referencing_app_data.buck_target_name.as_ref()?; - - let mut res = Vec::new(); - let form_list = sema.form_list(file_id); - - // Check -spec attributes - for (spec_id, _spec) in form_list.specs() { - check_spec( - &mut res, - sema, - file_id, - &referencing_app_data, - referencing_target, - spec_id, - ); - } - - // Check -type and -opaque attributes - for (type_alias_id, _type_alias) in form_list.type_aliases() { - check_type_alias( - &mut res, - sema, - file_id, - &referencing_app_data, - referencing_target, - type_alias_id, - ); - } - - // Check -callback attributes - for (callback_id, _callback) in form_list.callback_attributes() { - check_callback( - &mut res, - sema, - file_id, - &referencing_app_data, - referencing_target, - callback_id, - ); - } - - // Check -record attributes - for (record_id, _record) in form_list.records() { - check_record( - &mut res, - sema, - file_id, - &referencing_app_data, - referencing_target, - record_id, - ); - } - - Some(res) - } - - fn match_description(&self, context: &Self::Context) -> Cow<'_, str> { - Cow::Owned(format!( - "The type '{}' is defined in application '{}', but the application is not a dependency of '{}' (defined in '{}').", - context.type_label, - context.defining_app, - context.referencing_app, - context.referencing_target - )) - } -} - -pub static LINTER: UnavailableTypeLinter = UnavailableTypeLinter; - -fn check_spec( - matches: &mut Vec>, - sema: &Semantic, - file_id: FileId, - referencing_app_data: &AppData, - referencing_target: &String, - spec_id: hir::SpecId, -) { - let spec_id = InFile::new(file_id, spec_id); - let spec_body = sema.db.spec_body(spec_id); - - Spec::fold( - sema, - Strategy { - macros: MacroStrategy::Expand, - parens: ParenStrategy::InvisibleParens, - }, - spec_id, - (), - &mut |_acc, ctx| { - check_type_call( - matches, - sema, - file_id, - referencing_app_data, - referencing_target, - &ctx, - &spec_body.body, - ); - }, - ); -} - -fn check_type_alias( - matches: &mut Vec>, - sema: &Semantic, - file_id: FileId, - referencing_app_data: &AppData, - referencing_target: &String, - type_alias_id: hir::TypeAliasId, -) { - let type_alias_id = InFile::new(file_id, type_alias_id); - let type_body = sema.db.type_body(type_alias_id); - - TypeAlias::fold( - sema, - Strategy { - macros: MacroStrategy::Expand, - parens: ParenStrategy::InvisibleParens, - }, - type_alias_id, - (), - &mut |_acc, ctx| { - check_type_call( - matches, - sema, - file_id, - referencing_app_data, - referencing_target, - &ctx, - &type_body.body, - ); - }, - ); -} - -fn check_callback( - matches: &mut Vec>, - sema: &Semantic, - file_id: FileId, - referencing_app_data: &AppData, - referencing_target: &String, - callback_id: hir::CallbackId, -) { - let callback_id = InFile::new(file_id, callback_id); - let callback_body = sema.db.callback_body(callback_id); - - Callback::fold( - sema, - Strategy { - macros: MacroStrategy::Expand, - parens: ParenStrategy::InvisibleParens, - }, - callback_id, - (), - &mut |_acc, ctx| { - check_type_call( - matches, - sema, - file_id, - referencing_app_data, - referencing_target, - &ctx, - &callback_body.body, - ); - }, - ); -} - -fn check_record( - matches: &mut Vec>, - sema: &Semantic, - file_id: FileId, - referencing_app_data: &AppData, - referencing_target: &String, - record_id: hir::RecordId, -) { - let record_id = InFile::new(file_id, record_id); - let record_body = sema.db.record_body(record_id); - - Record::fold( - sema, - Strategy { - macros: MacroStrategy::Expand, - parens: ParenStrategy::InvisibleParens, - }, - record_id, - (), - &mut |_acc, ctx| { - check_type_call( - matches, - sema, - file_id, - referencing_app_data, - referencing_target, - &ctx, - &record_body.body, - ); - }, - ); -} - -fn is_type_available( - sema: &Semantic, - referencing_app_data: &AppData, - referencing_target: &String, - referencing_app_name: &AppName, - defining_app_name: &AppName, -) -> bool { - // Types from the same app are always available - if referencing_app_name == defining_app_name { - return true; - } - - // Check if type is available through dependencies - if let Some(include_mapping) = &sema - .db - .project_data(referencing_app_data.project_id) - .include_mapping - { - include_mapping.is_dep(referencing_target, defining_app_name) - } else { - // Can't determine - be conservative and allow it - true - } -} - -fn check_type_call( - matches: &mut Vec>, - sema: &Semantic, - file_id: FileId, - referencing_app_data: &AppData, - referencing_target: &String, - ctx: &hir::fold::AnyCallBackCtx<'_>, - body: &hir::Body, -) -> Option<()> { - if let AnyExpr::TypeExpr(TypeExpr::Call { target, args }) = &ctx.item { - let arity = args.len() as u32; - let target_label = target.label(arity, sema, body)?; - let target_range = target.range(sema, body)?; - let type_alias_def = target.resolve_call(arity, sema, file_id, body)?; - let defining_file_id = type_alias_def.file.file_id; - let defining_app_data = sema.db.file_app_data(defining_file_id)?; - let defining_app_name = &defining_app_data.name; - let referencing_app_name = &referencing_app_data.name; - - if !is_type_available( - sema, - referencing_app_data, - referencing_target, - referencing_app_name, - defining_app_name, - ) { - matches.push(GenericLinterMatchContext { - range: target_range.range, - context: Context { - type_label: target_label.to_string(), - defining_app: defining_app_name.to_string(), - referencing_app: referencing_app_name.to_string(), - referencing_target: referencing_target.to_string(), - }, - }); - } - } - Some(()) -} diff --git a/crates/ide/src/diagnostics/undefined_function.rs b/crates/ide/src/diagnostics/undefined_function.rs index 52fa2cfa3c..6472a08f07 100644 --- a/crates/ide/src/diagnostics/undefined_function.rs +++ b/crates/ide/src/diagnostics/undefined_function.rs @@ -43,13 +43,6 @@ impl Linter for UndefinedFunctionLinter { fn should_process_generated_files(&self) -> bool { true } - // Ideally, we would like to report undefined functions in all files, but - // there are too many false positives in test files to do so. - // This is often due to mocked modules and test suite cleverness. - // We can revisit this decision in the future. See T249044930. - fn should_process_test_files(&self) -> bool { - false - } } impl FunctionCallLinter for UndefinedFunctionLinter { @@ -87,45 +80,19 @@ impl FunctionCallLinter for UndefinedFunctionLinter { return None; } - if sema.is_atom_named(name, &known::module_info) && (arity == 0 || arity == 1) { + if sema.is_atom_named(name, &known::module_info) && (arity == 0 || arity == 1) + || sema + .resolve_module_expr(def_fb.file_id(), module) + .is_some_and(|module| is_automatically_added(sema, module, name, arity)) + { return None; } - - // Try to resolve the module expression to a static module - let resolved_module = sema.resolve_module_expr(def_fb.file_id(), module); - - match resolved_module { - Some(resolved_module) => { - // Module exists, check if the function exists - match context.target.resolve_call( - arity, - sema, - def_fb.file_id(), - &def_fb.body(), - ) { - Some(_) => None, - None => { - // Function doesn't exist - check if it would be automatically added - if is_automatically_added(sema, resolved_module, name, arity) { - return None; - } - Some(context.target.label(arity, sema, &def_fb.body())) - } - } - } - None => { - // Module cannot be resolved. If the module expression is a static atom, - // it means the module doesn't exist and we should report it. - // If it's a dynamic expression (e.g., a variable or function call), - // we can't determine at compile time whether it's defined. - if module.as_atom().is_some() { - // Static module name that doesn't exist - report as undefined - Some(context.target.label(arity, sema, &def_fb.body())) - } else { - // Dynamic module expression - can't determine at compile time - None - } - } + match context + .target + .resolve_call(arity, sema, def_fb.file_id(), &def_fb.body()) + { + Some(_) => None, + None => Some(context.target.label(arity, sema, &def_fb.body())), } } // Diagnostic L1227 already covers the case for local calls, so avoid double-reporting @@ -446,29 +413,4 @@ exists() -> ok. "#, ) } - - #[test] - fn test_macro_remote_call() { - check_diagnostics( - r#" - //- /src/main.erl - -module(main). - -export([do/0]). - -define(COUNT_BACKEND, (count_backend:count_module())). - -define(COUNT(Name), ?COUNT_BACKEND:count(Name)). - - do() -> - ?COUNT('error.count'). - - //- /src/stats.erl - -module(stats). - -export([count/1]). - count(_) -> ok. - //- /src/count_backend.erl - -module(count_backend). - -export([count_module/0]). - count_module() -> ?MODULE. - "#, - ) - } } diff --git a/crates/ide/src/diagnostics/undefined_macro.rs b/crates/ide/src/diagnostics/undefined_macro.rs index 51ee0ceaff..c90e2d1285 100644 --- a/crates/ide/src/diagnostics/undefined_macro.rs +++ b/crates/ide/src/diagnostics/undefined_macro.rs @@ -15,7 +15,7 @@ use elp_ide_db::DiagnosticCode; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::elp_base_db::path_for_file; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; +use elp_text_edit::TextEdit; use fxhash::FxHashSet; use hir::Semantic; use lazy_static::lazy_static; diff --git a/crates/ide/src/diagnostics/undocumented_function.rs b/crates/ide/src/diagnostics/undocumented_function.rs index f1d0aa06b5..c895b52622 100644 --- a/crates/ide/src/diagnostics/undocumented_function.rs +++ b/crates/ide/src/diagnostics/undocumented_function.rs @@ -8,10 +8,9 @@ * above-listed licenses. */ -// Diagnostic: undocumented-function use elp_ide_assists::helpers::unwrap_parens; +// Diagnostic: undocumented-function use elp_ide_db::elp_base_db::FileId; -use elp_ide_db::text_edit::TextRange; use elp_syntax::ast; use elp_syntax::ast::Atom; use fxhash::FxHashSet; @@ -22,66 +21,37 @@ use hir::Semantic; use hir::form_list::ModuleDocAttribute; use hir::known; -use crate::diagnostics::DiagnosticCode; -use crate::diagnostics::GenericLinter; -use crate::diagnostics::GenericLinterMatchContext; -use crate::diagnostics::Linter; -use crate::diagnostics::Severity; +use super::Diagnostic; +use super::DiagnosticCode; +use super::DiagnosticConditions; +use super::DiagnosticDescriptor; +use super::Severity; -pub(crate) struct UndocumentedFunctionLinter; +const DIAGNOSTIC_CODE: DiagnosticCode = DiagnosticCode::UndocumentedFunction; +const DIAGNOSTIC_MESSAGE: &str = "The function is non-trivial, exported, but not documented."; +const DIAGNOSTIC_SEVERITY: Severity = Severity::WeakWarning; -impl Linter for UndocumentedFunctionLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::UndocumentedFunction - } +pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { + conditions: DiagnosticConditions { + experimental: false, + include_generated: false, + include_tests: false, + default_disabled: true, + }, + checker: &|diags, sema, file_id, _ext| { + check(diags, sema, file_id); + }, +}; - fn description(&self) -> &'static str { - "The function is non-trivial, exported, but not documented." - } - - fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { - Severity::WeakWarning - } - - fn is_enabled(&self) -> bool { - false - } - - fn should_process_test_files(&self) -> bool { - false +fn check(diagnostics: &mut Vec, sema: &Semantic, file_id: FileId) { + let callbacks = sema.resolve_callbacks(file_id); + if !contains_moduledoc_hidden_attribute(sema, file_id) { + sema.def_map_local(file_id) + .get_functions() + .for_each(|(_arity, def)| check_function(diagnostics, sema, def, &callbacks)); } } -#[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct Context { - range: TextRange, -} - -impl GenericLinter for UndocumentedFunctionLinter { - type Context = Context; - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let mut res = Vec::new(); - let callbacks = sema.resolve_callbacks(file_id); - if !contains_moduledoc_hidden_attribute(sema, file_id) { - sema.def_map_local(file_id) - .get_functions() - .for_each(|(_arity, def)| { - if let Some(match_context) = check_function(sema, def, &callbacks) { - res.push(match_context); - } - }); - } - Some(res) - } -} - -pub static LINTER: UndocumentedFunctionLinter = UndocumentedFunctionLinter; - fn contains_moduledoc_hidden_attribute(sema: &Semantic, file_id: FileId) -> bool { sema.form_list(file_id) .moduledoc_attributes() @@ -117,22 +87,20 @@ fn function_should_be_checked( } fn check_function( + diagnostics: &mut Vec, sema: &Semantic, def: &FunctionDef, callbacks: &FxHashSet, -) -> Option> { +) { if function_should_be_checked(sema, def, callbacks) && !def.has_doc_attribute() && !def.has_doc_attribute_metadata() && def.edoc_comments(sema.db).is_none() && let Some(name_range) = def.name_range(sema.db) { - Some(GenericLinterMatchContext { - range: name_range, - context: Context { range: name_range }, - }) - } else { - None + let diagnostic = Diagnostic::new(DIAGNOSTIC_CODE, DIAGNOSTIC_MESSAGE, name_range) + .with_severity(DIAGNOSTIC_SEVERITY); + diagnostics.push(diagnostic); } } @@ -162,7 +130,7 @@ mod tests { -module(main). -export([main/0]). main() -> - %% ^^^^ 💡 weak: W0040: The function is non-trivial, exported, but not documented. + %% ^^^^ weak: W0040: The function is non-trivial, exported, but not documented. [ok, ok, ok, @@ -179,7 +147,7 @@ mod tests { -module(main). -export([main/0]). main() -> - %% ^^^^ 💡 weak: W0040: The function is non-trivial, exported, but not documented. + %% ^^^^ weak: W0040: The function is non-trivial, exported, but not documented. [ok, ok, ok, @@ -349,7 +317,7 @@ mod tests { -export([handle_call/1]). main() -> - %%<^ 💡 weak: W0040: The function is non-trivial, exported, but not documented. + %%<^ weak: W0040: The function is non-trivial, exported, but not documented. [ok, ok, ok, @@ -381,7 +349,7 @@ mod tests { ok. complex() -> - %%<^^^^ 💡 weak: W0040: The function is non-trivial, exported, but not documented. + %%<^^^^ weak: W0040: The function is non-trivial, exported, but not documented. [ok, ok, ok, @@ -402,7 +370,7 @@ mod tests { ok. complex(a) -> - %%<^^^^ 💡 weak: W0040: The function is non-trivial, exported, but not documented. + %%<^^^^ weak: W0040: The function is non-trivial, exported, but not documented. [ok]; complex(b) -> [ok, diff --git a/crates/ide/src/diagnostics/undocumented_module.rs b/crates/ide/src/diagnostics/undocumented_module.rs index 1b2c80cfc9..ad440d5acd 100644 --- a/crates/ide/src/diagnostics/undocumented_module.rs +++ b/crates/ide/src/diagnostics/undocumented_module.rs @@ -12,94 +12,64 @@ use elp_ide_assists::Assist; use elp_ide_assists::helpers; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChangeBuilder; -use elp_ide_db::text_edit::TextRange; use elp_syntax::AstNode; +use elp_text_edit::TextRange; +use elp_text_edit::TextSize; use hir::Semantic; -use crate::diagnostics::DiagnosticCode; -use crate::diagnostics::GenericLinter; -use crate::diagnostics::GenericLinterMatchContext; -use crate::diagnostics::Linter; -use crate::diagnostics::Severity; -use crate::fix; +use super::Diagnostic; +use super::DiagnosticCode; +use super::DiagnosticConditions; +use super::DiagnosticDescriptor; +use super::Severity; -pub(crate) struct UndocumentedModuleLinter; +const DIAGNOSTIC_CODE: DiagnosticCode = DiagnosticCode::UndocumentedModule; +const DIAGNOSTIC_MESSAGE: &str = "The module is not documented."; +const DIAGNOSTIC_SEVERITY: Severity = Severity::WeakWarning; +const FIX_ID: &str = "add_moduledoc_false"; +const FIX_LABEL: &str = "Add `-moduledoc false.` attribute"; -impl Linter for UndocumentedModuleLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::UndocumentedModule - } - - fn description(&self) -> &'static str { - "The module is not documented." - } - - fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { - Severity::WeakWarning - } - - fn is_enabled(&self) -> bool { - false - } - - fn should_process_test_files(&self) -> bool { - false +pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { + conditions: DiagnosticConditions { + experimental: false, + include_generated: false, + include_tests: false, + default_disabled: true, + }, + checker: &|diags, sema, file_id, _ext| { + check(diags, sema, file_id); + }, +}; + +fn check(diagnostics: &mut Vec, sema: &Semantic, file_id: FileId) -> Option<()> { + let def_map = sema.def_map_local(file_id); + let module_attribute = sema.module_attribute(file_id)?; + let module_has_no_docs = def_map.moduledoc.is_empty() + && def_map.moduledoc_metadata.is_empty() + && sema + .module_edoc_header(file_id, &module_attribute) + .is_none(); + if module_has_no_docs { + let module_name = module_attribute.name()?; + let module_name_range = module_name.syntax().text_range(); + let moduledoc_insert_offset = helpers::moduledoc_insert_offset(sema, file_id)?; + let fixes = fixes(file_id, moduledoc_insert_offset, module_name_range); + let diagnostic = Diagnostic::new(DIAGNOSTIC_CODE, DIAGNOSTIC_MESSAGE, module_name_range) + .with_severity(DIAGNOSTIC_SEVERITY) + .with_fixes(Some(fixes)); + diagnostics.push(diagnostic); } + Some(()) } -#[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct Context; - -impl GenericLinter for UndocumentedModuleLinter { - type Context = Context; - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let mut res = Vec::new(); - let def_map = sema.def_map_local(file_id); - let module_attribute = sema.module_attribute(file_id)?; - let module_has_no_docs = def_map.moduledoc.is_empty() - && def_map.moduledoc_metadata.is_empty() - && sema - .module_edoc_header(file_id, &module_attribute) - .is_none(); - if module_has_no_docs { - let module_name = module_attribute.name()?; - let module_name_range = module_name.syntax().text_range(); - res.push(GenericLinterMatchContext { - range: module_name_range, - context: Context, - }); - } - Some(res) - } - - fn fixes( - &self, - _context: &Context, - range: TextRange, - sema: &Semantic, - file_id: FileId, - ) -> Option> { - let insert_offset = helpers::moduledoc_insert_offset(sema, file_id)?; - let mut builder = SourceChangeBuilder::new(file_id); - builder.insert(insert_offset, "-moduledoc false.\n"); - let source_change = builder.finish(); - let fix = fix( - "add_moduledoc_false", - "Add `-moduledoc false.` attribute", - source_change, - range, - ); - Some(vec![fix]) - } +fn fixes(file_id: FileId, insert_offset: TextSize, show_range: TextRange) -> Vec { + let mut builder = SourceChangeBuilder::new(file_id); + builder.insert(insert_offset, "-moduledoc false.\n"); + let source_change = builder.finish(); + let fix = crate::fix(FIX_ID, FIX_LABEL, source_change, show_range); + vec![fix] } -pub static LINTER: UndocumentedModuleLinter = UndocumentedModuleLinter; - #[cfg(test)] mod tests { diff --git a/crates/ide/src/diagnostics/unexported_function.rs b/crates/ide/src/diagnostics/unexported_function.rs index 2e1ebf7f54..7aae73a9f1 100644 --- a/crates/ide/src/diagnostics/unexported_function.rs +++ b/crates/ide/src/diagnostics/unexported_function.rs @@ -27,7 +27,7 @@ use crate::codemod_helpers::CheckCallCtx; use crate::codemod_helpers::MatchCtx; use crate::diagnostics::FunctionCallLinter; use crate::diagnostics::Linter; -// @fb-only: use crate::diagnostics::meta_only; +// @fb-only use crate::fix; use crate::lazy_function_matches; @@ -45,9 +45,9 @@ impl Linter for UnexportedFunctionLinter { } #[rustfmt::skip] fn should_process_file_id(&self, _sema: &Semantic, _file_id: FileId) -> bool { // @oss-only - // @fb-only: fn should_process_file_id(&self, sema: &Semantic, file_id: FileId) -> bool { + // @fb-only true // @oss-only - // @fb-only: meta_only::should_check_for_unexported(sema, file_id) + // @fb-only } } diff --git a/crates/ide/src/diagnostics/unnecessary_fold_to_build_map.rs b/crates/ide/src/diagnostics/unnecessary_fold_to_build_map.rs index 40f16da4d8..5fea930a9a 100644 --- a/crates/ide/src/diagnostics/unnecessary_fold_to_build_map.rs +++ b/crates/ide/src/diagnostics/unnecessary_fold_to_build_map.rs @@ -49,7 +49,7 @@ impl Linter for UnnecessaryFoldToBuildMapLinter { "Unnecessary explicit fold to construct map." } - fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { + fn severity(&self) -> Severity { Severity::WeakWarning } } diff --git a/crates/ide/src/diagnostics/unnecessary_map_to_list_in_comprehension.rs b/crates/ide/src/diagnostics/unnecessary_map_to_list_in_comprehension.rs index 0c2ed5e140..6dbf3cd4c7 100644 --- a/crates/ide/src/diagnostics/unnecessary_map_to_list_in_comprehension.rs +++ b/crates/ide/src/diagnostics/unnecessary_map_to_list_in_comprehension.rs @@ -33,7 +33,7 @@ impl Linter for UnnecessaryMapToListInComprehensionLinter { "Unnecessary intermediate list allocated." } - fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { + fn severity(&self) -> Severity { Severity::WeakWarning } } diff --git a/crates/ide/src/diagnostics/unspecific_include.rs b/crates/ide/src/diagnostics/unspecific_include.rs index 431740c085..339874f6ee 100644 --- a/crates/ide/src/diagnostics/unspecific_include.rs +++ b/crates/ide/src/diagnostics/unspecific_include.rs @@ -14,9 +14,9 @@ use elp_ide_db::elp_base_db::FileId; use elp_ide_db::elp_base_db::generated_file_include_lib; use elp_ide_db::elp_base_db::path_for_file; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; -use elp_ide_db::text_edit::TextRange; use elp_syntax::ast; +use elp_text_edit::TextEdit; +use elp_text_edit::TextRange; use hir::InFile; use hir::Semantic; @@ -152,12 +152,10 @@ fn replace_include_path( #[cfg(test)] mod tests { use elp_ide_db::DiagnosticCode; - // @fb-only: use elp_ide_db::meta_only::MetaOnlyDiagnosticCode; use expect_test::Expect; use expect_test::expect; use crate::diagnostics::Diagnostic; - use crate::diagnostics::DiagnosticsConfig; use crate::tests; fn filter(d: &Diagnostic) -> bool { @@ -169,13 +167,9 @@ mod tests { tests::check_filtered_diagnostics(fixture, &filter) } - #[rustfmt::skip] #[track_caller] fn check_fix(fixture_before: &str, fixture_after: Expect) { - let config = DiagnosticsConfig::default() - // @fb-only: .disable(DiagnosticCode::MetaOnly(MetaOnlyDiagnosticCode::MalformedInclude)) - .disable(DiagnosticCode::UnusedInclude); - tests::check_fix_with_config(config, fixture_before, fixture_after) + tests::check_fix(fixture_before, fixture_after) } #[test] diff --git a/crates/ide/src/diagnostics/unused_function_args.rs b/crates/ide/src/diagnostics/unused_function_args.rs index ec4825e522..53306052ce 100644 --- a/crates/ide/src/diagnostics/unused_function_args.rs +++ b/crates/ide/src/diagnostics/unused_function_args.rs @@ -18,9 +18,9 @@ use std::collections::HashSet; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; -use elp_ide_db::text_edit::TextRange; use elp_syntax::ast; +use elp_text_edit::TextEdit; +use elp_text_edit::TextRange; use hir::AnyExpr; use hir::AnyExprId; use hir::FunctionClauseDef; diff --git a/crates/ide/src/diagnostics/unused_include.rs b/crates/ide/src/diagnostics/unused_include.rs index eb26bcd923..3a91377338 100644 --- a/crates/ide/src/diagnostics/unused_include.rs +++ b/crates/ide/src/diagnostics/unused_include.rs @@ -12,17 +12,14 @@ // // Return a warning if nothing is used from an include file -use std::borrow::Cow; - use elp_ide_assists::helpers::extend_range; use elp_ide_db::SearchScope; use elp_ide_db::SymbolDefinition; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; use elp_syntax::SmolStr; -use elp_syntax::TextRange; use elp_syntax::ast::AstNode; +use elp_text_edit::TextEdit; use fxhash::FxHashMap; use fxhash::FxHashSet; use hir::FormIdx; @@ -34,11 +31,9 @@ use hir::db::DefDatabase; use hir::known; use lazy_static::lazy_static; -use crate::Assist; +use super::Diagnostic; use crate::diagnostics::DiagnosticCode; -use crate::diagnostics::GenericLinter; -use crate::diagnostics::GenericLinterMatchContext; -use crate::diagnostics::Linter; +use crate::diagnostics::Severity; use crate::fix; lazy_static! { @@ -48,114 +43,56 @@ lazy_static! { .collect(); } -pub(crate) struct UnusedIncludeLinter; - -impl Linter for UnusedIncludeLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::UnusedInclude - } - - fn description(&self) -> &'static str { - "Unused include file" - } - - fn should_process_file_id(&self, sema: &Semantic, file_id: FileId) -> bool { - let file_kind = sema.db.file_kind(file_id); - file_kind.is_module() - } - - fn should_process_generated_files(&self) -> bool { - true - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Context { - path: SmolStr, - extended_range: TextRange, -} - -impl Default for Context { - fn default() -> Self { - Context { - path: SmolStr::new(""), - extended_range: TextRange::default(), - } - } -} - -impl GenericLinter for UnusedIncludeLinter { - type Context = Context; - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let db = sema.db; - let form_list = db.file_form_list(file_id); - let mut cache = Default::default(); - let source_file = db.parse(file_id); - let mut res = Vec::new(); - - for (include_idx, attr) in form_list.includes() { - if !EXCLUDES.contains(attr.path()) { - let in_file = InFile::new(file_id, include_idx); - if let Some(include_file_id) = db.resolve_include(in_file) { - if is_file_used(sema, db, include_file_id, file_id, &mut cache) { - continue; - } - - let path = match attr { - IncludeAttribute::Include { path, .. } => path, - IncludeAttribute::IncludeLib { path, .. } => path, - }; - let attribute = attr.form_id().get(&source_file.tree()); - let attribute_syntax = attribute.syntax(); - let attribute_range = attribute_syntax.text_range(); - let extended_attribute_range = extend_range(attribute_syntax); - - log::debug!("Found unused include {path:?}"); - - res.push(GenericLinterMatchContext { - range: attribute_range, - context: Context { - path: path.clone(), - extended_range: extended_attribute_range, - }, - }); +pub(crate) fn unused_includes( + sema: &Semantic, + db: &dyn DefDatabase, + diagnostics: &mut Vec, + file_id: FileId, +) { + let form_list = db.file_form_list(file_id); + let mut cache = Default::default(); + let source_file = db.parse(file_id); + for (include_idx, attr) in form_list.includes() { + if !EXCLUDES.contains(attr.path()) { + let in_file = InFile::new(file_id, include_idx); + if let Some(include_file_id) = db.resolve_include(in_file) { + if is_file_used(sema, db, include_file_id, file_id, &mut cache) { + continue; } + + let path = match attr { + IncludeAttribute::Include { path, .. } => path, + IncludeAttribute::IncludeLib { path, .. } => path, + }; + let attribute = attr.form_id().get(&source_file.tree()); + let attribute_syntax = attribute.syntax(); + let attribute_range = attribute_syntax.text_range(); + let mut edit_builder = TextEdit::builder(); + let extended_attribute_range = extend_range(attribute_syntax); + edit_builder.delete(extended_attribute_range); + let edit = edit_builder.finish(); + + let diagnostic = Diagnostic::new( + DiagnosticCode::UnusedInclude, + format!("Unused file: {path}"), + attribute_range, + ) + .with_severity(Severity::Warning) + .with_fixes(Some(vec![fix( + "remove_unused_include", + "Remove unused include", + SourceChange::from_text_edit(file_id, edit.clone()), + attribute_range, + )])); + + log::debug!("Found unused include {path:?}"); + + diagnostics.push(diagnostic); } } - Some(res) - } - - fn match_description(&self, context: &Self::Context) -> Cow<'_, str> { - Cow::Owned(format!("Unused file: {}", context.path)) - } - - fn fixes( - &self, - context: &Self::Context, - _range: TextRange, - _sema: &Semantic, - file_id: FileId, - ) -> Option> { - let mut edit_builder = TextEdit::builder(); - edit_builder.delete(context.extended_range); - let edit = edit_builder.finish(); - - Some(vec![fix( - "remove_unused_include", - "Remove unused include", - SourceChange::from_text_edit(file_id, edit), - context.extended_range, - )]) } } -pub static LINTER: UnusedIncludeLinter = UnusedIncludeLinter; - fn is_file_used( sema: &Semantic, db: &dyn DefDatabase, diff --git a/crates/ide/src/diagnostics/unused_macro.rs b/crates/ide/src/diagnostics/unused_macro.rs index 6ea8756b91..89f00e671b 100644 --- a/crates/ide/src/diagnostics/unused_macro.rs +++ b/crates/ide/src/diagnostics/unused_macro.rs @@ -19,9 +19,9 @@ use elp_ide_assists::helpers::extend_range; use elp_ide_db::SymbolDefinition; use elp_ide_db::elp_base_db::FileId; use elp_ide_db::source_change::SourceChange; -use elp_ide_db::text_edit::TextEdit; use elp_syntax::AstNode; use elp_syntax::TextRange; +use elp_text_edit::TextEdit; use hir::Semantic; use crate::diagnostics::DiagnosticCode; @@ -88,13 +88,7 @@ impl GenericLinter for UnusedMacroLinter { Some(DiagnosticTag::Unused) } - fn fixes( - &self, - context: &Context, - _range: TextRange, - _sema: &Semantic, - file_id: FileId, - ) -> Option> { + fn fixes(&self, context: &Context, _sema: &Semantic, file_id: FileId) -> Option> { Some(vec![delete_unused_macro( file_id, context.delete_range, @@ -129,9 +123,7 @@ mod tests { #[track_caller] pub(crate) fn check_diagnostics(fixture: &str) { - let config = DiagnosticsConfig::default() - .disable(DiagnosticCode::UndefinedFunction) - .disable(DiagnosticCode::HirUnresolvedMacro); + let config = DiagnosticsConfig::default().disable(DiagnosticCode::UndefinedFunction); check_diagnostics_with_config(config, fixture) } diff --git a/crates/ide/src/diagnostics_collection.rs b/crates/ide/src/diagnostics_collection.rs index fe1fc759aa..d944e223da 100644 --- a/crates/ide/src/diagnostics_collection.rs +++ b/crates/ide/src/diagnostics_collection.rs @@ -104,7 +104,7 @@ impl DiagnosticCollection { let native = self.native.get(&file_id).unwrap_or(&empty_diags); let erlang_service = self.erlang_service.get(&file_id).unwrap_or(&empty_diags); let mut combined: Vec = - attach_related_diagnostics(file_id, native.clone(), erlang_service.clone()); + attach_related_diagnostics(native.clone(), erlang_service.clone()); let eqwalizer = self.eqwalizer.get(&file_id).into_iter().flatten().cloned(); let eqwalizer_project = self .eqwalizer_project @@ -266,8 +266,8 @@ mod tests { use std::iter::once; use elp_ide_db::elp_base_db::FileId; - use elp_ide_db::text_edit::TextRange; use elp_syntax::label::Label; + use elp_text_edit::TextRange; use fxhash::FxHashMap; use fxhash::FxHashSet; @@ -348,7 +348,7 @@ mod tests { let file_id = *file_id; let diagnostics = diagnostics::native_diagnostics(&db, &config, &vec![], file_id); - let combined = attach_related_diagnostics(file_id, diagnostics, extra_diags.clone()); + let combined = attach_related_diagnostics(diagnostics, extra_diags.clone()); let expected = fixture.annotations_by_file_id(&file_id); let mut actual = combined .into_iter() @@ -415,7 +415,6 @@ mod tests { config, &extra_diags, r#" - //- expect_parse_errors -module(main). -export([foo/0,bar/0]). diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 6a85ab3dc3..d13befe8bb 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -15,9 +15,9 @@ use elp_syntax::AstNode; use hir::InFile; use hir::Semantic; -// @fb-only: use crate::meta_only::exdoc_links; +// @fb-only -// @fb-only: mod meta_only; +// @fb-only mod otp_links; #[derive(Debug, Clone, PartialEq, Eq)] @@ -40,10 +40,10 @@ pub(crate) fn external_docs(db: &RootDatabase, position: &FilePosition) -> Optio if let Some(class) = SymbolClass::classify(&sema, in_file_token.clone()) { class.iter().for_each(|def| { otp_links::links(&mut doc_links, &sema, &def); - // @fb-only: exdoc_links::links(&mut doc_links, &sema, &def); + // @fb-only }); } - // @fb-only: meta_only::links(&mut doc_links, node, position); + // @fb-only Some(doc_links) } diff --git a/crates/ide/src/document_symbols.rs b/crates/ide/src/document_symbols.rs index daed2c6368..390a975132 100644 --- a/crates/ide/src/document_symbols.rs +++ b/crates/ide/src/document_symbols.rs @@ -264,7 +264,7 @@ mod tests { -record(my_second_record, {my_list :: [] }). %% ^^^^^^^^^^^^^^^^ Record | my_second_record -type my_integer() :: integer(). -%% ^^^^^^^^^^ Type | my_integer/0 +%% ^^^^^^^^^^^^ Type | my_integer/0 -define(MEANING_OF_LIFE, 42). %% ^^^^^^^^^^^^^^^ Define | MEANING_OF_LIFE @@ -340,7 +340,7 @@ mod tests { -record(included_record, {my_field :: integer()}). %% ^^^^^^^^^^^^^^^ Record | included_record -type local_type() :: integer(). -%% ^^^^^^^^^^ Type | local_type/0 +%% ^^^^^^^^^^^^ Type | local_type/0 local_function() -> ok. %% ^^^^^^^^^^^^^^ Function | local_function/0 "#, diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index a5a6f759fc..95735a904d 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs @@ -83,7 +83,7 @@ mod tests { check( r#" -module(foo). -bar() -> ?L~INE. +-bar() -> ?L~INE. "#, expect![[r#" LINE @@ -97,7 +97,7 @@ bar() -> ?L~INE. check( r#" -module(foo). -bar() -> ?F~ILE. +-bar() -> ?F~ILE. "#, expect![[r#" FILE @@ -420,7 +420,7 @@ baz() -> maps:get(type, ExpectedQr, missing_expected_type); _ -> Type - end + end, ). baz() -> ?asser~tQrs(AliceWID, ?WA_QR_TYPE_MESSAGE, []), diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs index 88a95e86d7..cf16198dfe 100644 --- a/crates/ide/src/inlay_hints/param_name.rs +++ b/crates/ide/src/inlay_hints/param_name.rs @@ -259,7 +259,6 @@ main() -> fn param_hints_variables_missing_param() { check_params( r#" -//- expect_parse_errors -module(main).~ -compile(export_all). sum(A, B) -> A + B. diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index ad5c1bb680..dcaff6de70 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -110,7 +110,7 @@ pub mod diagnostics; pub mod diagnostics_collection; pub mod diff; mod highlight_related; -// @fb-only: pub mod meta_only; +// @fb-only pub use annotations::Annotation; pub use annotations::AnnotationKind; @@ -251,9 +251,9 @@ impl Analysis { }) } - pub fn should_eqwalize(&self, file_id: FileId) -> Cancellable { + pub fn should_eqwalize(&self, file_id: FileId, include_tests: bool) -> Cancellable { let is_in_app = self.file_app_type(file_id).ok() == Some(Some(AppType::App)); - Ok(is_in_app && self.is_eqwalizer_enabled(file_id)?) + Ok(is_in_app && self.is_eqwalizer_enabled(file_id, include_tests)?) } /// Computes the set of eqwalizer diagnostics for the given files, @@ -383,8 +383,8 @@ impl Analysis { /// - the app (the module belongs to) has `.eqwalizer` marker in the roof /// - or the module has `-typing([eqwalizer]).` pragma /// - or the whole project has `enable_all=true` in its `.elp.toml` file - pub fn is_eqwalizer_enabled(&self, file_id: FileId) -> Cancellable { - self.with_db(|db| db.is_eqwalizer_enabled(file_id)) + pub fn is_eqwalizer_enabled(&self, file_id: FileId, include_tests: bool) -> Cancellable { + self.with_db(|db| db.is_eqwalizer_enabled(file_id, include_tests)) } /// ETF for the module's abstract forms diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index ee5bfb7219..2642aed015 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -77,28 +77,6 @@ fn find_definitions( syntax: &SyntaxNode, position: FilePosition, ) -> RenameResult> { - // Try to find a macro name and classify it to resolve definitions (including across includes) - if let Some(macro_name) = algo::find_node_at_offset::(syntax, position.offset) - && let Some(token) = macro_name.syntax().first_token() - { - let location = InFile { - file_id: position.file_id, - value: token, - }; - match SymbolClass::classify(sema, location) { - Some(SymbolClass::Definition(def)) => return Ok(vec![def]), - Some(SymbolClass::Reference { refs, typ: _ }) => match refs { - ReferenceClass::Definition(def) => return Ok(vec![def]), - ReferenceClass::MultiMacro(defs) => { - return Ok(defs.into_iter().map(SymbolDefinition::Define).collect()); - } - _ => {} - }, - None => {} - } - } - - // If not a macro, try to find a general name let symbols = if let Some(name_like) = algo::find_node_at_offset::(syntax, position.offset) { match &name_like { @@ -194,53 +172,35 @@ pub fn rename_var( #[cfg(test)] pub(crate) mod tests { - use elp_ide_db::RootDatabase; - use elp_ide_db::elp_base_db::AnchoredPathBuf; - use elp_ide_db::elp_base_db::FileId; - use elp_ide_db::elp_base_db::VfsPath; use elp_ide_db::elp_base_db::assert_eq_text; - use elp_ide_db::elp_base_db::fixture::ChangeFixture; use elp_ide_db::elp_base_db::fixture::WithFixture as _; - use elp_ide_db::source_change::FileSystemEdit; - use elp_ide_db::text_edit::TextEdit; use elp_project_model::test_fixture::trim_indent; use elp_syntax::AstNode; use elp_syntax::algo; use elp_syntax::ast; - use fxhash::FxHashSet; + use elp_text_edit::TextEdit; use hir::AnyExprId; use hir::InFile; use hir::Semantic; use super::rename_var; - use crate::AnalysisHost; use crate::fixture; #[track_caller] pub(crate) fn check_rename(new_name: &str, fixture_before: &str, fixture_after_str: &str) { let fixture_after_str = &trim_indent(fixture_after_str); + let analysis_after = fixture::multi_file(fixture_after_str); - let (db_before, fixture) = RootDatabase::with_fixture(fixture_before); - let host_before = AnalysisHost { db: db_before }; - let analysis = host_before.analysis(); - let position = fixture.position(); - - let (db_after, fixture_after) = RootDatabase::with_fixture(fixture_after_str); - let host_after = AnalysisHost { db: db_after }; - let analysis_after = host_after.analysis(); - + let (analysis, position, _) = fixture::position(fixture_before); let rename_result = analysis .rename(position, new_name) .unwrap_or_else(|err| panic!("Rename to '{new_name}' was cancelled: {err}")); match rename_result { Ok(source_change) => { - let mut file_ids: FxHashSet = FxHashSet::default(); for edit in source_change.source_file_edits { let mut text_edit_builder = TextEdit::builder(); let file_id = edit.0; - // New and old file_id are the same - file_ids.insert(file_id); for indel in edit.1.into_iter() { text_edit_builder.replace(indel.delete, indel.insert); } @@ -250,82 +210,6 @@ pub(crate) mod tests { let expected = analysis_after.file_text(file_id).unwrap().to_string(); assert_eq_text!(&*expected, &*result); } - for op in source_change.file_system_edits { - let expected; - let new_file_id; - match op { - FileSystemEdit::CreateFile { - dst, - initial_contents, - } => { - let new_file = - find_new_file_id(&fixture_after, &dst).unwrap_or_else(|| { - panic!( - "Fixture after:could not find file created as '{}'", - &dst.path - ) - }); - new_file_id = *new_file.1; - expected = initial_contents; - let actual = analysis_after.file_text(new_file_id).unwrap().to_string(); - assert_eq_text!(&*expected, &*actual); - } - FileSystemEdit::MoveFile { src: _, dst } => { - let new_file = - find_new_file_id(&fixture_after, &dst).unwrap_or_else(|| { - panic!( - "Fixture after:could not find file renamed to '{}'", - &dst.path - ) - }); - new_file_id = *new_file.1; - // We simply record the new file id for checking in `fixture_after``. - // The expected value will be updated by the new_file_edits below, - // and the result asserted there - } - } - file_ids.insert(new_file_id); - } - for (dst, op) in source_change.new_file_edits { - // When renaming a module, we move the original file, then apply fixup edits - // to the new file - let anchored_dst = AnchoredPathBuf { - anchor: dst.anchor, - path: dst.path, - }; - let new_file = - find_new_file_id(&fixture_after, &anchored_dst).unwrap_or_else(|| { - panic!( - "Fixture after:could not find file created as '{}'", - &anchored_dst.path - ) - }); - - let mut text_edit_builder = TextEdit::builder(); - let file_id = *new_file.1; - // New and old file_id are the same - file_ids.insert(file_id); - for indel in op.iter() { - text_edit_builder.replace(indel.delete, indel.insert.to_string()); - } - let mut result = analysis.file_text(file_id).unwrap().to_string(); - let edit = text_edit_builder.finish(); - edit.apply(&mut result); - let expected = analysis_after.file_text(file_id).unwrap().to_string(); - assert_eq_text!(&*expected, &*result); - } - // Check the balance of the expectations in the new fixture. - for file_id in &fixture_after.files { - if !file_ids.contains(file_id) { - let actual = analysis_after.file_text(*file_id).unwrap().to_string(); - let expected = if fixture.files.contains(file_id) { - analysis.file_text(*file_id).unwrap().to_string() - } else { - format!("File {:?} not present in original fixture", file_id) - }; - assert_eq_text!(&*expected, &*actual); - } - } } Err(err) => { if fixture_after_str.starts_with("error:") { @@ -341,16 +225,6 @@ pub(crate) mod tests { }; } - fn find_new_file_id<'a>( - fixture: &'a ChangeFixture, - dst: &'a AnchoredPathBuf, - ) -> Option<(&'a VfsPath, &'a FileId)> { - fixture - .files_by_path - .iter() - .find(|(name, _)| name.as_path().unwrap().to_string().ends_with(&dst.path)) - } - #[test] fn test_rename_var_1() { check_rename("Y", r#"main() -> I~ = 1."#, r#"main() -> Y = 1."#); @@ -1239,326 +1113,6 @@ pub(crate) mod tests { ); } - // --------------------------------- - // Renaming modules - - #[test] - fn rename_module_fails_name_exists() { - check_rename( - "main_2", - r#" - //- /app_a/src/main.erl - -module(ma~in). - //- /app_a_/src/main_2.erl - -module(main_2). - "#, - r#"error: module 'main_2' already exists"#, - ); - } - - #[test] - fn rename_module_fails_bad_name_1() { - check_rename( - "Main", - r#" - //- /app_a/src/main.erl - -module(ma~in). - //- /app_a_/src/main_2.erl - -module(main_2). - "#, - r#"error: Invalid new module name: 'Main'"#, - ); - } - - #[test] - fn rename_module_simple() { - check_rename( - "main_2", - r#" - //- /app_a/src/main.erl - -module(ma~in). - "#, - r#" - //- /app_a/src/main_2.erl - -module(main_2). - "#, - ); - } - - #[test] - fn rename_module_fails_dup_name() { - check_rename( - "main_2", - r#" - //- /app_a/src/main_2.erl - -module(main_2). - -export([foo/0]). - foo() -> ok. - //- /app_a/src/main.erl - -module(ma~in). - -export([foo/0]). - foo() -> ok. - bar() -> main:foo(). - baz() -> main:bar(). - - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - bar() -> main:foo(). - "#, - r#"error: module 'main_2' already exists"#, - ); - } - - #[test] - fn rename_module_with_usage_internal() { - check_rename( - "main_2", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export([foo/0]). - foo() -> ok. - bar() -> main:foo(). - baz() -> main:bar(). - - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - bar() -> main:foo(). - "#, - //------------------ - r#" - //- /app_a/src/main_2.erl - -module(main_2). - -export([foo/0]). - foo() -> ok. - bar() -> main_2:foo(). - baz() -> main_2:bar(). - - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - bar() -> main_2:foo(). - "#, - ); - } - #[test] - fn rename_module_with_usage_type() { - // TODO: check for compile errors in the fixture - check_rename( - "main_3", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export_type([foo/0]). - -type foo() :: ok. - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - -spec bar() -> main:foo(). - bar() -> ok. - "#, - r#" - //- /app_a/src/main_3.erl - -module(main_3). - -export_type([foo/0]). - -type foo() :: ok. - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - -spec bar() -> main_3:foo(). - bar() -> ok. - "#, - ); - } - - #[test] - fn rename_module_with_usage_record() { - check_rename( - "main_3", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export_type([foo/0]). - -type foo() :: ok. - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - -spec bar() -> main:foo(). - bar() -> ok. - -record(main, {field :: main:foo()}). - "#, - //------------------ - r#" - //- /app_a/src/main_3.erl - -module(main_3). - -export_type([foo/0]). - -type foo() :: ok. - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - -spec bar() -> main_3:foo(). - bar() -> ok. - -record(main, {field :: main_3:foo()}). - "#, - ); - } - - #[test] - fn rename_module_with_usage_fun_arg() { - check_rename( - "main_3", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export_type([foo/0]). - -type foo() :: ok. - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - -spec bar() -> main:foo(). - bar() -> - meck:new(main, [passthrough]), - meck:new([other, main] , [passthrough]), - meck:unload(main), - apply(main, foo, []), - ok. - -record(main, {field :: main:foo()}). - "#, - //------------------ - r#" - //- /app_a/src/main_3.erl - -module(main_3). - -export_type([foo/0]). - -type foo() :: ok. - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - -spec bar() -> main_3:foo(). - bar() -> - meck:new(main_3, [passthrough]), - meck:new([other, main_3] , [passthrough]), - meck:unload(main_3), - apply(main_3, foo, []), - ok. - -record(main, {field :: main_3:foo()}). - "#, - ); - } - - #[test] - fn rename_module_with_usage_fun() { - check_rename( - "main_3", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export([foo/1]). - foo(X) -> {X}. - //- /app_a/src/other.erl - -module(other). - -export([bar/1]). - -spec bar(term()) -> ok. - bar(UStrings) -> - Jobs = [{fun main:foo/1, [U], []} || U <- UStrings], - ok. - "#, - r#" - //- /app_a/src/main_3.erl - -module(main_3). - -export([foo/1]). - foo(X) -> {X}. - //- /app_a/src/other.erl - -module(other). - -export([bar/1]). - -spec bar(term()) -> ok. - bar(UStrings) -> - Jobs = [{fun main_3:foo/1, [U], []} || U <- UStrings], - ok. - "#, - ); - } - - #[test] - fn rename_module_with_usage_fun_as_module() { - check_rename( - "main_3", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export([main/1]). - main(X) -> {X}. - //- /app_a/src/other.erl - -module(other). - -export([bar/1]). - -spec bar(term()) -> ok. - bar(UStrings) -> - Jobs = [{fun main:main/1, [U], []} || U <- UStrings], - ok. - "#, - r#" - //- /app_a/src/main_3.erl - -module(main_3). - -export([main/1]). - main(X) -> {X}. - //- /app_a/src/other.erl - -module(other). - -export([bar/1]). - -spec bar(term()) -> ok. - bar(UStrings) -> - Jobs = [{fun main_3:main/1, [U], []} || U <- UStrings], - ok. - "#, - ); - } - - #[test] - fn rename_module_with_usage_define() { - check_rename( - "main_3", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export([foo/1]). - foo(X) -> {X}. - - //- /app_a/src/definer.hrl - -define(FOO(X), main:foo(X)). - - //- /app_a/src/other.erl - -module(other). - -include("definer.hrl"). - -export([bar/0]). - -spec bar(term()) -> ok. - bar(U) -> - main:foo(U), - ?FOO(U), - ok. - "#, - //------------------ - r#" - //- /app_a/src/main_3.erl - -module(main_3). - -export([foo/1]). - foo(X) -> {X}. - - //- /app_a/src/definer.hrl - -define(FOO(X), main_3:foo(X)). - - //- /app_a/src/other.erl - -module(other). - -include("definer.hrl"). - -export([bar/0]). - -spec bar(term()) -> ok. - bar(U) -> - main_3:foo(U), - ?FOO(U), - ok. - "#, - ); - } - // --------------------------------- #[track_caller] @@ -1629,258 +1183,6 @@ pub(crate) mod tests { ); } - #[test] - fn test_rename_macro() { - check_rename( - "NEW_MACRO", - r#" - -define(OLD_~MACRO, value). - foo() -> ?OLD_MACRO. - "#, - r#" - -define(NEW_MACRO, value). - foo() -> ?NEW_MACRO. - "#, - ); - } - - #[test] - fn test_rename_macro_from_reference() { - check_rename( - "NEW_MACRO", - r#" - -define(OLD_MACRO, value). - foo() -> ?OLD_~MACRO. - "#, - r#" - -define(NEW_MACRO, value). - foo() -> ?NEW_MACRO. - "#, - ); - } - - #[test] - fn test_rename_macro_atom() { - check_rename( - "new_macro", - r#" - -define(old_~macro, value). - foo() -> ?old_macro. - "#, - r#" - -define(new_macro, value). - foo() -> ?new_macro. - "#, - ); - } - - #[test] - fn test_rename_macro_atom_from_reference() { - check_rename( - "new_macro", - r#" - -define(old_macro, value). - foo() -> ?old_~macro. - "#, - r#" - -define(new_macro, value). - foo() -> ?new_macro. - "#, - ); - } - - #[test] - fn test_rename_macro_from_definition_multi_file() { - check_rename( - "NEW_MACRO", - r#" - //- /src/common.hrl - -define(OLD_~MACRO, value). - - //- /src/module_a.erl - -module(module_a). - -include("common.hrl"). - foo() -> ?OLD_MACRO. - - //- /src/module_b.erl - -module(module_b). - -include("common.hrl"). - bar() -> ?OLD_MACRO. - "#, - r#" - //- /src/common.hrl - -define(NEW_MACRO, value). - - //- /src/module_a.erl - -module(module_a). - -include("common.hrl"). - foo() -> ?NEW_MACRO. - - //- /src/module_b.erl - -module(module_b). - -include("common.hrl"). - bar() -> ?NEW_MACRO. - "#, - ); - } - - #[test] - fn test_rename_macro_from_usage_multi_file() { - check_rename( - "NEW_MACRO", - r#" - //- /src/common.hrl - -define(OLD_MACRO, value). - - //- /src/module_a.erl - -module(module_a). - -include("common.hrl"). - foo() -> ?OLD_~MACRO. - - //- /src/module_b.erl - -module(module_b). - -include("common.hrl"). - bar() -> ?OLD_MACRO. - "#, - r#" - //- /src/common.hrl - -define(NEW_MACRO, value). - - //- /src/module_a.erl - -module(module_a). - -include("common.hrl"). - foo() -> ?NEW_MACRO. - - //- /src/module_b.erl - -module(module_b). - -include("common.hrl"). - bar() -> ?NEW_MACRO. - "#, - ); - } - - #[test] - fn test_rename_macro_name_clash() { - check_rename( - "EXISTING_MACRO", - r#" - -define(OLD_~MACRO, value1). - -define(EXISTING_MACRO, value2). - foo() -> ?OLD_MACRO. - "#, - r#"error: Macro 'EXISTING_MACRO' already in scope"#, - ); - } - - #[test] - fn test_rename_macro_from_usage_ifdef() { - check_rename( - "NEW_MACRO", - r#" - //- /src/common.hrl - -ifndef(TEST). - -define(OLD_MACRO, value1). - -else. - -define(OLD_MACRO, value2). - -endif. - - //- /src/module_a.erl - -module(module_a). - -include("common.hrl"). - foo() -> ?OLD_~MACRO. - - //- /src/module_b.erl - -module(module_b). - -include("common.hrl"). - bar() -> ?OLD_MACRO. - "#, - r#" - //- /src/common.hrl - -ifndef(TEST). - -define(OLD_MACRO, value1). - -else. - -define(NEW_MACRO, value2). - -endif. - - //- /src/module_a.erl - -module(module_a). - -include("common.hrl"). - foo() -> ?NEW_MACRO. - - //- /src/module_b.erl - -module(module_b). - -include("common.hrl"). - bar() -> ?NEW_MACRO. - "#, - ); - } - - #[test] - fn test_rename_macro_name_clash_from_reference() { - check_rename( - "EXISTING_MACRO", - r#" - -define(OLD_MACRO, value1). - -define(EXISTING_MACRO, value2). - foo() -> ?OLD_~MACRO. - "#, - r#"error: Macro 'EXISTING_MACRO' already in scope"#, - ); - } - - #[test] - fn test_rename_macro_name_clash_from_reference_multi_file() { - check_rename( - "EXISTING_MACRO", - r#" - //- /src/common.hrl - -define(OLD_MACRO, value1). - - //- /src/module_a.erl - -module(module_a). - -include("common.hrl"). - foo() -> ?OLD_~MACRO. - - //- /src/module_b.erl - -module(module_b). - -include("common.hrl"). - -define(EXISTING_MACRO, value3). - bar() -> ?OLD_MACRO. - "#, - r#"error: Macro 'EXISTING_MACRO' already in scope"#, - ); - } - - #[test] - fn test_rename_macro_different_arity_ok() { - check_rename( - "EXISTING_MACRO", - r#" - -define(OLD_~MACRO, value1). - -define(EXISTING_MACRO(X), X). - foo() -> ?OLD_MACRO. - "#, - r#" - -define(EXISTING_MACRO, value1). - -define(EXISTING_MACRO(X), X). - foo() -> ?EXISTING_MACRO. - "#, - ); - } - - #[test] - fn test_rename_macro_same_arity_conflict() { - check_rename( - "EXISTING_MACRO", - r#" - -define(OLD_~MACRO(X), X). - -define(EXISTING_MACRO(Y), Y). - foo() -> ?OLD_MACRO(1). - "#, - r#"error: Macro 'EXISTING_MACRO' already in scope"#, - ); - } - #[test] fn test_rename_in_rpc_call_4() { check_rename( @@ -2700,403 +2002,20 @@ pub(crate) mod tests { check_rename( "new_name", r#" - //- /src/baz.erl - -module(baz). - foo() -> - erpc:send_request(node, ?MODULE, bar, [], label, collection). + //- /src/baz.erl + -module(baz). + foo() -> + erpc:send_request(node, ?MODULE, bar, [], label, collection). - b~ar() -> - ok."#, + b~ar() -> + ok."#, r#" - -module(baz). - foo() -> - erpc:send_request(node, ?MODULE, new_name, [], label, collection). + -module(baz). + foo() -> + erpc:send_request(node, ?MODULE, new_name, [], label, collection). - new_name() -> - ok."#, - ); - } - - // --------------------------------- - // Type Renaming Tests - // --------------------------------- - - #[test] - fn test_rename_type_simple() { - check_rename( - "new_type", - r#" - -module(main). - -type ol~d_type() :: ok. - -spec foo(old_type()) -> ok. - foo(_) -> ok. - "#, - r#" - -module(main). - -type new_type() :: ok. - -spec foo(new_type()) -> ok. - foo(_) -> ok. - "#, - ); - } - - #[test] - fn test_rename_type_with_arity() { - check_rename( - "new_type", - r#" - -module(main). - -type old_~type(T) :: {ok, T}. - -spec foo(old_type(integer())) -> ok. - foo(_) -> ok. - "#, - r#" - -module(main). - -type new_type(T) :: {ok, T}. - -spec foo(new_type(integer())) -> ok. - foo(_) -> ok. - "#, - ); - } - - #[test] - fn test_rename_type_from_usage() { - check_rename( - "new_type", - r#" - -module(main). - -type old_type() :: ok. - -spec foo(old_~type()) -> ok. - foo(_) -> ok. - "#, - r#" - -module(main). - -type new_type() :: ok. - -spec foo(new_type()) -> ok. - foo(_) -> ok. - "#, - ); - } - - #[test] - fn test_rename_opaque_type() { - check_rename( - "new_type", - r#" - -module(main). - -opaque old_~type() :: {internal, term()}. - -spec create() -> old_type(). - create() -> {internal, data}. - "#, - r#" - -module(main). - -opaque new_type() :: {internal, term()}. - -spec create() -> new_type(). - create() -> {internal, data}. - "#, - ); - } - - #[test] - fn test_rename_type_fails_name_clash() { - check_rename( - "existing_type", - r#" - -module(main). - -type old_~type() :: ok. - -type existing_type() :: error. - "#, - r#"error: Type 'existing_type/0' already in scope"#, - ); - } - - #[test] - fn test_rename_type_allows_different_arity() { - check_rename( - "existing_type", - r#" - -module(main). - -type old_~type() :: ok. - -type existing_type(T) :: {error, T}. - "#, - r#" - -module(main). - -type existing_type() :: ok. - -type existing_type(T) :: {error, T}. - "#, - ); - } - - #[test] - fn test_rename_type_invalid_name() { - check_rename( - "New_Type", - r#" - -module(main). - -type old_~type() :: ok. - "#, - r#"error: Invalid new type name: 'New_Type'"#, - ); - } - - #[test] - fn test_rename_type_remote_reference() { - check_rename( - "new_type", - r#" - //- /src/module_a.erl - -module(module_a). - -export_type([old_~type/0]). - -type old_type() :: {ok, term()}. - - //- /src/module_b.erl - -module(module_b). - -spec foo(module_a:old_type()) -> ok. - foo(_) -> ok. - "#, - r#" - //- /src/module_a.erl - -module(module_a). - -export_type([new_type/0]). - -type new_type() :: {ok, term()}. - - //- /src/module_b.erl - -module(module_b). - -spec foo(module_a:new_type()) -> ok. - foo(_) -> ok. - "#, - ); - } - - #[test] - fn test_rename_type_remote_reference_from_usage() { - check_rename( - "new_type", - r#" - //- /src/module_a.erl - -module(module_a). - -export_type([old_type/0]). - -type old_type() :: {ok, term()}. - - //- /src/module_b.erl - -module(module_b). - -spec foo(module_a:old_~type()) -> ok. - foo(_) -> ok. - "#, - r#" - //- /src/module_a.erl - -module(module_a). - -export_type([new_type/0]). - -type new_type() :: {ok, term()}. - - //- /src/module_b.erl - -module(module_b). - -spec foo(module_a:new_type()) -> ok. - foo(_) -> ok. - "#, - ); - } - - #[test] - fn test_rename_type_from_header_multi_file() { - check_rename( - "new_type", - r#" - //- /src/types.hrl - -type old_~type() :: {ok, term()}. - - //- /src/module_a.erl - -module(module_a). - -include("types.hrl"). - -spec foo(old_type()) -> ok. - foo(_) -> ok. - - //- /src/module_b.erl - -module(module_b). - -include("types.hrl"). - -spec bar(old_type()) -> ok. - bar(_) -> ok. - "#, - r#" - //- /src/types.hrl - -type new_type() :: {ok, term()}. - - //- /src/module_a.erl - -module(module_a). - -include("types.hrl"). - -spec foo(new_type()) -> ok. - foo(_) -> ok. - - //- /src/module_b.erl - -module(module_b). - -include("types.hrl"). - -spec bar(new_type()) -> ok. - bar(_) -> ok. - "#, - ); - } - - #[test] - fn test_rename_type_from_usage_in_header() { - check_rename( - "new_type", - r#" - //- /src/types.hrl - -type old_type() :: {ok, term()}. - - //- /src/module_a.erl - -module(module_a). - -include("types.hrl"). - -spec foo(old_~type()) -> ok. - foo(_) -> ok. - - //- /src/module_b.erl - -module(module_b). - -include("types.hrl"). - -spec bar(old_type()) -> ok. - bar(_) -> ok. - "#, - r#" - //- /src/types.hrl - -type new_type() :: {ok, term()}. - - //- /src/module_a.erl - -module(module_a). - -include("types.hrl"). - -spec foo(new_type()) -> ok. - foo(_) -> ok. - - //- /src/module_b.erl - -module(module_b). - -include("types.hrl"). - -spec bar(new_type()) -> ok. - bar(_) -> ok. - "#, - ); - } - - #[test] - fn test_rename_type_name_clash_in_remote_module() { - check_rename( - "existing_type", - r#" - //- /src/module_a.erl - -module(module_a). - -export_type([old_type/0]). - -type old_~type() :: {ok, term()}. - - //- /src/module_b.erl - -module(module_b). - -type existing_type() :: error. - -spec foo(module_a:old_type()) -> ok. - foo(_) -> ok. - "#, - r#"error: Type 'existing_type/0' already in scope"#, - ); - } - - #[test] - fn test_rename_type_name_clash_from_header_multi_file() { - check_rename( - "existing_type", - r#" - //- /src/types.hrl - -type old_type() :: {ok, term()}. - - //- /src/module_a.erl - -module(module_a). - -include("types.hrl"). - -spec foo(old_~type()) -> ok. - foo(_) -> ok. - - //- /src/module_b.erl - -module(module_b). - -include("types.hrl"). - -type existing_type() :: error. - -spec bar(old_type()) -> ok. - bar(_) -> ok. - "#, - r#"error: Type 'existing_type/0' already in scope"#, - ); - } - - #[test] - fn test_rename_opaque_type_from_header() { - check_rename( - "new_type", - r#" - //- /src/types.hrl - -opaque old_~type() :: {internal, term()}. - - //- /src/module_a.erl - -module(module_a). - -include("types.hrl"). - -spec create() -> old_type(). - create() -> {internal, data}. - - //- /src/module_b.erl - -module(module_b). - -include("types.hrl"). - -spec use(old_type()) -> ok. - use(_) -> ok. - "#, - r#" - //- /src/types.hrl - -opaque new_type() :: {internal, term()}. - - //- /src/module_a.erl - -module(module_a). - -include("types.hrl"). - -spec create() -> new_type(). - create() -> {internal, data}. - - //- /src/module_b.erl - -module(module_b). - -include("types.hrl"). - -spec use(new_type()) -> ok. - use(_) -> ok. - "#, - ); - } - - #[test] - fn test_rename_macro_separate_definitions() { - check_rename( - "NEW_MACRO", - r#" - //- /src/a.hrl - -define(MACRO, ok). - - //- /src/a.erl - -module(a). - -include("a.hrl"). - foo() -> ?MACRO~. - - //- /src/b.hrl - -define(MACRO, error). - - //- /src/b.erl - -module(b). - -include("b.hrl"). - bar() -> ?MACRO. - "#, - r#" - //- /src/a.hrl - -define(NEW_MACRO, ok). - - //- /src/a.erl - -module(a). - -include("a.hrl"). - foo() -> ?NEW_MACRO. - - //- /src/b.hrl - -define(MACRO, error). - - //- /src/b.erl - -module(b). - -include("b.hrl"). - bar() -> ?MACRO. - "#, + new_name() -> + ok."#, ); } } diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 0aa731c8c9..4b2348f610 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -243,7 +243,7 @@ mod tests { //- /my_app/src/runnables.erl ~ -module(runnables). - -export([all/0]). + -export([all/]). main() -> ok. "#, diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index d09ec201f8..fba6d12d73 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -311,7 +311,6 @@ mod tests { fn test_fn_signature_local_two_args() { check( r#" -//- expect_parse_errors -module(main). -spec add(integer(), integer()) -> integer(). @@ -344,7 +343,6 @@ main() -> ); check( r#" -//- expect_parse_errors -module(main). -spec add(integer(), integer()) -> integer(). @@ -377,7 +375,6 @@ main() -> ); check( r#" -//- expect_parse_errors -module(main). -spec add(integer(), integer()) -> integer(). @@ -414,7 +411,6 @@ main() -> fn test_fn_signature_remote_two_args() { check( r#" -//- expect_parse_errors //- /one.erl -module(one). @@ -453,7 +449,6 @@ main() -> ); check( r#" -//- expect_parse_errors //- /one.erl -module(one). @@ -492,7 +487,6 @@ main() -> ); check( r#" -//- expect_parse_errors //- /one.erl -module(one). @@ -535,7 +529,6 @@ main() -> fn test_fn_signature_quoted_remote_two_args() { check( r#" -//- expect_parse_errors //- /Elixir.One.erl -module('Elixir.One'). @@ -583,7 +576,6 @@ main() -> fn test_fn_signature_unclosed_call() { check( r#" -//- expect_parse_errors -module(main). -compile(export_all). @@ -634,7 +626,6 @@ main() -> fn test_fn_signature_doc() { check( r#" -//- expect_parse_errors -module(main). -compile(export_all). @@ -694,7 +685,6 @@ main() -> if supports_eep59_doc_attributes() { check( r#" -//- expect_parse_errors -module(main). -compile(export_all). @@ -763,7 +753,6 @@ main() -> fn test_fn_signature_local_imported() { check( r#" -//- expect_parse_errors //- /one.erl -module(one). -compile(export_all). @@ -805,7 +794,6 @@ main() -> fn test_fn_signature_spec_arg_names() { check( r#" -//- expect_parse_errors //- /one.erl -module(one). -compile(export_all). diff --git a/crates/ide/src/tests.rs b/crates/ide/src/tests.rs index 55e9494e48..a32b7e3044 100644 --- a/crates/ide/src/tests.rs +++ b/crates/ide/src/tests.rs @@ -20,8 +20,8 @@ use elp_ide_db::elp_base_db::SourceDatabaseExt; use elp_ide_db::elp_base_db::assert_eq_text; use elp_ide_db::elp_base_db::fixture::WithFixture; use elp_ide_db::elp_base_db::remove_annotations; -use elp_ide_db::text_edit::TextRange; use elp_project_model::test_fixture::trim_indent; +use elp_text_edit::TextRange; use expect_test::Expect; use itertools::Itertools; @@ -376,10 +376,7 @@ pub(crate) fn check_diagnostics(fixture: &str) { let config = DiagnosticsConfig::default() .set_experimental(true) .disable(DiagnosticCode::UnspecificInclude) - .disable(DiagnosticCode::BinaryStringToSigil) - .disable(DiagnosticCode::HirUnresolvedMacro) - .disable(DiagnosticCode::BoundVarInLhs) - .disable(DiagnosticCode::HirUnresolvedInclude); + .disable(DiagnosticCode::BinaryStringToSigil); check_diagnostics_with_config(config, fixture) } @@ -402,23 +399,6 @@ fn convert_diagnostics_to_annotations(diagnostics: Vec) -> Vec<(Text annotation.push_str(&d.code.as_code()); annotation.push_str(": "); annotation.push_str(&convert_diagnostic_message(&d)); - - // Append related info to the annotation - if let Some(related_info) = &d.related_info { - // Sort related info alphabetically by message for consistent test output - let mut sorted_info = related_info.clone(); - sorted_info.sort_by(|a, b| a.message.cmp(&b.message)); - for info in sorted_info { - annotation.push_str(&format!( - "\nRelated info: {}:{}-{} {}", - info.file_id.index(), - u32::from(info.range.start()), - u32::from(info.range.end()), - info.message - )); - } - } - (d.range, annotation) }) .collect::>(); @@ -531,8 +511,7 @@ pub(crate) fn check_diagnostics_with_config_and_extra( for file_id in &fixture.files { let file_id = *file_id; let diagnostics = diagnostics::native_diagnostics(&analysis.db, &config, &vec![], file_id); - let diagnostics = - diagnostics::attach_related_diagnostics(file_id, diagnostics, extra_diags.clone()); + let diagnostics = diagnostics::attach_related_diagnostics(diagnostics, extra_diags.clone()); let expected = fixture.annotations_by_file_id(&file_id); let actual = convert_diagnostics_to_annotations(diagnostics); @@ -545,7 +524,6 @@ pub fn check_no_parse_errors(analysis: &Analysis, file_id: FileId) { let config = DiagnosticsConfig::default() .disable(DiagnosticCode::UnspecificInclude) .disable(DiagnosticCode::UndefinedFunction) - .disable(DiagnosticCode::HirUnresolvedMacro) .disable(DiagnosticCode::NoCatch); check_no_parse_errors_with_config(analysis, file_id, &config, &vec![]); } @@ -696,8 +674,7 @@ mod test { fn filtered_diagnostics_passes_syntax_errors() { check_filtered_diagnostics( r#" - //- expect_parse_errors - %%<^^^^^^^^^^^^ 💡 error: L1201: no module definition + %%<^^^^^^^^^^^^ error: L1201: no module definition foo() -> bug bug. %% ^^^^ error: P1711: Syntax Error diff --git a/crates/ide_assists/Cargo.toml b/crates/ide_assists/Cargo.toml index b2277cd12d..167e1f4b11 100644 --- a/crates/ide_assists/Cargo.toml +++ b/crates/ide_assists/Cargo.toml @@ -9,6 +9,7 @@ workspace = true [dependencies] elp_ide_db.workspace = true elp_syntax.workspace = true +elp_text_edit.workspace = true hir.workspace = true cov-mark.workspace = true diff --git a/crates/ide_assists/src/handlers/add_doc.rs b/crates/ide_assists/src/handlers/add_doc.rs index 87a511fbff..b1f51a7b90 100644 --- a/crates/ide_assists/src/handlers/add_doc.rs +++ b/crates/ide_assists/src/handlers/add_doc.rs @@ -12,9 +12,9 @@ use std::fmt::Write; use elp_ide_db::assists::AssistId; use elp_ide_db::assists::AssistKind; -use elp_ide_db::text_edit::TextSize; use elp_syntax::AstNode; use elp_syntax::ast; +use elp_text_edit::TextSize; use hir::FunctionDef; use crate::AssistContext; diff --git a/crates/ide_assists/src/handlers/flip_sep.rs b/crates/ide_assists/src/handlers/flip_sep.rs index 65ae663518..662e31b3e9 100644 --- a/crates/ide_assists/src/handlers/flip_sep.rs +++ b/crates/ide_assists/src/handlers/flip_sep.rs @@ -10,12 +10,12 @@ use elp_ide_db::assists::AssistId; use elp_ide_db::assists::AssistKind; -use elp_ide_db::text_edit::TextRange; use elp_syntax::AstNode; use elp_syntax::Direction; use elp_syntax::SyntaxKind; use elp_syntax::SyntaxToken; use elp_syntax::algo::non_trivia_sibling; +use elp_text_edit::TextRange; use fxhash::FxHashSet; use hir::InFile; diff --git a/crates/ide_assists/src/handlers/implement_behaviour.rs b/crates/ide_assists/src/handlers/implement_behaviour.rs index 2821e9214e..384ac8a65b 100644 --- a/crates/ide_assists/src/handlers/implement_behaviour.rs +++ b/crates/ide_assists/src/handlers/implement_behaviour.rs @@ -12,10 +12,10 @@ use std::cmp::max; use elp_ide_db::assists::AssistId; use elp_ide_db::assists::AssistKind; -use elp_ide_db::text_edit::TextRange; -use elp_ide_db::text_edit::TextSize; use elp_syntax::AstNode; use elp_syntax::ast::BehaviourAttribute; +use elp_text_edit::TextRange; +use elp_text_edit::TextSize; use hir::Callback; use hir::CallbackId; use hir::InFile; diff --git a/crates/ide_assists/src/handlers/inline_function.rs b/crates/ide_assists/src/handlers/inline_function.rs index 055395af52..69dbb1c55d 100644 --- a/crates/ide_assists/src/handlers/inline_function.rs +++ b/crates/ide_assists/src/handlers/inline_function.rs @@ -22,7 +22,6 @@ use elp_ide_db::elp_base_db::FileRange; use elp_ide_db::find_best_token; use elp_ide_db::helpers::get_call; use elp_ide_db::rename::SafetyChecks; -use elp_ide_db::text_edit::TextEdit; use elp_syntax::AstNode; use elp_syntax::NodeOrToken; use elp_syntax::SyntaxKind; @@ -33,6 +32,7 @@ use elp_syntax::TextSize; use elp_syntax::ast; use elp_syntax::ast::HasArity; use elp_syntax::ast::edit::IndentLevel; +use elp_text_edit::TextEdit; use fxhash::FxHashSet; use hir::FunctionDef; use hir::InFile; diff --git a/crates/ide_assists/src/helpers.rs b/crates/ide_assists/src/helpers.rs index 121b1dda41..bb2a38cf1b 100644 --- a/crates/ide_assists/src/helpers.rs +++ b/crates/ide_assists/src/helpers.rs @@ -20,8 +20,6 @@ use elp_ide_db::elp_base_db::FileId; use elp_ide_db::helpers::top_insert_position; use elp_ide_db::rename::is_safe_function; use elp_ide_db::source_change::SourceChangeBuilder; -use elp_ide_db::text_edit::TextEdit; -use elp_ide_db::text_edit::TextSize; use elp_syntax::AstNode; use elp_syntax::AstPtr; use elp_syntax::Direction; @@ -36,6 +34,8 @@ use elp_syntax::algo; use elp_syntax::algo::skip_inline_comment; use elp_syntax::ast; use elp_syntax::match_ast; +use elp_text_edit::TextEdit; +use elp_text_edit::TextSize; use fxhash::FxHashSet; use hir::Attribute; use hir::Body; diff --git a/crates/ide_completion/src/attributes.rs b/crates/ide_completion/src/attributes.rs index f381df147d..fc97832d30 100644 --- a/crates/ide_completion/src/attributes.rs +++ b/crates/ide_completion/src/attributes.rs @@ -166,7 +166,6 @@ mod test { fn test_error_recovery() { check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample1). % U.S. English @@ -181,7 +180,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample1). % U.K. English @@ -199,7 +197,6 @@ mod test { fn test_typing_attribute() { check( r#" - //- expect_parse_errors -module(sample). -typ~ "#, @@ -214,7 +211,6 @@ mod test { fn test_module_attribute() { check( r#" - //- expect_parse_errors -mod~ "#, None, @@ -228,7 +224,6 @@ mod test { fn test_module_attribute_hyphen() { check( r#" - //- expect_parse_errors //- /src/my-module.erl -mod~ "#, @@ -243,7 +238,6 @@ mod test { fn test_module_attribute_at() { check( r#" - //- expect_parse_errors //- /src/my@module.erl -mod~ "#, @@ -258,7 +252,6 @@ mod test { fn test_module_attribute_underscore() { check( r#" - //- expect_parse_errors //- /src/my_module.erl -mod~ "#, @@ -273,7 +266,6 @@ mod test { fn test_module_attribute_uppercase() { check( r#" - //- expect_parse_errors //- /src/Module.erl -mod~ "#, @@ -288,7 +280,6 @@ mod test { fn test_module_attribute_uppercase_middle() { check( r#" - //- expect_parse_errors //- /src/moDule.erl -mod~ "#, diff --git a/crates/ide_completion/src/ctx.rs b/crates/ide_completion/src/ctx.rs index 0d9381e7ec..22e385e3fa 100644 --- a/crates/ide_completion/src/ctx.rs +++ b/crates/ide_completion/src/ctx.rs @@ -281,7 +281,6 @@ mod ctx_tests { fn expr_ctx() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> ~X. @@ -291,7 +290,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> case 1 of. @@ -303,7 +301,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> fun(_) -> ~X end. @@ -313,7 +310,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> try 1 @@ -357,7 +353,6 @@ mod ctx_tests { fn ctx_pattern() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(Y, X) -> ~Y = X. @@ -367,7 +362,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(X) -> case rand:uniform(1) of @@ -379,7 +373,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(X) -> fun(X~) -> 1 end. @@ -389,7 +382,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> receive @@ -401,7 +393,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> try [1] @@ -416,7 +407,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(X) -> if @@ -439,7 +429,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(Y, X) -> try ok of @@ -451,7 +440,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(Y, X) -> try ok of @@ -469,7 +457,6 @@ mod ctx_tests { fn ctx_pattern_error_recovery_wip() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(Y, X) -> try ok of @@ -482,7 +469,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(Y, X) -> try ok of @@ -499,7 +485,6 @@ mod ctx_tests { fn test_type_param_ctx() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -type ty(s~) :: ok. "#), @@ -511,7 +496,6 @@ mod ctx_tests { fn test_export_ctx() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -export([ f~ @@ -525,7 +509,6 @@ mod ctx_tests { fn test_export_type_ctx() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -export_type([ t~ @@ -539,7 +522,6 @@ mod ctx_tests { fn test_spec_ctx() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -spec t~ table() -> ok. @@ -553,7 +535,6 @@ mod ctx_tests { fn test_type_ctx() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -spec test() -> ~ test() -> ok. @@ -563,7 +544,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -spec test() -> o~k test() -> ok. @@ -573,7 +553,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -spec test(o~) -> ok. test() -> ok. @@ -583,7 +562,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -record(foo, {field1, field2 :: X~}). "#), @@ -592,7 +570,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -opaque test() :: ~. "#), @@ -601,7 +578,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -nominal test() :: ~. "#), @@ -610,7 +586,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -type test() :: m~ "#), @@ -619,7 +594,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -spec test() -> ~ok. "#), @@ -631,7 +605,6 @@ mod ctx_tests { fn test_ctx_error_recovery() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> ~ @@ -641,7 +614,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> X + ~ @@ -651,7 +623,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> X + ~. @@ -661,7 +632,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> case rand:uniform(1) of @@ -673,7 +643,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> (erlang:term_to_binary(~ @@ -684,7 +653,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> (erlang:term_to_binary(~. @@ -695,7 +663,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -type ty() :: ~ "#), @@ -704,7 +671,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -type ty() :: l~. "#), @@ -713,7 +679,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -record(rec, {field = lists:map(fun(X) -> X + 1 end, [1, ~])}). "#), diff --git a/crates/ide_completion/src/export_functions.rs b/crates/ide_completion/src/export_functions.rs index ef803eb9ab..f362ea830a 100644 --- a/crates/ide_completion/src/export_functions.rs +++ b/crates/ide_completion/src/export_functions.rs @@ -83,7 +83,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -export([ foo~ @@ -107,7 +106,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -export([ function_a/0, diff --git a/crates/ide_completion/src/export_types.rs b/crates/ide_completion/src/export_types.rs index c21a37339e..9e80828b66 100644 --- a/crates/ide_completion/src/export_types.rs +++ b/crates/ide_completion/src/export_types.rs @@ -79,7 +79,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -export_type([ foo~ diff --git a/crates/ide_completion/src/functions.rs b/crates/ide_completion/src/functions.rs index eab033765f..4ce641d0e9 100644 --- a/crates/ide_completion/src/functions.rs +++ b/crates/ide_completion/src/functions.rs @@ -243,7 +243,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -266,7 +265,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -340,7 +338,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -363,7 +360,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -383,14 +379,12 @@ mod test { {label:foon/2, kind:Function, contents:Snippet("foon(${1:A}, ${2:B})"), position:Some(FilePosition { file_id: FileId(1), offset: 86 })}"#]], ); } - #[test] fn test_remote_calls_deprecated() { assert!(serde_json::to_string(&lsp_types::CompletionItemKind::MODULE).unwrap() == "9"); check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -419,7 +413,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -448,7 +441,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -474,7 +466,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -593,7 +584,6 @@ mod test { fn test_remote_fun_exprs_with_trigger() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). main(_) -> @@ -617,7 +607,6 @@ mod test { fn test_local_fun_exprs_with_trigger() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). foo() -> ok. @@ -633,7 +622,6 @@ mod test { fn test_local_fun_exprs_no_trigger() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). foo() -> ok. @@ -649,7 +637,6 @@ mod test { fn function_error_recovery() { check( r#" - //- expect_parse_errors -module(sample1). foo() -> b~ @@ -663,7 +650,6 @@ mod test { ); check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -682,7 +668,6 @@ mod test { fn test_local_and_remote() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). samba() -> ok. @@ -703,7 +688,6 @@ mod test { fn test_remote_call_broken_case() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). test() -> @@ -725,7 +709,6 @@ mod test { fn test_local_call_broken_case() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). foo() -> ok. @@ -819,7 +802,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -838,7 +820,6 @@ mod test { ); check( r#" -//- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -858,7 +839,6 @@ foo(X, Y) -> ok. ); check( r#" -//- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -922,7 +902,6 @@ foo(X, Y) -> ok. fn test_remote_call_same_module_macro_prefix() { check( r#" - //- expect_parse_errors -module(main). -export([main/0, do_not_use_me/0]). -deprecated({do_not_use_me, 0, "Because I said so"}). @@ -943,7 +922,6 @@ foo(X, Y) -> ok. fn test_in_dialyzer_attribute() { check( r#" - //- expect_parse_errors -module(main). -export([ foo/1, @@ -964,7 +942,6 @@ foo(X, Y) -> ok. fn test_quoted_local_call() { check( r#" - //- expect_parse_errors -module(sample). test() -> fo~(something). diff --git a/crates/ide_completion/src/keywords.rs b/crates/ide_completion/src/keywords.rs index dc60ae8158..734afc80a5 100644 --- a/crates/ide_completion/src/keywords.rs +++ b/crates/ide_completion/src/keywords.rs @@ -141,7 +141,6 @@ mod test { fn test_no_keywords() { check( r#" - //- expect_parse_errors -module(sample). test(X) -> a~ @@ -151,7 +150,6 @@ mod test { ); check( r#" - //- expect_parse_errors -module(sample). test(~X) -> X. @@ -162,7 +160,6 @@ mod test { check( r#" - //- expect_parse_errors -module(m~). "#, None, @@ -171,7 +168,6 @@ mod test { check( r#" - //- expect_parse_errors -module(m). -~ "#, @@ -181,7 +177,6 @@ mod test { check( r#" - //- expect_parse_errors -module(m). -type foo() :: ~. "#, @@ -196,7 +191,6 @@ mod test { fn test_keywords_error_recovery() { check( r#" - //- expect_parse_errors -module(sample). test(X) -> X ~ @@ -240,7 +234,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). test(X) -> ~ diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index f41aecdd67..71b4ff02c0 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs @@ -40,7 +40,7 @@ mod helpers; mod keywords; mod macros; mod maps; -// @fb-only: mod meta_only; +// @fb-only mod modules; mod records; mod spec; @@ -176,7 +176,7 @@ pub fn completions( } CtxKind::Other => { let _ = attributes::add_completions(&mut acc, ctx) - // @fb-only: || meta_only::add_completions(&mut acc, ctx) + // @fb-only || vars::add_completions(&mut acc, ctx) || maps::add_completions(&mut acc, ctx) || records::add_completions(&mut acc, ctx); diff --git a/crates/ide_completion/src/macros.rs b/crates/ide_completion/src/macros.rs index e86cf3ba93..3c4b77cfad 100644 --- a/crates/ide_completion/src/macros.rs +++ b/crates/ide_completion/src/macros.rs @@ -253,7 +253,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample1). -define(FOO, 1). -define(FOO(), 1). @@ -272,7 +271,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample1). -define(FOO, 1). -define(BAR, 1). @@ -284,7 +282,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample1). -define(FOO, ok). -define(BAR, 1). diff --git a/crates/ide_completion/src/maps.rs b/crates/ide_completion/src/maps.rs index e232a7d8bc..4371793356 100644 --- a/crates/ide_completion/src/maps.rs +++ b/crates/ide_completion/src/maps.rs @@ -214,7 +214,6 @@ mod test { fn test_local_type() { check( r#" - //- expect_parse_errors -module(test_local_type). -type my_map() :: #{field1 := integer(), field2 => boolean()}. foo(X) -> #~ @@ -230,7 +229,6 @@ mod test { fn test_included_type() { check( r#" - //- expect_parse_errors //- /include/test_included_type.hrl include_path:/include -type my_included_map() :: #{field1 := integer(), field2 => integer()}. //- /src/test_included_type.erl @@ -252,7 +250,6 @@ mod test { fn test_empty_map_type() { check( r#" - //- expect_parse_errors -module(test_empty_map_type). -type my_map() :: #{}. foo(X) -> #~ @@ -268,7 +265,6 @@ mod test { fn test_arity_1_map_type() { check( r#" - //- expect_parse_errors -module(test_arity_1_map_type). -type my_map() :: #{field1 := true }. foo(X) -> #~ @@ -284,7 +280,6 @@ mod test { fn test_mixed_map_and_record_types() { check( r#" - //- expect_parse_errors -module(test_mixed_map_and_record_types). -type my_map() :: #{field1 := true }. -record(my_record, {field1}). @@ -302,7 +297,6 @@ mod test { fn test_nested_map_type() { check( r#" - //- expect_parse_errors -module(test_nested_map_type). -type my_map() :: #{field1 := true, field2 => false}. -type my_nested_map() :: #{field1 := #{field1 => my_map()}}. @@ -321,12 +315,11 @@ mod test { fn test_type_from_spec() { check( r#" - //- expect_parse_errors //- /src/one.erl -module(one). -type my_map(X) :: #{field1 := X}. -export_type([my_map/0]). - + //- /src/two.erl -module(two). -spec foo(one:my_map(integer())) -> one:my_map(integer()). @@ -345,12 +338,11 @@ mod test { fn test_type_from_unowned_spec() { check( r#" - //- expect_parse_errors //- /src/one.erl -module(one). -type my_map(X) :: #{field1 := X}. -export_type([my_map/0]). - + //- /src/two.erl -module(two). -spec foo(one:my_map(integer())) -> one:my_map(integer()). @@ -367,7 +359,6 @@ mod test { fn test_local_type_in_function_argument() { check( r#" - //- expect_parse_errors -module(test_local_type). -type my_map() :: #{field1 := integer(), field2 => boolean()}. foo(#~ diff --git a/crates/ide_completion/src/modules.rs b/crates/ide_completion/src/modules.rs index 3823339f78..820d04cfe8 100644 --- a/crates/ide_completion/src/modules.rs +++ b/crates/ide_completion/src/modules.rs @@ -132,7 +132,6 @@ foo() -> check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). -export([ diff --git a/crates/ide_completion/src/records.rs b/crates/ide_completion/src/records.rs index d66e054423..cf8e0abc7c 100644 --- a/crates/ide_completion/src/records.rs +++ b/crates/ide_completion/src/records.rs @@ -320,7 +320,6 @@ mod test { fn test_record_name() { check( r#" - //- expect_parse_errors -module(sample). -record(this_record, {field1=1, field2=2}). -record(that_record, {}). @@ -335,7 +334,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -record(this_record, {field1=1, field2=2}). -record(that_record, {}). @@ -355,7 +353,6 @@ mod test { // Irregular names are quoted. check( r#" - //- expect_parse_errors -module(sample). -record('this.record', {field1=1, field2=2}). -record('that$record', {}). @@ -372,7 +369,6 @@ mod test { fn test_record_error_recovery() { check( r#" - //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> #rec{field1 = 1, field2~. @@ -385,7 +381,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> X#rec{field1 = 1, field2~. @@ -398,7 +393,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> case ok of @@ -410,7 +404,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> case ok of @@ -424,7 +417,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> case ok of @@ -441,7 +433,6 @@ mod test { fn test_record_name_in_function_signature() { check( r#" - //- expect_parse_errors -module(sample). -record(this_record, {field1=1, field2=2}). -record(that_record, {}). @@ -459,7 +450,6 @@ mod test { fn test_record_field_in_function_signature() { check( r#" - //- expect_parse_errors -module(sample). -record(rec, {field1, field2, other}). foo(#rec{fie~ diff --git a/crates/ide_completion/src/spec.rs b/crates/ide_completion/src/spec.rs index cc853af865..6a0061e914 100644 --- a/crates/ide_completion/src/spec.rs +++ b/crates/ide_completion/src/spec.rs @@ -109,7 +109,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). frog() -> ok. @@ -130,7 +129,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). frog(A, B) -> {A, B}. diff --git a/crates/ide_completion/src/types.rs b/crates/ide_completion/src/types.rs index e232ab2944..3800a97b5c 100644 --- a/crates/ide_completion/src/types.rs +++ b/crates/ide_completion/src/types.rs @@ -169,7 +169,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample). -type alias() :: ok. @@ -198,7 +197,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample). -type alias() :: ok. @@ -227,7 +225,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample). -spec foo() -> sample2:~. @@ -251,7 +248,6 @@ mod test { // something reasonable (show nothing) check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample). -spec foo() -> sample~:. @@ -267,7 +263,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample). -spec foo() -> sample~:. diff --git a/crates/ide_completion/src/vars.rs b/crates/ide_completion/src/vars.rs index 5544475ed3..65740d56a4 100644 --- a/crates/ide_completion/src/vars.rs +++ b/crates/ide_completion/src/vars.rs @@ -100,7 +100,6 @@ mod test { fn test_local_variables_1() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). test(AnArg1,Blah) -> @@ -118,7 +117,6 @@ mod test { fn test_local_variables_limit_to_current_function() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). another(AnArgNotMatched) -> @@ -144,7 +142,6 @@ mod test { fn test_local_variables_none_if_space() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). test(AnArg1,Blah) -> @@ -160,7 +157,6 @@ mod test { fn test_local_variables_no_duplicates() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). handle_update(Config, Contents) -> diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml index 927391ba93..babeee31b9 100644 --- a/crates/ide_db/Cargo.toml +++ b/crates/ide_db/Cargo.toml @@ -12,16 +12,15 @@ elp_eqwalizer.workspace = true elp_erlang_service.workspace = true elp_project_model.workspace = true elp_syntax.workspace = true +elp_text_edit.workspace = true elp_types_db.workspace = true hir.workspace = true anyhow.workspace = true -cov-mark.workspace = true eetf.workspace = true either.workspace = true fxhash.workspace = true indexmap.workspace = true -itertools.workspace = true lazy_static.workspace = true log.workspace = true memchr.workspace = true @@ -36,7 +35,6 @@ stdx.workspace = true strum.workspace = true strum_macros.workspace = true tempfile.workspace = true -text-size.workspace = true toml.workspace = true tracing.workspace = true diff --git a/crates/ide_db/src/diagnostic_code.rs b/crates/ide_db/src/diagnostic_code.rs index ec1e1d76cf..d3e73636bd 100644 --- a/crates/ide_db/src/diagnostic_code.rs +++ b/crates/ide_db/src/diagnostic_code.rs @@ -20,9 +20,9 @@ use serde::de; use strum::IntoEnumIterator; use strum_macros::EnumIter; -// @fb-only: use crate::meta_only::MetaOnlyDiagnosticCode; +// @fb-only -// @fb-only: pub const BASE_URL: &str = crate::meta_only::BASE_URL; +// @fb-only pub const BASE_URL: &str = "https://whatsapp.github.io/erlang-language-platform/docs"; // @oss-only #[derive(Clone, Debug, PartialEq, Eq, Hash, EnumIter)] @@ -52,7 +52,6 @@ pub enum DiagnosticCode { DependentHeader, DeprecatedFunction, UndefinedFunction, - UnavailableType, Unexpected(String), ExpressionCanBeSimplified, CannotEvaluateCTCallbacks, @@ -90,10 +89,6 @@ pub enum DiagnosticCode { NoErrorLogger, NoNoWarnSuppressions, CouldBeAStringLiteral, - ListsReverseAppend, - HirUnresolvedMacro, - HirUnresolvedInclude, - BoundVarInLhs, // Wrapper for erlang service diagnostic codes ErlangService(String), @@ -101,7 +96,7 @@ pub enum DiagnosticCode { Eqwalizer(String), // Used for ad-hoc diagnostics via lints/codemods AdHoc(String), - // @fb-only: MetaOnly(MetaOnlyDiagnosticCode), + // @fb-only } // These namespaces map the error codes returned by the Erlang Service. @@ -117,7 +112,7 @@ pub enum Namespace { Parser, EDoc, WhatsApp, - // @fb-only: MetaOnly, + // @fb-only } impl fmt::Display for Namespace { @@ -132,7 +127,7 @@ impl fmt::Display for Namespace { Namespace::Parser => "p", Namespace::EDoc => "o", Namespace::WhatsApp => "w", - // @fb-only: Namespace::MetaOnly => "meta_only", + // @fb-only }; write!(f, "{namespace}") } @@ -165,7 +160,7 @@ impl Namespace { pub fn supports_doc_path(&self) -> bool { match self { Namespace::WhatsApp => true, - // @fb-only: Namespace::MetaOnly => true, + // @fb-only _ => false, } } @@ -253,15 +248,10 @@ impl DiagnosticCode { DiagnosticCode::NoErrorLogger => "W0053".to_string(), DiagnosticCode::NoNoWarnSuppressions => "W0054".to_string(), DiagnosticCode::CouldBeAStringLiteral => "W0055".to_string(), - DiagnosticCode::ListsReverseAppend => "W0056".to_string(), - DiagnosticCode::HirUnresolvedMacro => "W0057".to_string(), - DiagnosticCode::HirUnresolvedInclude => "W0058".to_string(), - DiagnosticCode::UnavailableType => "W0059".to_string(), - DiagnosticCode::BoundVarInLhs => "W0060".to_string(), DiagnosticCode::ErlangService(c) => c.to_string(), DiagnosticCode::Eqwalizer(c) => format!("eqwalizer: {c}"), DiagnosticCode::AdHoc(c) => format!("ad-hoc: {c}"), - // @fb-only: DiagnosticCode::MetaOnly(c) => c.as_code(), + // @fb-only } } @@ -273,7 +263,6 @@ impl DiagnosticCode { DiagnosticCode::HeadMismatch => "head_mismatch".to_string(), DiagnosticCode::SyntaxError => "syntax_error".to_string(), DiagnosticCode::BoundVarInPattern => "bound_var_in_pattern".to_string(), - DiagnosticCode::BoundVarInLhs => "bound_var_in_lhs".to_string(), DiagnosticCode::ModuleMismatch => "module_mismatch".to_string(), DiagnosticCode::UnusedMacro => "unused_macro".to_string(), DiagnosticCode::UnusedRecordField => "unused_record_field".to_string(), @@ -355,15 +344,11 @@ impl DiagnosticCode { DiagnosticCode::NoErrorLogger => "no_error_logger".to_string(), DiagnosticCode::NoNoWarnSuppressions => "no_nowarn_suppressions".to_string(), DiagnosticCode::CouldBeAStringLiteral => "could_be_a_binary_string_literal".to_string(), - DiagnosticCode::ListsReverseAppend => "lists_reverse_append".to_string(), - DiagnosticCode::HirUnresolvedMacro => "hir_unresolved_macro".to_string(), - DiagnosticCode::HirUnresolvedInclude => "hir_unresolved_include".to_string(), - DiagnosticCode::UnavailableType => "unavailable_type".to_string(), DiagnosticCode::ErlangService(c) => c.to_string(), DiagnosticCode::Eqwalizer(c) => c.to_string(), DiagnosticCode::AdHoc(c) => format!("ad-hoc: {c}"), - // @fb-only: DiagnosticCode::MetaOnly(c) => c.as_label(), + // @fb-only } } @@ -374,7 +359,7 @@ impl DiagnosticCode { pub fn maybe_from_string(s: &str) -> Option { DIAGNOSTIC_CODE_LOOKUPS .get(s).cloned() - // @fb-only: .or_else(|| MetaOnlyDiagnosticCode::from_str(s).ok().map(DiagnosticCode::MetaOnly)) + // @fb-only .or_else( || // Look for ErlangService and AdHoc if let Some(code) = Self::is_adhoc(s) { @@ -391,7 +376,7 @@ impl DiagnosticCode { match self { DiagnosticCode::DefaultCodeForEnumIter => None, DiagnosticCode::AdHoc(_) => None, - // @fb-only: DiagnosticCode::MetaOnly(_) => Some(Namespace::MetaOnly), + // @fb-only DiagnosticCode::ErlangService(code) => Namespace::from_str(code).ok(), _ => Namespace::from_str(&self.as_code()).ok(), } @@ -400,7 +385,7 @@ impl DiagnosticCode { pub fn supports_doc_path(&self) -> bool { match self { DiagnosticCode::DefaultCodeForEnumIter => false, - // @fb-only: DiagnosticCode::MetaOnly(MetaOnlyDiagnosticCode::DefaultCodeForEnumIter) => false, + // @fb-only _ => true, } } @@ -489,7 +474,6 @@ impl DiagnosticCode { DiagnosticCode::ModuleMismatch => false, DiagnosticCode::UnusedInclude => false, DiagnosticCode::BoundVarInPattern => false, - DiagnosticCode::BoundVarInLhs => false, DiagnosticCode::UnusedMacro => false, DiagnosticCode::UnusedRecordField => false, DiagnosticCode::MutableVarBug => false, @@ -504,7 +488,6 @@ impl DiagnosticCode { DiagnosticCode::DependentHeader => false, DiagnosticCode::DeprecatedFunction => false, DiagnosticCode::UndefinedFunction => false, - DiagnosticCode::UnavailableType => false, DiagnosticCode::Unexpected(_) => false, DiagnosticCode::ExpressionCanBeSimplified => false, DiagnosticCode::UnnecessaryFlatteningToFindFlatLength => false, @@ -537,15 +520,12 @@ impl DiagnosticCode { DiagnosticCode::NoCatch => false, DiagnosticCode::NoErrorLogger => false, DiagnosticCode::NoNoWarnSuppressions => false, - DiagnosticCode::ListsReverseAppend => false, - DiagnosticCode::HirUnresolvedMacro => false, - DiagnosticCode::HirUnresolvedInclude => false, DiagnosticCode::BinaryStringToSigil => false, DiagnosticCode::ErlangService(_) => false, DiagnosticCode::Eqwalizer(_) => false, DiagnosticCode::AdHoc(_) => false, - // @fb-only: DiagnosticCode::MetaOnly(code) => code.allows_fixme_comment(), + // @fb-only } } diff --git a/crates/ide_db/src/eqwalizer.rs b/crates/ide_db/src/eqwalizer.rs index fca577bb21..4deed79778 100644 --- a/crates/ide_db/src/eqwalizer.rs +++ b/crates/ide_db/src/eqwalizer.rs @@ -12,6 +12,7 @@ use std::sync::Arc; use elp_base_db::FileId; use elp_base_db::FileRange; +use elp_base_db::FileSource; use elp_base_db::ModuleName; use elp_base_db::ProjectId; use elp_base_db::SourceDatabase; @@ -88,7 +89,7 @@ pub trait EqwalizerDatabase: fn types_for_file(&self, file_id: FileId) -> Option>>; fn has_eqwalizer_module_marker(&self, file_id: FileId) -> bool; fn has_eqwalizer_ignore_marker(&self, file_id: FileId) -> bool; - fn is_eqwalizer_enabled(&self, file_id: FileId) -> bool; + fn is_eqwalizer_enabled(&self, file_id: FileId, include_tests: bool) -> bool; } pub fn eqwalizer_diagnostics_by_project( @@ -113,7 +114,7 @@ fn type_at_position( db: &dyn EqwalizerDatabase, range: FileRange, ) -> Option> { - if !db.is_eqwalizer_enabled(range.file_id) { + if !db.is_eqwalizer_enabled(range.file_id, false) { return None; } let project_id = db.file_app_data(range.file_id)?.project_id; @@ -148,7 +149,7 @@ fn type_at_position( } fn types_for_file(db: &dyn EqwalizerDatabase, file_id: FileId) -> Option>> { - if !db.is_eqwalizer_enabled(file_id) { + if !db.is_eqwalizer_enabled(file_id, false) { return None; } let project_id = db.file_app_data(file_id)?.project_id; @@ -161,7 +162,7 @@ fn types_for_file(db: &dyn EqwalizerDatabase, file_id: FileId) -> Option bool { +fn is_eqwalizer_enabled(db: &dyn EqwalizerDatabase, file_id: FileId, include_tests: bool) -> bool { if !otp_supported_by_eqwalizer() { return false; } @@ -177,8 +178,11 @@ fn is_eqwalizer_enabled(db: &dyn EqwalizerDatabase, file_id: FileId) -> bool { let project = db.project_data(project_id); let eqwalizer_config = &project.eqwalizer_config; let module_index = db.module_index(project_id); + let is_src = module_index.file_source_for_file(file_id) == Some(FileSource::Src); + let is_test_opted_in = db.is_test_suite_or_test_helper(file_id) == Some(true) && include_tests; let global_opt_in = eqwalizer_config.enable_all; - let opt_in = global_opt_in || db.has_eqwalizer_module_marker(file_id); + let opt_in = + (global_opt_in && (is_src || is_test_opted_in)) || db.has_eqwalizer_module_marker(file_id); let ignored_in_config = if let Some(module_name) = module_index.module_for_file(file_id) { eqwalizer_config .ignore_modules_compiled_patterns diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs index 038b41f0be..cad66d9e48 100644 --- a/crates/ide_db/src/helpers.rs +++ b/crates/ide_db/src/helpers.rs @@ -15,9 +15,9 @@ use elp_syntax::SourceFile; use elp_syntax::SyntaxKind; use elp_syntax::SyntaxNode; use elp_syntax::SyntaxToken; -use elp_syntax::TextSize; use elp_syntax::TokenAtOffset; use elp_syntax::ast; +use elp_text_edit::TextSize; use hir::FormList; #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -43,22 +43,11 @@ pub fn pick_best_token( tokens.max_by_key(move |t| f(t.kind())) } -/// Given a syntax node, check it it is immediately enclosed in a call, -/// which can represent a function call or a type. -/// For a remote call, the node can be the module or the function name. -/// In the former case, there is an extra level of nesting, so we need -/// to check up to 3 steps up pub fn get_call(syntax: &SyntaxNode) -> Option { - ast::Call::cast(syntax.parent()?) - .or_else(|| ast::Call::cast(syntax.parent()?.parent()?)) - .or_else(|| ast::Call::cast(syntax.parent()?.parent()?.parent()?)) -} - -pub fn get_external_fun(syntax: &SyntaxNode) -> Option { - if let Some(external_fun) = ast::ExternalFun::cast(syntax.parent()?) { - Some(external_fun) + if let Some(call) = ast::Call::cast(syntax.parent()?) { + Some(call) } else { - ast::ExternalFun::cast(syntax.parent()?.parent()?) + ast::Call::cast(syntax.parent()?.parent()?) } } diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index aecfd86473..0240d8498d 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs @@ -57,17 +57,15 @@ pub mod docs; pub mod eqwalizer; mod erl_ast; mod line_index; -// @fb-only: pub mod meta_only; +// @fb-only pub mod metadata; mod search; -pub mod text_edit; // --------------------------------------------------------------------- pub mod assists; pub mod helpers; pub mod rename; pub mod source_change; -pub mod tree_diff; pub use defs::ReferenceClass; pub use defs::ReferenceType; @@ -385,7 +383,7 @@ impl TypedSemantic for RootDatabase { let project_id = app_data.project_id; - let eqwalizer_enabled = self.is_eqwalizer_enabled(file_id); + let eqwalizer_enabled = self.is_eqwalizer_enabled(file_id, false); if !eqwalizer_enabled { return Some(vec![]); } @@ -421,8 +419,8 @@ impl TypedSemantic for RootDatabase { mod tests { use elp_base_db::SourceDatabase; use elp_base_db::fixture::WithFixture; + use elp_text_edit::TextRange; - use super::text_edit::TextRange; use crate::RootDatabase; #[test] @@ -448,17 +446,4 @@ mod tests { let position = fixture.position(); debug_assert_eq!(db.clamp_offset(position.file_id, 2000.into()), 15.into()) } - - #[test] - #[should_panic(expected = "Fixture validation failed: syntax errors found in test fixture")] - fn validate_fixture_with_parse_error() { - let fixture = r#" -//- /src/test.erl --module(test). -foo( -> ok. -"#; - - let (db, fixture) = RootDatabase::with_fixture(fixture); - fixture.validate(&db); - } } diff --git a/crates/ide_db/src/rename.rs b/crates/ide_db/src/rename.rs index bd5a49f8cf..c25ee41e2a 100644 --- a/crates/ide_db/src/rename.rs +++ b/crates/ide_db/src/rename.rs @@ -15,24 +15,19 @@ use std::fmt; use std::iter::once; -use elp_base_db::AnchoredPathBuf; use elp_base_db::FileId; use elp_base_db::FileRange; -use elp_base_db::ModuleName; use elp_syntax::AstNode; use elp_syntax::ast; use elp_syntax::ast::in_erlang_module; +use elp_text_edit::TextEdit; use hir::InFile; use hir::Semantic; use crate::SymbolDefinition; use crate::helpers::get_call; -use crate::helpers::get_external_fun; use crate::search::NameLike; -use crate::source_change::FileSystemEdit; use crate::source_change::SourceChange; -use crate::text_edit::TextEdit; -use crate::text_edit::TextEditBuilder; pub type RenameResult = Result; @@ -84,45 +79,6 @@ pub fn is_valid_function_name(new_name: &String) -> bool { } } -// Delegate checking macro name validity to the parser -// Macros can be either atoms or variables -pub fn is_valid_macro_name(new_name: &String) -> bool { - let parse = ast::SourceFile::parse_text(format!("-define({new_name}, value).").as_str()); - matches!( - parse.tree().forms().next(), - Some(ast::Form::PreprocessorDirective( - ast::PreprocessorDirective::PpDefine(_) - )) - ) -} - -// Delegate checking type name validity to the parser -pub fn is_valid_type_name(new_name: &String) -> bool { - let parse = ast::SourceFile::parse_text(format!("-type {new_name}() :: ok.").as_str()); - // Check that we got a TypeAlias form - if let Some(ast::Form::TypeAlias(type_alias)) = parse.tree().forms().next() { - // Check that the name is an atom (not a variable) - if let Some(type_name) = type_alias.name() - && let Some(ast::Name::Atom(_)) = type_name.name() - { - return true; - } - } - false -} - -// Delegate checking module name validity to the parser -pub fn is_valid_module_name(new_name: &String) -> bool { - let parse = ast::SourceFile::parse_text(format!("-module({}).", new_name).as_str()); - match parse.tree().forms().next() { - Some(ast::Form::ModuleAttribute(ma)) => match ma.name() { - Some(ast::Name::Atom(atom)) => atom.syntax().text().to_string() == *new_name, - _ => false, - }, - _ => false, - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SafetyChecks { Yes, @@ -139,10 +95,7 @@ impl SymbolDefinition { ) -> RenameResult { match self.clone() { SymbolDefinition::Module(_) => { - if safety_check == SafetyChecks::Yes && !is_valid_module_name(new_name) { - rename_error!("Invalid new module name: '{}'", new_name); - } - self.rename_reference(sema, new_name, parens_needed_in_context, safety_check) + rename_error!("Cannot rename module") } SymbolDefinition::Function(fun) => { if safety_check == SafetyChecks::Yes && !is_valid_function_name(new_name) { @@ -164,58 +117,14 @@ impl SymbolDefinition { SymbolDefinition::RecordField(_) => { rename_error!("Cannot rename record field") } - SymbolDefinition::Type(type_alias) => { - if safety_check == SafetyChecks::Yes && !is_valid_type_name(new_name) { - rename_error!("Invalid new type name: '{}'", new_name); - } - - let arity = type_alias.name().arity(); - if safety_check == SafetyChecks::Yes { - // Check safety in the file where the type is defined - if !is_safe_type(sema, type_alias.file.file_id, new_name, arity) { - rename_error!("Type '{}/{}' already in scope", new_name, arity); - } - - // Also check safety in all files where the type is used - let usages = self.clone().usages(sema).all(); - for (file_id, _refs) in usages.iter() { - if file_id != type_alias.file.file_id - && !is_safe_type(sema, file_id, new_name, arity) - { - rename_error!("Type '{}/{}' already in scope", new_name, arity); - } - } - } - - self.rename_reference(sema, new_name, parens_needed_in_context, safety_check) + SymbolDefinition::Type(_) => { + rename_error!("Cannot rename type") } SymbolDefinition::Callback(_) => { rename_error!("Cannot rename callback") } - SymbolDefinition::Define(define) => { - if safety_check == SafetyChecks::Yes && !is_valid_macro_name(new_name) { - rename_error!("Invalid new macro name: '{}'", new_name); - } - - let arity = define.define.name.arity(); - if safety_check == SafetyChecks::Yes { - // Check safety in the file where the macro is defined - if !is_safe_macro(sema, define.file.file_id, new_name, arity) { - rename_error!("Macro '{}' already in scope", new_name); - } - - // Also check safety in all files where the macro is used - let usages = self.clone().usages(sema).all(); - for (file_id, _refs) in usages.iter() { - if file_id != define.file.file_id - && !is_safe_macro(sema, file_id, new_name, arity) - { - rename_error!("Macro '{}' already in scope", new_name); - } - } - } - - self.rename_reference(sema, new_name, parens_needed_in_context, safety_check) + SymbolDefinition::Define(_) => { + rename_error!("Cannot rename define") } SymbolDefinition::Header(_) => { rename_error!("Cannot rename header") @@ -242,27 +151,6 @@ impl SymbolDefinition { range, }) } - SymbolDefinition::Define(d) => { - // Get the macro definition location - let source = d.source(sema.db.upcast()); - if let Some(name) = source.name() { - let range = name.syntax().text_range(); - Some(FileRange { - file_id: d.file.file_id, - range, - }) - } else { - None - } - } - SymbolDefinition::Type(t) => { - // Get the type definition location - let range = t.name_range(sema.db.upcast())?; - Some(FileRange { - file_id: t.file.file_id, - range, - }) - } _ => None, } } @@ -327,40 +215,6 @@ impl SymbolDefinition { ); Ok(source_change) } - SymbolDefinition::Define(_define) => { - // Find all usages of the macro - let usages = self.clone().usages(sema).all(); - - // Also need to rename the definition itself - // Get the macro definition location - let (file_id, def_edit) = source_edit_from_def(sema, self.clone(), new_name)?; - source_change.insert_source_edit(file_id, def_edit); - - source_edit_from_usages( - &mut source_change, - usages.iter().collect(), - new_name, - parens_needed_in_context, - ); - Ok(source_change) - } - SymbolDefinition::Type(_type_alias) => { - // Find all usages of the type - let usages = self.clone().usages(sema).all(); - - // Also need to rename the definition itself - // Get the type definition location - let (file_id, def_edit) = source_edit_from_def(sema, self.clone(), new_name)?; - source_change.insert_source_edit(file_id, def_edit); - - source_edit_from_usages( - &mut source_change, - usages.iter().collect(), - new_name, - parens_needed_in_context, - ); - Ok(source_change) - } SymbolDefinition::Var(var) => { let usages = sema .find_local_usages_ast(InFile { @@ -395,7 +249,6 @@ impl SymbolDefinition { ); Ok(source_change) } - SymbolDefinition::Module(_module) => self.rename_module(sema, new_name, safety_check), // Note: This is basically an internal error, this function is called from // SymbolDefinition::rename which already weeds them out _ => { @@ -403,184 +256,6 @@ impl SymbolDefinition { } } } - - fn rename_module( - &self, - sema: &Semantic, - new_name: &str, - safety_check: SafetyChecks, - ) -> RenameResult { - let file_id = self.file().file_id; - if let Some(project_id) = sema.db.file_project_id(file_id) { - let module_index = sema.db.module_index(project_id); - if safety_check == SafetyChecks::Yes { - let new_name_module = ModuleName::new(new_name); - if module_index - .all_modules() - .iter() - .any(|name| name == &new_name_module) - { - rename_error!("module '{}' already exists", new_name); - } - } - - let mut source_change = SourceChange::default(); - // Step 1, rename all references - let usages = self.clone().usages(sema).all(); - let mut renamed_module_edit: TextEdit = TextEdit::default(); - rename_remote_module_call_refs( - usages, - file_id, - new_name, - &mut source_change, - &mut renamed_module_edit, - ); - - // Step 2: Rename the module attribute in the module being renamed - let form_list = sema.form_list(file_id); - if let Some(module_attribute) = form_list.module_attribute() { - let ast = module_attribute.form_id.get_ast(sema.db, file_id); - if let Some(name) = ast.name() { - let range = name.syntax().text_range(); - let mut builder = TextEdit::builder(); - builder.replace(range, new_name.to_string()); - renamed_module_edit - .union(builder.finish()) - .expect("Could not combine TextEdits"); - } - } - - let anchor = file_id; - let path = format!("{new_name}.erl"); - let dst = AnchoredPathBuf { anchor, path }; - source_change.insert_new_source_edit(dst.clone().into(), renamed_module_edit); - source_change.push_file_system_edit(FileSystemEdit::MoveFile { src: anchor, dst }); - Ok(source_change) - } else { - rename_error!( - "Could not find project for '{:?}'", - self.file().name(sema.db.upcast()) - ) - } - } -} - -fn rename_remote_module_call_refs( - usages: crate::UsageSearchResult, - file_id: FileId, - new_name: &str, - source_change: &mut SourceChange, - renamed_module_edit: &mut TextEdit, -) { - usages.iter().for_each(|(usage_file_id, refs)| { - if let Some(edit) = rename_module_in_refs(refs, new_name) { - if usage_file_id == file_id { - renamed_module_edit - .union(edit) - .expect("Could not combine TextEdits"); - } else { - source_change.insert_source_edit(usage_file_id, edit); - } - }; - }); -} - -fn rename_module_in_refs(refs: &[NameLike], new_name: &str) -> Option { - let mut builder = TextEdit::builder(); - for usage in refs { - // Note: we cannot blindly replace all occurrences of an - // atom that happens to be a module name - // We will flesh out other usages as we need them - let _ = rename_call_module_in_ref(usage, &mut builder, new_name); - let _ = rename_external_fun_module_in_ref(usage, &mut builder, new_name); - } - Some(builder.finish()) -} - -fn rename_call_module_in_ref( - usage: &NameLike, - builder: &mut TextEditBuilder, - new_name: &str, -) -> Option<()> { - let call = get_call(usage.syntax())?; - // We can only rename an atom usage - let usage_atom = match usage { - NameLike::Name(ast::Name::Atom(atom)) => atom, - _ => return Some(()), - }; - - // First check if this is the module part of a remote call (e.g., module:function()) - if let Some(ast::Expr::Remote(remote)) = call.expr() - && let Some(module) = remote.module() - && let Some(ast::ExprMax::Atom(mod_atom)) = module.module() - && mod_atom.syntax() == usage_atom.syntax() - { - builder.replace(usage_atom.syntax().text_range(), new_name.to_string()); - return Some(()); - } - - // Check if this is a known function call that takes a module as an argument - // Extract function name and optional module name based on call type - let (module_name, function_name) = match call.expr()? { - ast::Expr::Remote(remote) => { - let module = remote.module()?; - let mod_atom = match module.module()? { - ast::ExprMax::Atom(atom) => atom, - _ => return Some(()), - }; - let fun_atom = match remote.fun()? { - ast::ExprMax::Atom(atom) => atom, - _ => return Some(()), - }; - (Some(mod_atom.text()?), fun_atom.text()?) - } - ast::Expr::ExprMax(ast::ExprMax::Atom(fun_atom)) => (None, fun_atom.text()?), - _ => return Some(()), - }; - - let args = call.args()?; - let args_vec: Vec<_> = args.args().collect(); - let arity = args_vec.len(); - let pattern_key = (module_name.as_deref(), function_name.as_str(), arity); - - // Use combined patterns that merge dynamic call patterns and module argument patterns - let combined_patterns = hir::sema::to_def::get_module_arg_patterns(); - if let Some(pattern) = combined_patterns.get(&pattern_key) - && let Some(arg) = args_vec.get(pattern.index) - { - match arg { - ast::Expr::ExprMax(ast::ExprMax::Atom(arg_atom)) - if pattern.accepts_atom() && arg_atom.syntax() == usage_atom.syntax() => - { - builder.replace(usage_atom.syntax().text_range(), new_name.to_string()); - } - ast::Expr::ExprMax(ast::ExprMax::List(list)) if pattern.accepts_list() => { - // Handle list of modules (e.g., meck:new([mod1, mod2], Options)) - for expr in list.exprs() { - if let ast::Expr::ExprMax(ast::ExprMax::Atom(list_atom)) = expr - && list_atom.syntax() == usage_atom.syntax() - { - builder.replace(usage_atom.syntax().text_range(), new_name.to_string()); - break; - } - } - } - _ => {} - } - } - - Some(()) -} - -fn rename_external_fun_module_in_ref( - usage: &NameLike, - builder: &mut TextEditBuilder, - new_name: &str, -) -> Option<()> { - let external_fun = get_external_fun(usage.syntax())?; - let module = external_fun.module()?; - builder.replace(module.name()?.syntax().text_range(), new_name.to_string()); - Some(()) } fn source_edit_from_usages( @@ -713,32 +388,6 @@ pub fn is_safe_function(sema: &Semantic, file_id: FileId, new_name: &str, arity: scope_ok && !in_erlang_module(new_name, arity as usize) } -/// Check that the new macro name is not already defined in scope. -/// Macros are identified by both name and arity, similar to functions. -pub fn is_safe_macro(sema: &Semantic, file_id: FileId, new_name: &str, arity: Option) -> bool { - sema.db - .def_map(file_id) - .get_macros() - .iter() - .all(|(name, _)| { - // A macro is considered different if either the name or arity differs - *name.name().to_string() != *new_name || name.arity() != arity - }) -} - -/// Check that the new type name is not already defined in scope. -/// Types are identified by both name and arity, similar to functions and macros. -pub fn is_safe_type(sema: &Semantic, file_id: FileId, new_name: &str, arity: u32) -> bool { - sema.db - .def_map(file_id) - .get_types() - .iter() - .all(|(name, _)| { - // A type is considered different if either the name or arity differs - *name.name().to_string() != *new_name || name.arity() != arity - }) -} - /// Check that the new function name is not in scope already in the /// module via an explicit import. pub fn is_safe_remote_function( diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index 1e66598359..20b4f050b4 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs @@ -325,7 +325,7 @@ impl<'a> FindUsages<'a> { /// Represents possible ast reference points - /// a string for header, or ast::Name for everything else -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub enum NameLike { Name(ast::Name), String(ast::String), diff --git a/crates/ide_db/src/source_change.rs b/crates/ide_db/src/source_change.rs index 60b62279fe..bb64431772 100644 --- a/crates/ide_db/src/source_change.rs +++ b/crates/ide_db/src/source_change.rs @@ -20,46 +20,19 @@ use std::mem; use elp_base_db::AnchoredPathBuf; use elp_base_db::FileId; use elp_syntax::SyntaxNode; -use elp_syntax::TextRange; -use elp_syntax::TextSize; +use elp_syntax::algo; +use elp_text_edit::TextEdit; +use elp_text_edit::TextEditBuilder; +use elp_text_edit::TextRange; +use elp_text_edit::TextSize; use fxhash::FxHashMap; use stdx::never; use crate::helpers::SnippetCap; -use crate::text_edit::TextEdit; -use crate::text_edit::TextEditBuilder; -use crate::tree_diff::diff; - -#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug)] -pub struct HashableAnchoredPathBuf { - /// File that this path is relative to. - pub anchor: FileId, - /// Path relative to `anchor`'s containing directory. - pub path: String, -} - -impl From for HashableAnchoredPathBuf { - fn from(value: AnchoredPathBuf) -> Self { - HashableAnchoredPathBuf { - anchor: value.anchor, - path: value.path, - } - } -} - -impl From for AnchoredPathBuf { - fn from(value: HashableAnchoredPathBuf) -> Self { - AnchoredPathBuf { - anchor: value.anchor, - path: value.path, - } - } -} #[derive(Default, Debug, Clone)] pub struct SourceChange { pub source_file_edits: FxHashMap, - pub new_file_edits: FxHashMap, pub file_system_edits: Vec, pub is_snippet: bool, } @@ -73,7 +46,6 @@ impl SourceChange { ) -> Self { SourceChange { source_file_edits, - new_file_edits: FxHashMap::default(), file_system_edits, is_snippet: false, } @@ -102,22 +74,6 @@ impl SourceChange { } } - /// Inserts a [`TextEdit`] for the given [`AnchoredPathBuf`]. This properly handles merging existing - /// edits for a file if some already exist. - pub fn insert_new_source_edit(&mut self, file_id: HashableAnchoredPathBuf, edit: TextEdit) { - match self.new_file_edits.entry(file_id) { - Entry::Occupied(mut entry) => { - never!( - entry.get_mut().union(edit).is_err(), - "overlapping edits for same file" - ); - } - Entry::Vacant(entry) => { - entry.insert(edit); - } - } - } - pub fn push_file_system_edit(&mut self, edit: FileSystemEdit) { self.file_system_edits.push(edit); } @@ -129,15 +85,12 @@ impl SourceChange { pub fn merge(mut self, other: SourceChange) -> SourceChange { self.extend(other.source_file_edits); self.extend(other.file_system_edits); - self.extend(other.new_file_edits); self.is_snippet |= other.is_snippet; self } pub fn is_empty(&self) -> bool { - self.source_file_edits.is_empty() - && self.file_system_edits.is_empty() - && self.new_file_edits.is_empty() + self.source_file_edits.is_empty() && self.file_system_edits.is_empty() } pub fn text_range(&self, file_id: FileId) -> Option { @@ -163,18 +116,10 @@ impl Extend for SourceChange { } } -impl Extend<(HashableAnchoredPathBuf, TextEdit)> for SourceChange { - fn extend>(&mut self, iter: T) { - iter.into_iter() - .for_each(|(file_id, edit)| self.insert_new_source_edit(file_id, edit)); - } -} - impl From> for SourceChange { fn from(source_file_edits: FxHashMap) -> SourceChange { SourceChange { source_file_edits, - new_file_edits: FxHashMap::default(), file_system_edits: Vec::new(), is_snippet: false, } @@ -226,7 +171,7 @@ impl SourceChangeBuilder { fn commit(&mut self) { if let Some(tm) = self.mutated_tree.take() { - diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit) + algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit) } let edit = mem::take(&mut self.edit).finish(); @@ -320,7 +265,6 @@ impl From for SourceChange { fn from(edit: FileSystemEdit) -> SourceChange { SourceChange { source_file_edits: Default::default(), - new_file_edits: Default::default(), file_system_edits: vec![edit], is_snippet: false, } diff --git a/crates/ide_db/src/tree_diff.rs b/crates/ide_db/src/tree_diff.rs deleted file mode 100644 index 5bca5c2ec2..0000000000 --- a/crates/ide_db/src/tree_diff.rs +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is dual-licensed under either the MIT license found in the - * LICENSE-MIT file in the root directory of this source tree or the Apache - * License, Version 2.0 found in the LICENSE-APACHE file in the root directory - * of this source tree. You may select, at your option, one of the - * above-listed licenses. - */ - -//! Basic tree diffing functionality. - -use std::hash::BuildHasherDefault; - -use elp_syntax::NodeOrToken; -use elp_syntax::SyntaxElement; -use elp_syntax::SyntaxNode; -use fxhash::FxHashMap; -use indexmap::IndexMap; - -use crate::text_edit::TextEditBuilder; - -type FxIndexMap = IndexMap>; - -#[derive(Debug, Hash, PartialEq, Eq)] -enum TreeDiffInsertPos { - After(SyntaxElement), - AsFirstChild(SyntaxElement), -} - -#[derive(Debug)] -pub struct TreeDiff { - replacements: FxHashMap, - deletions: Vec, - // the vec as well as the indexmap are both here to preserve order - insertions: FxIndexMap>, -} - -impl TreeDiff { - pub fn into_text_edit(&self, builder: &mut TextEditBuilder) { - let _p = tracing::info_span!("into_text_edit").entered(); - - for (anchor, to) in self.insertions.iter() { - let offset = match anchor { - TreeDiffInsertPos::After(it) => it.text_range().end(), - TreeDiffInsertPos::AsFirstChild(it) => it.text_range().start(), - }; - to.iter() - .for_each(|to| builder.insert(offset, to.to_string())); - } - for (from, to) in self.replacements.iter() { - builder.replace(from.text_range(), to.to_string()) - } - for text_range in self.deletions.iter().map(SyntaxElement::text_range) { - builder.delete(text_range); - } - } - - pub fn is_empty(&self) -> bool { - self.replacements.is_empty() && self.deletions.is_empty() && self.insertions.is_empty() - } -} - -/// Finds a (potentially minimal) diff, which, applied to `from`, will result in `to`. -/// -/// Specifically, returns a structure that consists of a replacements, insertions and deletions -/// such that applying this map on `from` will result in `to`. -/// -/// This function tries to find a fine-grained diff. -pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { - let _p = tracing::info_span!("diff").entered(); - - let mut diff = TreeDiff { - replacements: FxHashMap::default(), - insertions: FxIndexMap::default(), - deletions: Vec::new(), - }; - let (from, to) = (from.clone().into(), to.clone().into()); - - if !syntax_element_eq(&from, &to) { - go(&mut diff, from, to); - } - return diff; - - fn syntax_element_eq(lhs: &SyntaxElement, rhs: &SyntaxElement) -> bool { - lhs.kind() == rhs.kind() - && lhs.text_range().len() == rhs.text_range().len() - && match (&lhs, &rhs) { - (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => { - lhs == rhs || lhs.text() == rhs.text() - } - (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(), - _ => false, - } - } - - // FIXME: this is horribly inefficient. I bet there's a cool algorithm to diff trees properly. - fn go(diff: &mut TreeDiff, lhs: SyntaxElement, rhs: SyntaxElement) { - let (lhs, rhs) = match lhs.as_node().zip(rhs.as_node()) { - Some((lhs, rhs)) => (lhs, rhs), - _ => { - cov_mark::hit!(diff_node_token_replace); - diff.replacements.insert(lhs, rhs); - return; - } - }; - - let mut look_ahead_scratch = Vec::default(); - - let mut rhs_children = rhs.children_with_tokens(); - let mut lhs_children = lhs.children_with_tokens(); - let mut last_lhs = None; - loop { - let lhs_child = lhs_children.next(); - match (lhs_child.clone(), rhs_children.next()) { - (None, None) => break, - (None, Some(element)) => { - let insert_pos = match last_lhs.clone() { - Some(prev) => { - cov_mark::hit!(diff_insert); - TreeDiffInsertPos::After(prev) - } - // first iteration, insert into out parent as the first child - None => { - cov_mark::hit!(diff_insert_as_first_child); - TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) - } - }; - diff.insertions.entry(insert_pos).or_default().push(element); - } - (Some(element), None) => { - cov_mark::hit!(diff_delete); - diff.deletions.push(element); - } - (Some(ref lhs_ele), Some(ref rhs_ele)) if syntax_element_eq(lhs_ele, rhs_ele) => {} - (Some(lhs_ele), Some(rhs_ele)) => { - // nodes differ, look for lhs_ele in rhs, if its found we can mark everything up - // until that element as insertions. This is important to keep the diff minimal - // in regards to insertions that have been actually done, this is important for - // use insertions as we do not want to replace the entire module node. - look_ahead_scratch.push(rhs_ele.clone()); - let mut rhs_children_clone = rhs_children.clone(); - let mut insert = false; - for rhs_child in rhs_children_clone.by_ref() { - if syntax_element_eq(&lhs_ele, &rhs_child) { - cov_mark::hit!(diff_insertions); - insert = true; - break; - } else { - look_ahead_scratch.push(rhs_child); - } - } - let drain = look_ahead_scratch.drain(..); - if insert { - let insert_pos = if let Some(prev) = last_lhs.clone().filter(|_| insert) { - TreeDiffInsertPos::After(prev) - } else { - cov_mark::hit!(insert_first_child); - TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) - }; - - diff.insertions.entry(insert_pos).or_default().extend(drain); - rhs_children = rhs_children_clone; - } else { - go(diff, lhs_ele, rhs_ele) - } - } - } - last_lhs = lhs_child.or(last_lhs); - } - } -} - -#[cfg(test)] -mod tests { - use elp_syntax::AstNode; - use elp_syntax::SourceFile; - use elp_syntax::SyntaxElement; - use elp_syntax::SyntaxKind; - use expect_test::Expect; - use expect_test::expect; - use itertools::Itertools; - - use crate::text_edit::TextEdit; - - #[test] - fn replace_node_token() { - cov_mark::check!(diff_node_token_replace); - check_diff( - r#"-module(foo)."#, - r#"ident"#, - expect![[r#" - insertions: - - - - replacements: - - Line 0: Token(ANON_DASH@0..1 "-") -> ident - - deletions: - - Line 1: module - Line 1: ( - Line 1: foo - Line 1: ) - Line 1: . - "#]], - ); - } - - #[test] - fn replace_parent() { - cov_mark::check!(diff_node_token_replace); - check_diff( - r#""#, - r#"-module(foo)."#, - expect![[r#" - insertions: - - - - replacements: - - Line 0: Token(SOURCE_FILE@0..0 "") -> -module(foo). - - deletions: - - - "#]], - ); - } - - #[test] - fn insert_last() { - cov_mark::check!(diff_insert); - check_diff( - r#" --module(foo). --use(foo). --use(bar)."#, - r#" --module(foo). --use(foo). --use(bar). --use(baz)."#, - expect![[r#" - insertions: - - Line 3: After(Node(WILD_ATTRIBUTE@26..36)) - -> "\n" - -> -use(baz). - - replacements: - - - - deletions: - - - "#]], - ); - } - - #[test] - fn insert_middle() { - check_diff( - r#" --module(foo). --use(foo). --use(bar)."#, - r#" --module(foo). --use(foo). --use(baz). --use(bar)."#, - expect![[r#" - insertions: - - Line 3: After(Token(WHITESPACE@25..26 "\n")) - -> -use(baz). - -> "\n" - - replacements: - - - - deletions: - - - "#]], - ) - } - - #[test] - fn insert_first() { - check_diff( - r#" --use(bar). --use(baz)."#, - r#" --export([foo/0]). --use(bar). --use(baz)."#, - expect![[r#" - insertions: - - Line 0: After(Token(WHITESPACE@0..1 "\n")) - -> -export([foo/0]). - -> "\n" - - replacements: - - - - deletions: - - - "#]], - ) - } - - #[test] - fn first_child_insertion() { - // cov_mark::check!(insert_first_child); - check_diff( - r#" -main() -> - ok."#, - r#" --module(foo). - -main() -> - ok."#, - expect![[r#" - insertions: - - Line 0: After(Token(WHITESPACE@0..1 "\n")) - -> -module(foo). - -> "\n\n" - - replacements: - - - - deletions: - - - "#]], - ); - } - - #[test] - fn delete_last() { - cov_mark::check!(diff_delete); - check_diff( - r#"-module(foo). - -bar([baz])."#, - r#"-module(foo)."#, - expect![[r#" - insertions: - - - - replacements: - - - - deletions: - - Line 1: "\n " - Line 2: -bar([baz]). - "#]], - ); - } - - #[test] - fn delete_middle() { - // cov_mark::check!(diff_insertions); - check_diff( - r#" --export([foo/0,bar/1]). --bar(aaa). - --foo(bbb). -"#, - r#" --export([foo/0,bar/1]). - --foo(bbb). -"#, - expect![[r#" - insertions: - - Line 1: After(Node(EXPORT_ATTRIBUTE@1..24)) - -> "\n\n" - -> -foo(bbb). - - replacements: - - - - deletions: - - Line 2: -bar(aaa). - Line 3: "\n\n" - Line 4: -foo(bbb). - Line 5: "\n" - "#]], - ) - } - - #[test] - fn delete_first() { - check_diff( - r#" --export([foo/0,bar/1]). - --foo(bbb). -"#, - r#" --foo(bbb). -"#, - expect![[r#" - insertions: - - - - replacements: - - Line 1: Token(ANON_DASH@1..2 "-") -> -foo - Line 2: Token(ANON_EXPORT@2..8 "export") -> (bbb) - Line 2: Token(ANON_LPAREN@8..9 "(") -> . - Line 2: Token(WHITESPACE@24..26 "\n\n") -> "\n" - - deletions: - - Line 2: [ - Line 2: foo/0 - Line 2: , - Line 2: bar/1 - Line 2: ] - Line 2: ) - Line 2: . - Line 3: -foo(bbb). - Line 4: "\n" - "#]], - ) - } - - fn check_diff(from: &str, to: &str, expected_diff: Expect) { - let from_node = SourceFile::parse_text(from).tree().syntax().clone(); - let to_node = SourceFile::parse_text(to).tree().syntax().clone(); - let diff = super::diff(&from_node, &to_node); - - let line_number = - |syn: &SyntaxElement| from[..syn.text_range().start().into()].lines().count(); - - let fmt_syntax = |syn: &SyntaxElement| match syn.kind() { - SyntaxKind::WHITESPACE => format!("{:?}", syn.to_string()), - _ => format!("{syn}"), - }; - - let insertions = - diff.insertions - .iter() - .format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> { - f(&format!( - "Line {}: {:?}\n-> {}", - line_number(match k { - super::TreeDiffInsertPos::After(syn) => syn, - super::TreeDiffInsertPos::AsFirstChild(syn) => syn, - }), - k, - v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v))) - )) - }); - - let replacements = diff - .replacements - .iter() - .sorted_by_key(|(syntax, _)| syntax.text_range().start()) - .format_with("\n", |(k, v), f| { - f(&format!( - "Line {}: {:?} -> {}", - line_number(k), - k, - fmt_syntax(v) - )) - }); - - let deletions = diff.deletions.iter().format_with("\n", |v, f| { - f(&format!("Line {}: {}", line_number(v), &fmt_syntax(v))) - }); - - let actual = format!( - "insertions:\n\n{insertions}\n\nreplacements:\n\n{replacements}\n\ndeletions:\n\n{deletions}\n" - ); - expected_diff.assert_eq(&actual); - - let mut from = from.to_owned(); - let mut text_edit = TextEdit::builder(); - diff.into_text_edit(&mut text_edit); - text_edit.finish().apply(&mut from); - assert_eq!(&*from, to, "diff did not turn `from` to `to`"); - } -} diff --git a/crates/ide_ssr/src/tests.rs b/crates/ide_ssr/src/tests.rs index 881a5ac123..108680853e 100644 --- a/crates/ide_ssr/src/tests.rs +++ b/crates/ide_ssr/src/tests.rs @@ -1288,7 +1288,7 @@ fn ssr_do_not_match_pattern_missing() { r#" g() -> <<$",$\\,194,181,$A,$">> = - """ + ~b""" "\\µA" """. "#, @@ -1327,7 +1327,7 @@ fn ssr_comments_in_match() { <<{ % preceding comment 3}, { 3 % following comment - }>>. + >>. "#; let strategy = Strategy { macros: MacroStrategy::Expand, @@ -1536,7 +1536,7 @@ fn ssr_predicates_on_match_expr_pat() { %-compile({"str", var, atom}). %-type foo(V) :: {"str", V, atom}. foo({"hello", Var, atom}) -> {"str", Var, aa}. - + "#; let strategy = Strategy { macros: MacroStrategy::Expand, @@ -1636,7 +1636,7 @@ fn ssr_predicates_on_match_type() { let pattern = "ssr: {_@V, _@A}."; let code = r#" -type foo(V) :: {V, atom}. - + "#; let strategy = Strategy { macros: MacroStrategy::Expand, diff --git a/crates/project_model/src/buck.rs b/crates/project_model/src/buck.rs index 45c6b7f732..064c93de26 100644 --- a/crates/project_model/src/buck.rs +++ b/crates/project_model/src/buck.rs @@ -58,7 +58,6 @@ lazy_static! { } const ERL_EXT: &str = "erl"; -const BUCK_ISOLATION_DIR: &str = "lsp"; #[derive( Debug, @@ -89,14 +88,6 @@ pub struct BuckConfig { #[serde(default)] pub excluded_targets: Vec, pub(crate) source_root: Option, - /// Buck2 labels that denote test applications. - /// Defaults to ["test_application"] if not specified. - #[serde(default = "default_test_application_labels")] - pub test_application_labels: Vec, -} - -fn default_test_application_labels() -> Vec { - vec!["test_application".to_string()] } impl BuckConfig { @@ -109,7 +100,7 @@ impl BuckConfig { cmd.env_remove("RUST_BACKTRACE") .env_remove("RUST_LIB_BACKTRACE"); cmd.arg("--isolation-dir"); - cmd.arg(BUCK_ISOLATION_DIR); + cmd.arg("lsp"); cmd.current_dir(self.buck_root()); CommandProxy::new(guard, cmd) } @@ -735,7 +726,7 @@ fn load_buck_targets_bxl( root, name, buck_target, - buck_config, + buck_config.build_deps, targets_include_prelude, &mut dep_path, &mut target_info, @@ -756,7 +747,7 @@ fn make_buck_target( root: &AbsPathBuf, name: &String, target: &BuckTarget, - buck_config: &BuckConfig, + build_deps: bool, targets_include_prelude: bool, dep_path: &mut FxHashMap, target_info: &mut TargetInfo, @@ -772,12 +763,7 @@ fn make_buck_target( (src, TargetType::ErlangTest, false, None) } else { let mut private_header = false; - let target_type = compute_target_type( - name, - target, - targets_include_prelude, - &buck_config.test_application_labels, - ); + let target_type = compute_target_type(name, target, targets_include_prelude); let mut src_files = vec![]; for src in &target.srcs { let src = json::canonicalize(buck_path_to_abs_path(root, src).unwrap())?; @@ -788,7 +774,7 @@ fn make_buck_target( } let ebin = match target_type { - TargetType::ThirdParty if buck_config.build_deps => dep_path + TargetType::ThirdParty if build_deps => dep_path .remove(name) .map(|dir| dir.join(Utf8PathBuf::from("ebin"))), TargetType::ThirdParty => Some(dir.clone()), @@ -831,20 +817,19 @@ fn compute_target_type( name: &TargetFullName, target: &BuckTarget, targets_include_prelude: bool, - test_application_labels: &[String], ) -> TargetType { // Check if we are trying to work on the prelude itself let is_prelude_as_third_party = !targets_include_prelude && name.starts_with("prelude//"); if is_prelude_as_third_party || name.contains("//third-party") { TargetType::ThirdParty } else { - let is_test_application = test_application_labels - .iter() - .any(|label| target.labels.contains(label)); - if is_test_application { - TargetType::ErlangTestUtils - } else { - TargetType::ErlangApp + let test_utils = target.labels.contains("test_utils"); + let test_application = target.labels.contains("test_application"); + let elp_enabled = target.labels.contains("elp_enabled"); + match (elp_enabled, test_application, test_utils) { + (true, _, _) => TargetType::ErlangApp, + (false, false, false) => TargetType::ErlangApp, + (_, _, _) => TargetType::ErlangTestUtils, } } } @@ -888,16 +873,6 @@ pub enum BuckQueryConfig { BuckTargetsOnly, } -impl fmt::Display for BuckQueryConfig { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - BuckQueryConfig::BuildGeneratedCode => write!(f, "BuildGeneratedCode"), - BuckQueryConfig::NoBuildGeneratedCode => write!(f, "NoBuildGeneratedCode"), - BuckQueryConfig::BuckTargetsOnly => write!(f, "BuckTargetsOnly"), - } - } -} - fn filter_buck_targets( buck_config: &BuckConfig, result: FxHashMap, @@ -1363,56 +1338,36 @@ fn include_path_from_file(path: &AbsPath) -> AbsPathBuf { } } -fn check_buck_output_success(mut command: CommandProxy<'_>) -> Result { - let output = command.output()?; - if output.status.success() { - return String::from_utf8(output.stdout) - .map_err(|e| anyhow::anyhow!("Invalid UTF-8 in stdout for `{command}`: {e}")); - } - let reason = match output.status.code() { - Some(code) => format!("Exited with status code: {code}"), - None => "Process terminated by signal".to_string(), - }; - let details = String::from_utf8(output.stderr).unwrap_or_default(); - bail!("Command `{command}` failed. Reason: {reason}. Details: {details}"); -} - /// This is used in tests pub fn get_prelude_cell(buck_config: &BuckConfig) -> Result { - let mut command = buck_config.buck_command(); - command + let output = buck_config + .buck_command() .arg("audit") .arg("cell") .arg("prelude") - .arg("--json"); - let raw_output = check_buck_output_success(command)?; - - let json: serde_json::Value = serde_json::from_str(&raw_output)?; - let prelude_path = json - .get("prelude") - .and_then(|v| v.as_str()) - .ok_or_else(|| anyhow::anyhow!("Could not find prelude path in Buck2 output"))? - .to_string(); - - if Path::new(&prelude_path).exists() { - Ok(prelude_path) - } else { - get_prelude_cell_bundled(buck_config) + .output()?; + if !output.status.success() { + let reason = match output.status.code() { + Some(code) => format!("Exited with status code: {code}"), + None => "Process terminated by signal".to_string(), + }; + let details = match String::from_utf8(output.stderr) { + Ok(err) => err, + Err(_) => "".to_string(), + }; + bail!("Error evaluating Buck2 query Reason: {reason}. Details: {details}",); } -} + let raw_output = String::from_utf8(output.stdout)?; -fn get_prelude_cell_bundled(buck_config: &BuckConfig) -> Result { - let mut command = buck_config.buck_command(); - command.arg("root"); - let root = check_buck_output_success(command)?; - let root = root.trim(); - let bundled_prelude_path = Path::new(&root) - .join("buck-out") - .join(BUCK_ISOLATION_DIR) - .join("external_cells") - .join("bundled") - .join("prelude"); - Ok(bundled_prelude_path.to_string_lossy().to_string()) + lazy_static! { + static ref RE: Regex = Regex::new(r"^prelude: ([^\s]+)").unwrap(); + } + let string = RE + .captures_iter(&raw_output) + .next() + .map(|c| c[1].to_string()) + .unwrap(); + Ok(string) } #[cfg(test)] @@ -1453,10 +1408,6 @@ mod tests { "#; let dir = FixtureWithProjectMeta::gen_project(spec); let root = AbsPath::assert(Utf8Path::from_path(dir.path()).unwrap()); - let _guard = set_test_cell_info(vec![( - "cell".to_string(), - dir.path().to_string_lossy().into_owned(), - )]); let target_name = "cell//app_a:app_a".to_string(); let target = BuckTarget { name: "app_a".to_string(), @@ -1485,10 +1436,6 @@ mod tests { "#; let dir = FixtureWithProjectMeta::gen_project(spec); let root = AbsPath::assert(Utf8Path::from_path(dir.path()).unwrap()); - let _guard = set_test_cell_info(vec![( - "cell".to_string(), - dir.path().to_string_lossy().into_owned(), - )]); let target_name = "cell//app_a:app_a".to_string(); let target = BuckTarget { name: "app_a".to_string(), @@ -1517,10 +1464,6 @@ mod tests { "#; let dir = FixtureWithProjectMeta::gen_project(spec); let root = AbsPath::assert(Utf8Path::from_path(dir.path()).unwrap()); - let _guard = set_test_cell_info(vec![( - "cell".to_string(), - dir.path().to_string_lossy().into_owned(), - )]); let target_name = "cell//app_a:app_a".to_string(); let target = BuckTarget { name: "app_a".to_string(), @@ -1619,10 +1562,6 @@ mod tests { "#; let dir = FixtureWithProjectMeta::gen_project(spec); let root = AbsPath::assert(Utf8Path::from_path(dir.path()).unwrap()); - let _guard = set_test_cell_info(vec![( - "cell".to_string(), - dir.path().to_string_lossy().into_owned(), - )]); let target_name = "cell//app_a:app_a".to_string(); let target = BuckTarget { name: "app_a".to_string(), @@ -1643,66 +1582,71 @@ mod tests { assert_eq!(expected, actual) } + // TODO: enable when buck is properly set up on github project + // @fb-only + const BUCK_TESTS_ENABLED: bool = false; // @oss-only + #[track_caller] fn check_buck_bxl_query(build_generated: bool, expect: Expect) { - let buck_root = to_abs_path_buf(&std::env::current_dir().unwrap()).unwrap(); - // We only need buck_config to get the buck command, everything but the buck root is ignored. - let buck_config = BuckConfig { - config_path: None, - buck_root: Some(buck_root), - enabled: true, - deps_target: None, - deps_targets: vec![], - build_deps: false, - included_targets: vec![], - excluded_targets: vec![], - source_root: None, - test_application_labels: vec!["test_application".to_string()], - }; - let generated_args = if build_generated { - vec!["--build_generated_code", "true"] - } else { - vec![] - }; - let output = buck_config - .buck_command() - .arg("bxl") - .arg("prelude//erlang/elp.bxl:elp_config") - .arg("--") - .args(generated_args) - .arg("--included_targets") - .arg("root//buck_tests_2/auto_gen/...") - .output() - .unwrap(); - if !output.status.success() { - panic!("{output:#?}"); - } - let string = String::from_utf8(output.stdout).unwrap(); - let prelude_cell = get_prelude_cell(&buck_config).expect("could not get prelude"); - let string = string.replace(&prelude_cell, "/[prelude]/"); + if BUCK_TESTS_ENABLED { + let buck_root = to_abs_path_buf(&std::env::current_dir().unwrap()).unwrap(); + // We only need buck_config to get the buck command, everything but the buck root is ignored. + let buck_config = BuckConfig { + config_path: None, + buck_root: Some(buck_root), + enabled: true, + deps_target: None, + deps_targets: vec![], + build_deps: false, + included_targets: vec![], + excluded_targets: vec![], + source_root: None, + }; + let generated_args = if build_generated { + vec!["--build_generated_code", "true"] + } else { + vec![] + }; + let output = buck_config + .buck_command() + .arg("bxl") + .arg("prelude//erlang/elp.bxl:elp_config") + .arg("--") + .args(generated_args) + .arg("--included_targets") + .arg("fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/...") + .output() + .unwrap(); + if !output.status.success() { + panic!("{output:#?}"); + } + let string = String::from_utf8(output.stdout).unwrap(); + let prelude_cell = get_prelude_cell(&buck_config).expect("could not get prelude"); + let string = string.replace(&prelude_cell, "/[prelude]/"); - let to_replace = env!("CARGO_WORKSPACE_DIR"); - let string = string.replace(to_replace, "/[..]/"); - expect.assert_eq(&string); + let to_replace = env!("CARGO_WORKSPACE_DIR"); + let string = string.replace(to_replace, "/[..]/"); + expect.assert_eq(&string); + } } #[test] #[ignore] fn build_info_buck_bxl_query() { - if cfg!(feature = "buck") { + if BUCK_TESTS_ENABLED { check_buck_bxl_query( false, expect![[r#" { - "root//buck_tests_2/auto_gen/auto_gen_a:auto_gen_a": { + "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:auto_gen_a": { "name": "auto_gen_a", "app_name": null, "suite": null, "srcs": [ - "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl" + "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl" ], "includes": [ - "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/include" + "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/include" ], "labels": [ "user_application" @@ -1712,7 +1656,7 @@ mod tests { "included_apps": [], "origin": "app" }, - "root//buck_tests_2/auto_gen/auto_gen_a:generated_srcs": { + "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:generated_srcs": { "name": "generated_srcs", "app_name": null, "suite": null, @@ -1855,23 +1799,23 @@ mod tests { #[test] #[ignore] fn build_info_buck_bxl_generated_query() { - if cfg!(feature = "buck") { + if BUCK_TESTS_ENABLED { // Note that there is now a value for `srcs` in the - // "root//buck_tests_2/auto_gen/auto_gen_a:generated_srcs" + // "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:generated_srcs" // target check_buck_bxl_query( true, expect![[r#" { - "root//buck_tests_2/auto_gen/auto_gen_a:auto_gen_a": { + "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:auto_gen_a": { "name": "auto_gen_a", "app_name": null, "suite": null, "srcs": [ - "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl" + "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl" ], "includes": [ - "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/include" + "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/include" ], "labels": [ "user_application" @@ -1881,12 +1825,12 @@ mod tests { "included_apps": [], "origin": "app" }, - "root//buck_tests_2/auto_gen/auto_gen_a:generated_srcs": { + "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:generated_srcs": { "name": "generated_srcs", "app_name": null, "suite": null, "srcs": [ - "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl" + "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl" ], "includes": [], "labels": [ diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index 233c687afc..53e550d05a 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs @@ -339,13 +339,7 @@ impl ProjectManifest { pub fn discover_in_place(path: &AbsPath, rebar_profile: Profile) -> Result { let _timer = timeit!("discover projects in place"); // We skip looking for the TOML file since we have already found it. - if let Some(elp_config_basedir) = path.parent() - && let Some(r) = Self::discover_rebar( - &elp_config_basedir.to_path_buf(), - Some(rebar_profile), - IncludeParentDirs::No, - )? - { + if let Some(r) = Self::discover_rebar(path, Some(rebar_profile), IncludeParentDirs::No)? { return Ok(r); } if let Some(s) = Self::discover_static(path, IncludeParentDirs::No)? { @@ -1577,60 +1571,6 @@ mod tests { .assert_eq(&debug_normalise_temp_dir(dir, &manifest)); } - #[test] - fn test_toml_empty_rebar_config() { - if cfg!(feature = "buck") { - let spec = r#" - //- /root/.elp.toml - //- /root/rebar.config - //- /root/app_a/src/app.erl - -module(app). - "#; - let dir = FixtureWithProjectMeta::gen_project(spec); - let discovered = ProjectManifest::discover( - &to_abs_path_buf(&dir.path().join("root/app_a/src/app.erl")).unwrap(), - ); - expect![[r#" - Ok( - ( - ElpConfig { - config_path: Some( - AbsPathBuf( - "TMPDIR/root/.elp.toml", - ), - ), - build_info: None, - buck: None, - eqwalizer: EqwalizerConfig { - enable_all: true, - max_tasks: 4, - ignore_modules: [], - ignore_modules_compiled_patterns: [], - }, - rebar: ElpRebarConfig { - profile: "test", - }, - otp: OtpConfig { - exclude_apps: [], - }, - }, - Rebar( - RebarConfig { - config_file: AbsPathBuf( - "TMPDIR/root/rebar.config", - ), - profile: Profile( - "test", - ), - }, - ), - ), - ) - "#]] - .assert_eq(&debug_normalise_temp_dir(dir, &discovered)); - } - } - #[test] fn test_toml_empty() { // This one is a real worst-case. We force discovery to happen in @@ -1899,7 +1839,6 @@ mod tests { "root//target/four".to_string(), ], source_root: Some(PathBuf::from("path/to/root")), - test_application_labels: vec!["test_application".to_string()], }), eqwalizer: EqwalizerConfig { enable_all: true, @@ -1925,7 +1864,6 @@ mod tests { included_targets = ["root//target/one", "root//target/two"] excluded_targets = ["root//target/three", "root//target/four"] source_root = "path/to/root" - test_application_labels = ["test_application"] [eqwalizer] enable_all = true @@ -1999,9 +1937,6 @@ mod tests { source_root: Some( "path/to/root", ), - test_application_labels: [ - "test_application", - ], }, ), eqwalizer: EqwalizerConfig { diff --git a/crates/project_model/src/test_fixture.rs b/crates/project_model/src/test_fixture.rs index 140baec0ee..769891190a 100644 --- a/crates/project_model/src/test_fixture.rs +++ b/crates/project_model/src/test_fixture.rs @@ -187,7 +187,6 @@ impl DiagnosticsEnabled { pub struct FixtureWithProjectMeta { pub fixture: Vec, pub diagnostics_enabled: DiagnosticsEnabled, - pub expect_parse_errors: bool, } impl FixtureWithProjectMeta { @@ -205,7 +204,6 @@ impl FixtureWithProjectMeta { let mut fixture = fixture.as_str(); let mut res: Vec = Vec::new(); let mut diagnostics_enabled = DiagnosticsEnabled::default(); - let mut expect_parse_errors = false; // --------------------------------------- // Each of the following is optional, but they must always @@ -234,12 +232,6 @@ impl FixtureWithProjectMeta { fixture = remain; } - if let Some(meta) = fixture.strip_prefix("//- expect_parse_errors") { - let (_meta, remain) = meta.split_once('\n').unwrap(); - expect_parse_errors = true; - fixture = remain; - } - if let Some(meta) = fixture.strip_prefix("//- native") { let (_meta, remain) = meta.split_once('\n').unwrap(); diagnostics_enabled.use_native = true; @@ -285,12 +277,6 @@ impl FixtureWithProjectMeta { if let Some(entry) = res.last_mut() { entry.text.push_str(line); - } else if line.chars().any(|c| !c.is_whitespace()) { - panic!( - "Fixture has content before the first file marker (`//- /path/to/file.erl`). \ - Did you forget to add a file marker at the beginning?\n\ - The offending line: {line:?}" - ); } } } @@ -312,7 +298,6 @@ impl FixtureWithProjectMeta { FixtureWithProjectMeta { fixture: res, diagnostics_enabled, - expect_parse_errors, } } @@ -487,14 +472,6 @@ pub fn extract_tags(mut text: &str, tag: &str) -> (Vec<(TextRange, Option syntax error oops. -/// %% ^^^^^ error: P1711: syntax error before: error -/// %% | Related info: 0:25-30 function foo/0 undefined -/// ``` -/// /// Annotations point to the last line that actually was long enough for the /// range, not counting annotations themselves. So overlapping annotations are /// possible: @@ -574,16 +551,10 @@ pub fn extract_annotations(text: &str) -> (Vec<(TextRange, String)>, String) { if !res.is_empty() { offset += annotation_offset; this_line_annotations.push((offset, res.len() - 1)); - // Try to find a previous annotation at the same offset - let idx = if let Some(&(_, idx)) = prev_line_annotations + let &(_, idx) = prev_line_annotations .iter() .find(|&&(off, _idx)| off == offset) - { - idx - } else { - // If no exact offset match, append to the most recent annotation - res.len() - 1 - }; + .unwrap(); res[idx].1.push('\n'); res[idx].1.push_str(&content); } @@ -853,19 +824,6 @@ mod tests { use crate::test_fixture::extract_tags; use crate::test_fixture::remove_annotations; - #[test] - #[should_panic(expected = "Fixture has content before the first file marker")] - fn parse_fixture_panics_on_content_before_first_file_marker() { - FixtureWithProjectMeta::parse( - r#" - -module(main). - foo() -> ok. - //- /src/erl_eval.erl - -module(erl_eval). - "#, - ); - } - #[test] #[should_panic] fn parse_fixture_checks_further_indented_metadata() { diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 1f8d1aaa63..081efa08d4 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -7,6 +7,9 @@ version.workspace = true workspace = true [dependencies] +elp_text_edit.workspace = true + +cov-mark.workspace = true eetf.workspace = true fxhash.workspace = true indexmap.workspace = true diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs index 08b7ed9a1f..af72d7de98 100644 --- a/crates/syntax/src/algo.rs +++ b/crates/syntax/src/algo.rs @@ -10,8 +10,12 @@ //! Collection of assorted algorithms for syntax trees. +use std::hash::BuildHasherDefault; use std::ops::RangeInclusive; +use elp_text_edit::TextEditBuilder; +use fxhash::FxHashMap; +use indexmap::IndexMap; use itertools::Itertools; use rowan::NodeOrToken; @@ -174,6 +178,157 @@ pub enum InsertPosition { After(T), } +type FxIndexMap = IndexMap>; + +#[derive(Debug, Hash, PartialEq, Eq)] +enum TreeDiffInsertPos { + After(SyntaxElement), + AsFirstChild(SyntaxElement), +} + +#[derive(Debug)] +pub struct TreeDiff { + replacements: FxHashMap, + deletions: Vec, + // the vec as well as the indexmap are both here to preserve order + insertions: FxIndexMap>, +} + +impl TreeDiff { + pub fn into_text_edit(&self, builder: &mut TextEditBuilder) { + let _p = tracing::info_span!("into_text_edit").entered(); + + for (anchor, to) in self.insertions.iter() { + let offset = match anchor { + TreeDiffInsertPos::After(it) => it.text_range().end(), + TreeDiffInsertPos::AsFirstChild(it) => it.text_range().start(), + }; + to.iter() + .for_each(|to| builder.insert(offset, to.to_string())); + } + for (from, to) in self.replacements.iter() { + builder.replace(from.text_range(), to.to_string()) + } + for text_range in self.deletions.iter().map(SyntaxElement::text_range) { + builder.delete(text_range); + } + } + + pub fn is_empty(&self) -> bool { + self.replacements.is_empty() && self.deletions.is_empty() && self.insertions.is_empty() + } +} + +/// Finds a (potentially minimal) diff, which, applied to `from`, will result in `to`. +/// +/// Specifically, returns a structure that consists of a replacements, insertions and deletions +/// such that applying this map on `from` will result in `to`. +/// +/// This function tries to find a fine-grained diff. +pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { + let _p = tracing::info_span!("diff").entered(); + + let mut diff = TreeDiff { + replacements: FxHashMap::default(), + insertions: FxIndexMap::default(), + deletions: Vec::new(), + }; + let (from, to) = (from.clone().into(), to.clone().into()); + + if !syntax_element_eq(&from, &to) { + go(&mut diff, from, to); + } + return diff; + + fn syntax_element_eq(lhs: &SyntaxElement, rhs: &SyntaxElement) -> bool { + lhs.kind() == rhs.kind() + && lhs.text_range().len() == rhs.text_range().len() + && match (&lhs, &rhs) { + (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => { + lhs == rhs || lhs.text() == rhs.text() + } + (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(), + _ => false, + } + } + + // FIXME: this is horribly inefficient. I bet there's a cool algorithm to diff trees properly. + fn go(diff: &mut TreeDiff, lhs: SyntaxElement, rhs: SyntaxElement) { + let (lhs, rhs) = match lhs.as_node().zip(rhs.as_node()) { + Some((lhs, rhs)) => (lhs, rhs), + _ => { + cov_mark::hit!(diff_node_token_replace); + diff.replacements.insert(lhs, rhs); + return; + } + }; + + let mut look_ahead_scratch = Vec::default(); + + let mut rhs_children = rhs.children_with_tokens(); + let mut lhs_children = lhs.children_with_tokens(); + let mut last_lhs = None; + loop { + let lhs_child = lhs_children.next(); + match (lhs_child.clone(), rhs_children.next()) { + (None, None) => break, + (None, Some(element)) => { + let insert_pos = match last_lhs.clone() { + Some(prev) => { + cov_mark::hit!(diff_insert); + TreeDiffInsertPos::After(prev) + } + // first iteration, insert into out parent as the first child + None => { + cov_mark::hit!(diff_insert_as_first_child); + TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) + } + }; + diff.insertions.entry(insert_pos).or_default().push(element); + } + (Some(element), None) => { + cov_mark::hit!(diff_delete); + diff.deletions.push(element); + } + (Some(ref lhs_ele), Some(ref rhs_ele)) if syntax_element_eq(lhs_ele, rhs_ele) => {} + (Some(lhs_ele), Some(rhs_ele)) => { + // nodes differ, look for lhs_ele in rhs, if its found we can mark everything up + // until that element as insertions. This is important to keep the diff minimal + // in regards to insertions that have been actually done, this is important for + // use insertions as we do not want to replace the entire module node. + look_ahead_scratch.push(rhs_ele.clone()); + let mut rhs_children_clone = rhs_children.clone(); + let mut insert = false; + for rhs_child in rhs_children_clone.by_ref() { + if syntax_element_eq(&lhs_ele, &rhs_child) { + cov_mark::hit!(diff_insertions); + insert = true; + break; + } else { + look_ahead_scratch.push(rhs_child); + } + } + let drain = look_ahead_scratch.drain(..); + if insert { + let insert_pos = if let Some(prev) = last_lhs.clone().filter(|_| insert) { + TreeDiffInsertPos::After(prev) + } else { + cov_mark::hit!(insert_first_child); + TreeDiffInsertPos::AsFirstChild(lhs.clone().into()) + }; + + diff.insertions.entry(insert_pos).or_default().extend(drain); + rhs_children = rhs_children_clone; + } else { + go(diff, lhs_ele, rhs_ele) + } + } + } + last_lhs = lhs_child.or(last_lhs); + } + } +} + /// Adds specified children (tokens or nodes) to the current node at the /// specific position. /// @@ -297,3 +452,337 @@ fn to_green_element(element: SyntaxElement) -> NodeOrToken it.green().to_owned().into(), } } + +#[cfg(test)] +mod tests { + use elp_text_edit::TextEdit; + use expect_test::Expect; + use expect_test::expect; + use itertools::Itertools; + + use crate::AstNode; + use crate::SyntaxElement; + use crate::SyntaxKind; + + #[test] + fn replace_node_token() { + cov_mark::check!(diff_node_token_replace); + check_diff( + r#"-module(foo)."#, + r#"ident"#, + expect![[r#" + insertions: + + + + replacements: + + Line 0: Token(ANON_DASH@0..1 "-") -> ident + + deletions: + + Line 1: module + Line 1: ( + Line 1: foo + Line 1: ) + Line 1: . + "#]], + ); + } + + #[test] + fn replace_parent() { + cov_mark::check!(diff_node_token_replace); + check_diff( + r#""#, + r#"-module(foo)."#, + expect![[r#" + insertions: + + + + replacements: + + Line 0: Token(SOURCE_FILE@0..0 "") -> -module(foo). + + deletions: + + + "#]], + ); + } + + #[test] + fn insert_last() { + cov_mark::check!(diff_insert); + check_diff( + r#" +-module(foo). +-use(foo). +-use(bar)."#, + r#" +-module(foo). +-use(foo). +-use(bar). +-use(baz)."#, + expect![[r#" + insertions: + + Line 3: After(Node(WILD_ATTRIBUTE@26..36)) + -> "\n" + -> -use(baz). + + replacements: + + + + deletions: + + + "#]], + ); + } + + #[test] + fn insert_middle() { + check_diff( + r#" +-module(foo). +-use(foo). +-use(bar)."#, + r#" +-module(foo). +-use(foo). +-use(baz). +-use(bar)."#, + expect![[r#" + insertions: + + Line 3: After(Token(WHITESPACE@25..26 "\n")) + -> -use(baz). + -> "\n" + + replacements: + + + + deletions: + + + "#]], + ) + } + + #[test] + fn insert_first() { + check_diff( + r#" +-use(bar). +-use(baz)."#, + r#" +-export([foo/0]). +-use(bar). +-use(baz)."#, + expect![[r#" + insertions: + + Line 0: After(Token(WHITESPACE@0..1 "\n")) + -> -export([foo/0]). + -> "\n" + + replacements: + + + + deletions: + + + "#]], + ) + } + + #[test] + fn first_child_insertion() { + // cov_mark::check!(insert_first_child); + check_diff( + r#" +main() -> + ok."#, + r#" +-module(foo). + +main() -> + ok."#, + expect![[r#" + insertions: + + Line 0: After(Token(WHITESPACE@0..1 "\n")) + -> -module(foo). + -> "\n\n" + + replacements: + + + + deletions: + + + "#]], + ); + } + + #[test] + fn delete_last() { + cov_mark::check!(diff_delete); + check_diff( + r#"-module(foo). + -bar([baz])."#, + r#"-module(foo)."#, + expect![[r#" + insertions: + + + + replacements: + + + + deletions: + + Line 1: "\n " + Line 2: -bar([baz]). + "#]], + ); + } + + #[test] + fn delete_middle() { + // cov_mark::check!(diff_insertions); + check_diff( + r#" +-export([foo/0,bar/1]). +-bar(aaa). + +-foo(bbb). +"#, + r#" +-export([foo/0,bar/1]). + +-foo(bbb). +"#, + expect![[r#" + insertions: + + Line 1: After(Node(EXPORT_ATTRIBUTE@1..24)) + -> "\n\n" + -> -foo(bbb). + + replacements: + + + + deletions: + + Line 2: -bar(aaa). + Line 3: "\n\n" + Line 4: -foo(bbb). + Line 5: "\n" + "#]], + ) + } + + #[test] + fn delete_first() { + check_diff( + r#" +-export([foo/0,bar/1]). + +-foo(bbb). +"#, + r#" +-foo(bbb). +"#, + expect![[r#" + insertions: + + + + replacements: + + Line 1: Token(ANON_DASH@1..2 "-") -> -foo + Line 2: Token(ANON_EXPORT@2..8 "export") -> (bbb) + Line 2: Token(ANON_LPAREN@8..9 "(") -> . + Line 2: Token(WHITESPACE@24..26 "\n\n") -> "\n" + + deletions: + + Line 2: [ + Line 2: foo/0 + Line 2: , + Line 2: bar/1 + Line 2: ] + Line 2: ) + Line 2: . + Line 3: -foo(bbb). + Line 4: "\n" + "#]], + ) + } + + fn check_diff(from: &str, to: &str, expected_diff: Expect) { + let from_node = crate::SourceFile::parse_text(from).tree().syntax().clone(); + let to_node = crate::SourceFile::parse_text(to).tree().syntax().clone(); + let diff = super::diff(&from_node, &to_node); + + let line_number = + |syn: &SyntaxElement| from[..syn.text_range().start().into()].lines().count(); + + let fmt_syntax = |syn: &SyntaxElement| match syn.kind() { + SyntaxKind::WHITESPACE => format!("{:?}", syn.to_string()), + _ => format!("{syn}"), + }; + + let insertions = + diff.insertions + .iter() + .format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> { + f(&format!( + "Line {}: {:?}\n-> {}", + line_number(match k { + super::TreeDiffInsertPos::After(syn) => syn, + super::TreeDiffInsertPos::AsFirstChild(syn) => syn, + }), + k, + v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v))) + )) + }); + + let replacements = diff + .replacements + .iter() + .sorted_by_key(|(syntax, _)| syntax.text_range().start()) + .format_with("\n", |(k, v), f| { + f(&format!( + "Line {}: {:?} -> {}", + line_number(k), + k, + fmt_syntax(v) + )) + }); + + let deletions = diff.deletions.iter().format_with("\n", |v, f| { + f(&format!("Line {}: {}", line_number(v), &fmt_syntax(v))) + }); + + let actual = format!( + "insertions:\n\n{insertions}\n\nreplacements:\n\n{replacements}\n\ndeletions:\n\n{deletions}\n" + ); + expected_diff.assert_eq(&actual); + + let mut from = from.to_owned(); + let mut text_edit = TextEdit::builder(); + diff.into_text_edit(&mut text_edit); + text_edit.finish().apply(&mut from); + assert_eq!(&*from, to, "diff did not turn `from` to `to`"); + } +} diff --git a/crates/syntax/src/syntax_kind/generated.rs b/crates/syntax/src/syntax_kind/generated.rs index 781d35aaaf..716d46d25a 100644 --- a/crates/syntax/src/syntax_kind/generated.rs +++ b/crates/syntax/src/syntax_kind/generated.rs @@ -1,8 +1,7 @@ //! @generated file, do not edit by hand, see `xtask/src/codegen.rs` #![allow(bad_style, missing_docs, unreachable_pub)] -use num_derive::FromPrimitive; -use num_derive::ToPrimitive; +use num_derive::{FromPrimitive, ToPrimitive}; #[doc = r" The kind of syntax node, e.g. `ATOM`, `IF_KW`, or `DOT`."] #[derive( Clone, diff --git a/crates/text_edit/Cargo.toml b/crates/text_edit/Cargo.toml new file mode 100644 index 0000000000..59d333adc7 --- /dev/null +++ b/crates/text_edit/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "elp_text_edit" +edition.workspace = true +version.workspace = true + +[lints] +workspace = true + +[dependencies] +itertools.workspace = true +text-size.workspace = true diff --git a/crates/ide_db/src/text_edit.rs b/crates/text_edit/src/lib.rs similarity index 99% rename from crates/ide_db/src/text_edit.rs rename to crates/text_edit/src/lib.rs index 0410102569..42dac0f3ac 100644 --- a/crates/ide_db/src/text_edit.rs +++ b/crates/text_edit/src/lib.rs @@ -15,6 +15,7 @@ //! `rust-analyzer` never mutates text itself and only sends diffs to clients, //! so `TextEdit` is the ultimate representation of the work done by //! rust-analyzer. + use std::cmp::max; use itertools::Itertools; diff --git a/editors/code/README.md b/editors/code/README.md index ff5663d5ca..b03ce757f2 100644 --- a/editors/code/README.md +++ b/editors/code/README.md @@ -1,82 +1,19 @@ # Erlang Language Platform -The **Erlang Language Platform (ELP)** is a modern Language Server Protocol -(LSP) implementation for Erlang, developed by WhatsApp. ELP provides -comprehensive IDE support for Erlang development, bringing features you'd expect -from modern development tools to the Erlang ecosystem. - -Built with scalability and performance in mind, ELP uses incremental analysis to -handle large codebases efficiently, making it suitable for projects of any size. +Provide support for the [Erlang](https://www.erlang.org/) Programming Language. ## Features -### Code Intelligence - -- **📍 Go To Definition** - Jump to function, type, record definitions, etc -- **🔍 Find References** - Find all usages of functions, types, and variables -- **✨ Auto-completion** - Intelligent code completion for functions, variables, - modules and more -- **🏷️ Hover Information** - View documentation and type information on hover -- **📞 Call Hierarchy** - Explore caller/callee relationships -- **✍️ Signature Help** - Parameter hints while typing function calls -- **📋 Inlay Hints** - Display parameter names inline -- **🎨 Syntax Highlighting** - Full Erlang syntax support -- **📝 Code Lenses** - Inline actions for running tests and debugging -- **🔄 Workspace Symbol Search** - Quickly find symbols across your project - -### Code Quality - -- **🔧 Diagnostics** - Real-time error and warning detection -- **💡 Code Actions** - Quick fixes and refactoring suggestions -- **🧪 Eqwalizer Integration** - Type checking with - [Eqwalizer](https://github.com/WhatsApp/eqwalizer) - -### Debugging & Testing - -- **🐞 Integrated Debugger** - Debug Erlang applications with breakpoints and - variable inspection +* Syntax Highlighting +* Go To Definition +* Find References +* Auto-completion +* Call Hierarchy +* Signature Help +* Diagnostics +* Inlay Hints +* ... ## Documentation -For comprehensive documentation, visit: - -- **📚 - [Official Documentation](https://whatsapp.github.io/erlang-language-platform/)** -- **🚀 - [Getting Started Guide](https://whatsapp.github.io/erlang-language-platform/docs/get-started/)** -- **⚙️ - [Configuration Reference](https://whatsapp.github.io/erlang-language-platform/docs/configuration/)** -- **❓ [FAQ](https://whatsapp.github.io/erlang-language-platform/docs/faq/)** - -## Contributing - -We welcome contributions! Please see our -[Contributing Guide](https://github.com/WhatsApp/erlang-language-platform/blob/main/CONTRIBUTING.md) -for details. - -## Community & Support - -- **🐛 Issues**: - [GitHub Issues](https://github.com/WhatsApp/erlang-language-platform/issues) -- **💬 Discussions**: - [GitHub Discussions](https://github.com/WhatsApp/erlang-language-platform/discussions) - -## License - -ELP is dual-licensed under: - -- [Apache License 2.0](https://github.com/WhatsApp/erlang-language-platform/blob/main/LICENSE-APACHE) -- [MIT License](https://github.com/WhatsApp/erlang-language-platform/blob/main/LICENSE-MIT) - -## Acknowledgments - -ELP was designed at **WhatsApp** and inspired by the -[Rust Analyzer](https://rust-analyzer.github.io/) project. Special thanks to all -[contributors](https://github.com/WhatsApp/erlang-language-platform/graphs/contributors) -who have helped make ELP better. - ---- - -

- Made with ❤️ by the WhatsApp team -

+See https://whatsapp.github.io/erlang-language-platform/ for more information. diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 6309d4c81e..1e62d62162 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -1,12 +1,12 @@ { "name": "erlang-language-platform", - "version": "0.47.0", + "version": "0.44.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "erlang-language-platform", - "version": "0.47.0", + "version": "0.44.0", "hasInstallScript": true, "license": "Apache2", "devDependencies": { @@ -1448,11 +1448,10 @@ "dev": true }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -1625,9 +1624,9 @@ } }, "node_modules/mocha/node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", "dependencies": { @@ -3400,9 +3399,9 @@ "dev": true }, "js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { "argparse": "^2.0.1" @@ -3533,9 +3532,9 @@ } }, "glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "requires": { "foreground-child": "^3.1.0", diff --git a/editors/code/package.json b/editors/code/package.json index eb7ced3148..d54a4de805 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1,10 +1,9 @@ { "name": "erlang-language-platform", - "displayName": "Erlang Language Platform", - "description": "Erlang Language Support for VS Code, by WhatsApp.", + "description": "Erlang language server", "author": "Meta Platforms, Inc", "license": "Apache2", - "version": "0.47.0", + "version": "0.44.0", "icon": "images/elp-logo-color.png", "homepage": "https://whatsapp.github.io/erlang-language-platform/", "repository": { @@ -21,8 +20,7 @@ "Testing" ], "keywords": [ - "elp", - "erlang" + "elp" ], "engines": { "vscode": "^1.75.0" diff --git a/editors/emacs/dotemacs.el b/elisp/dotemacs.el similarity index 100% rename from editors/emacs/dotemacs.el rename to elisp/dotemacs.el diff --git a/eqwalizer b/eqwalizer index 0f514eb389..bed8636fa6 160000 --- a/eqwalizer +++ b/eqwalizer @@ -1 +1 @@ -Subproject commit 0f514eb3893fa7070835c83ecb49fbea31b0426d +Subproject commit bed8636fa6b926e2292697be35e096db2386a78f diff --git a/erlang_service/src/elp_lint.erl b/erlang_service/src/elp_lint.erl index 31d2c70248..609e8c0712 100644 --- a/erlang_service/src/elp_lint.erl +++ b/erlang_service/src/elp_lint.erl @@ -4372,14 +4372,14 @@ is_format_function(io, fwrite) -> true; is_format_function(io, format) -> true; is_format_function(io_lib, fwrite) -> true; is_format_function(io_lib, format) -> true; -% @fb-only: is_format_function(wa_log, send_if) -> true; -% @fb-only: is_format_function(wa_string, format) -> true; +% @fb-only +% @fb-only is_format_function(M, F) when is_atom(M), is_atom(F) -> false. %% check_format_1([Arg]) -> ok | {warn,Level,Format,[Arg]}. -% @fb-only[end= ]: format_args(wa_log, send_if, [_Level, _Meta, _Opts, Format, Args]) -> [Format, Args]; -% @fb-only[end= ]: format_args(wa_string, format, [Format, Args, _Options]) -> [Format, Args]; +% @fb-only +% @fb-only format_args(_M, _F, As) -> As. diff --git a/erlang_service/src/erlang_service_lint.erl b/erlang_service/src/erlang_service_lint.erl index bc5a2faf3b..77223da49a 100644 --- a/erlang_service/src/erlang_service_lint.erl +++ b/erlang_service/src/erlang_service_lint.erl @@ -178,7 +178,6 @@ format_error(_Forms, _OriginalPath, Path, {Line, Mod, Reason}) when is_integer(L [ { unicode:characters_to_list(Path), - unicode:characters_to_list("ignored"), none, unicode:characters_to_list( io_lib:format("~p: ~ts", [Line, Mod:format_error(Reason)]) @@ -190,7 +189,6 @@ format_error(_Forms, SamePath, SamePath, {Location, Mod, Reason}) -> [ { unicode:characters_to_list(SamePath), - unicode:characters_to_list("ignored"), % Location would be {Line, Col} for a erlc compiler error/warning, % but {ByteStart, ByteEnd} for an eqwalizer diagnostic. % This is deciphered on elp side. @@ -201,19 +199,18 @@ format_error(_Forms, SamePath, SamePath, {Location, Mod, Reason}) -> erlang_service_error_codes:make_code(Mod, Reason) } ]; -format_error(Forms, IncluderPath, ErrorPath, {Location, Mod, Reason}) -> +format_error(Forms, OriginalPath, Path, {Location, Mod, Reason}) -> %% The original path and reported error path are different, the %% error is in an included file. %% This can be from an include, include_lib, behaviour or parse_transform - IncludeLocation = inclusion_range(Forms, ErrorPath), + IncludeLocation = inclusion_range(Forms, Path), %% We return an error at the location the error occurs, as well as %% a list of the errors in the included file. ELP will determine %% the appropriate FileId and emit diagnostics for the include file. [ { - unicode:characters_to_list(IncluderPath), - unicode:characters_to_list(ErrorPath), + unicode:characters_to_list(OriginalPath), % Location would be {Line, Col} for a erlc compiler error/warning, % but {ByteStart, ByteEnd} for an eqwalizer diagnostic. % This is deciphered on elp side. @@ -222,8 +219,7 @@ format_error(Forms, IncluderPath, ErrorPath, {Location, Mod, Reason}) -> erlang_service_error_codes:make_code(erlang_service_error_codes, "Issue in included file") }, { - unicode:characters_to_list(IncluderPath), - unicode:characters_to_list(ErrorPath), + unicode:characters_to_list(Path), % Location would be {Line, Col} for a erlc compiler error/warning, % but {ByteStart, ByteEnd} for an eqwalizer diagnostic. % This is deciphered on elp side. @@ -236,96 +232,13 @@ format_error(Forms, IncluderPath, ErrorPath, {Location, Mod, Reason}) -> ]. inclusion_range(Forms, Path) -> - %% The `include` or `include_lib` directive is processed by epp, so - %% it does not show up in the abstract forms directly. We infer its - %% location by looking for the `file` attribute with the same path, - %% which is inserted when epp starts processing a new file. - %% The wrinkle is that the range of the `file` attribute does not - %% correspond to the location of the `include` directive, but the last - %% thing processed in the current file. - - %% Track the full include context for a given path. - %% In the forms, process the file attributes. - %% Every time it has a Location of {0,0}, the file has been entered or re-entered - %% Keep a stack for the current location, pushing to it when a {0,0} is found for it, - %% popping when a {0,0} with the same path is found. - FileAttrs = [{Loc, FormPath} || {attribute, Loc, file, {FormPath, _}} <- Forms], - - Context = build_include_context(FileAttrs, Path), - - case Context of - [ _, {IncludeLoc, _IncludePath} | _Rest] -> - %% Return the location from the second entry (the include directive location in the parent file) - %% Extract the position from the location tuple and return as a range - case IncludeLoc of - {Pos, _} -> {Pos, Pos}; - Pos when is_integer(Pos) -> {Pos, Pos} - end; + case [Location || {attribute, Location, file, {FormPath, _}} <- Forms, FormPath == Path] of + [{Loc, _}] -> + {Loc, Loc}; _ -> {1, 1} end. -%% Build the include context stack for a given path -build_include_context(FileAttrs, TargetPath) -> - {_FinalStack, Context} = lists:foldl( - fun({Location, FilePath}, {Stack, ContextAcc}) -> - case Location of - {0, 0} -> - %% Entering or re-entering a file - case find_in_stack(Stack, FilePath) of - not_found -> - %% First time seeing this path - push to stack - NewStack = [{Location, FilePath} | Stack], - NewContextAcc = - case FilePath of - TargetPath -> - %% Found our target path, capture current stack (reversed to get bottom-up order) - lists:reverse(NewStack); - _ -> - ContextAcc - end, - {NewStack, NewContextAcc}; - _Found -> - %% Re-entering a file that was on the stack - pop back to it - NewStack = pop_to_path(Stack, FilePath), - {NewStack, ContextAcc} - end; - _ -> - %% Non-zero location - this is an include directive - %% Push this file onto the stack - NewStack = [{Location, FilePath} | Stack], - NewContextAcc = - case FilePath of - TargetPath -> - %% Found our target path, capture current stack (reversed to get bottom-up order) - lists:reverse(NewStack); - _ -> - ContextAcc - end, - {NewStack, NewContextAcc} - end - end, - {[], []}, - FileAttrs - ), - Context. - -%% Find a path in the stack -find_in_stack([], _Path) -> - not_found; -find_in_stack([{Loc, Path} | _Rest], Path) -> - {found, Loc}; -find_in_stack([_ | Rest], Path) -> - find_in_stack(Rest, Path). - -%% Pop the stack until we find the given path (inclusive) -pop_to_path([], _Path) -> - []; -pop_to_path([{_Loc, Path} | _Rest] = Stack, Path) -> - Stack; -pop_to_path([_ | Rest], Path) -> - pop_to_path(Rest, Path). - extract_forms(Id, FileName, FileId, FileText, Options) -> case filename:extension(FileName) of ".erl" -> diff --git a/test/test_projects/.buckconfig b/test/test_projects/.buckconfig deleted file mode 100644 index f14e564a7d..0000000000 --- a/test/test_projects/.buckconfig +++ /dev/null @@ -1,24 +0,0 @@ -[cells] - root = . - prelude = prelude - toolchains = toolchains - none = none - -[cell_aliases] - config = prelude - ovr_config = prelude - fbcode = none - fbsource = none - fbcode_macros = none - buck = none - -[external_cells] - prelude = bundled - -[parser] - target_platform_detector_spec = target:root//...->prelude//platforms:default \ - target:prelude//...->prelude//platforms:default \ - target:toolchains//...->prelude//platforms:default - -[build] - execution_platforms = prelude//platforms:default diff --git a/test/test_projects/.buckroot b/test/test_projects/.buckroot deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test/test_projects/buck_bad_config/.elp.toml b/test/test_projects/buck_bad_config/.elp.toml deleted file mode 100644 index 963072284c..0000000000 --- a/test/test_projects/buck_bad_config/.elp.toml +++ /dev/null @@ -1,8 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//buck_bad_config/..." ] -source_root = "buck_bad_config" - -[eqwalizer] -enable_all = false diff --git a/test/test_projects/buck_bad_config/BUCK b/test/test_projects/buck_bad_config/BUCK deleted file mode 100644 index 498c769dac..0000000000 --- a/test/test_projects/buck_bad_config/BUCK +++ /dev/null @@ -1,14 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "bad_app", - srcs = glob(["src/*.erl"]), - applications = [ - "root//buck_bad_config/non_existent:missing", - ], - includes = glob( - ["include/*.hrl"], - exclude = ["include/junk.hrl"], - ), - version = "1.0.0", -) diff --git a/test/test_projects/buck_tests/.elp.toml b/test/test_projects/buck_tests/.elp.toml deleted file mode 100644 index b38d6f043f..0000000000 --- a/test/test_projects/buck_tests/.elp.toml +++ /dev/null @@ -1,9 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//buck_tests/..." ] -excluded_targets = [ "buck_tests:test_elp_ignored" ] -source_root = "buck_tests" - -[eqwalizer] -enable_all = false diff --git a/test/test_projects/buck_tests_2/.elp.toml b/test/test_projects/buck_tests_2/.elp.toml deleted file mode 100644 index e71eb6a819..0000000000 --- a/test/test_projects/buck_tests_2/.elp.toml +++ /dev/null @@ -1,12 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ - "root//buck_tests_2/util/app_a/...", - "root//buck_tests_2:check_include" - ] -excluded_targets = [ "root//buck_tests_2:test_elp_ignored" ] -source_root = "buck_tests_2" - -[eqwalizer] -enable_all = false diff --git a/test/test_projects/buck_tests_2/BUCK b/test/test_projects/buck_tests_2/BUCK deleted file mode 100644 index b01fdb868c..0000000000 --- a/test/test_projects/buck_tests_2/BUCK +++ /dev/null @@ -1,41 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "check_include", - srcs = [ - "check_include/src/top_includer.erl", - ], - applications = [ - "common_test", - "stdlib", - "root//buck_tests_2:check_include_separate_1", - "root//buck_tests_2:check_include_separate_2", - ], - includes = [], - labels = [], - resources = [], -) - -erlang_application( - name = "check_include_separate_1", - srcs = glob([ - "src/*.erl", - ]), - applications = [ - ], - includes = [ - "check_include_separate_1/include/top_includer.hrl", - ], - resources = [], -) - -erlang_application( - name = "check_include_separate_2", - srcs = glob([ - "src/*.erl", - ]), - applications = [ - ], - includes = glob(["check_include_separate_2/include/*.hrl"]), - resources = [], -) diff --git a/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/BUCK b/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/BUCK deleted file mode 100644 index f021317020..0000000000 --- a/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/BUCK +++ /dev/null @@ -1,25 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "auto_gen_a", - srcs = glob([ - "src/*.erl", - "src/*.hrl", - ]), - includes = glob(["include/*.hrl"]), - visibility = ["//buck_tests_2/..."], -) - -erlang_application( - name = "generated_srcs", - srcs = [ - ":generated.erl", - ], - labels = ["generated"], - visibility = ["//buck_tests_2/..."], -) - -export_file( - name = "generated.erl", - src = "out/pretend_generated.erl", -) diff --git a/test/test_projects/buck_tests_2/check_include/src/top_includer.erl b/test/test_projects/buck_tests_2/check_include/src/top_includer.erl deleted file mode 100644 index 6f12fdb31d..0000000000 --- a/test/test_projects/buck_tests_2/check_include/src/top_includer.erl +++ /dev/null @@ -1,15 +0,0 @@ --module(top_includer). - --compile(warn_missing_spec_all). - --include_lib("stdlib/include/ms_transform.hrl"). --include_lib("check_include_separate_1/include/top_includer.hrl"). - --define(A_MACRO, ?FUNCTION_NAME). - -foo() -> - ?FIRST, - ?A_MACRO - ?SECOND, - ?THIRD(41,34), - ?FUNCTION_NAME. diff --git a/test/test_projects/buck_tests_2/check_include_separate_1/include/include_with_bug.hrl b/test/test_projects/buck_tests_2/check_include_separate_1/include/include_with_bug.hrl deleted file mode 100644 index 82ab343676..0000000000 --- a/test/test_projects/buck_tests_2/check_include_separate_1/include/include_with_bug.hrl +++ /dev/null @@ -1,5 +0,0 @@ -%% This file has a deliberate bug in it, to ensure we get a diagnostic -%% in the including file. -%% - -type foo() = ?FOO. diff --git a/test/test_projects/buck_tests_2/check_include_separate_1/include/top_includer.hrl b/test/test_projects/buck_tests_2/check_include_separate_1/include/top_includer.hrl deleted file mode 100644 index b67b5b8b2b..0000000000 --- a/test/test_projects/buck_tests_2/check_include_separate_1/include/top_includer.hrl +++ /dev/null @@ -1,6 +0,0 @@ - --include_lib("check_include_separate_2/include/separate_include.hrl"). --include("does_not_exist.hrl"). --include("include_with_bug.hrl"). - --define(FIRST, 1). diff --git a/test/test_projects/buck_tests_2/check_include_separate_2/include/separate_include.hrl b/test/test_projects/buck_tests_2/check_include_separate_2/include/separate_include.hrl deleted file mode 100644 index 1e0c48bf56..0000000000 --- a/test/test_projects/buck_tests_2/check_include_separate_2/include/separate_include.hrl +++ /dev/null @@ -1,2 +0,0 @@ - --define(SECOND, ok). diff --git a/test/test_projects/buck_tests_2/generated/BUCK b/test/test_projects/buck_tests_2/generated/BUCK deleted file mode 100644 index 8eec40830b..0000000000 --- a/test/test_projects/buck_tests_2/generated/BUCK +++ /dev/null @@ -1,12 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "generated_headers", - includes = [ - "out/generated_header.hrl", - ], - labels = ["generated"], - visibility = [ - "PUBLIC", - ], -) diff --git a/test/test_projects/buck_tests_2/util/app_a/BUCK b/test/test_projects/buck_tests_2/util/app_a/BUCK deleted file mode 100644 index 4231c1c6e8..0000000000 --- a/test/test_projects/buck_tests_2/util/app_a/BUCK +++ /dev/null @@ -1,16 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a_target", - srcs = glob(["src/*.erl"]), - app_name = "app_a", - applications = [ - "root//buck_tests_2/auto_gen/auto_gen_a:auto_gen_a", - "root//buck_tests_2/generated:generated_headers", - ], - includes = glob( - ["include/*.hrl"], - exclude = ["include/junk.hrl"], - ), - version = "1.0.0", -) diff --git a/test/test_projects/codegen_test/BUCK b/test/test_projects/codegen_test/BUCK deleted file mode 100644 index 1df5f86eba..0000000000 --- a/test/test_projects/codegen_test/BUCK +++ /dev/null @@ -1,73 +0,0 @@ -oncall("vscode_erlang") - -# Code generation rule - generates Erlang modules from template files -genrule( - name = "example_service_types_erl", - srcs = [ - "templates/example_service_types.erl", - ], - outs = { - "example_service_types.erl": ["example_service_types.erl"], - }, - cmd = "cp $SRCDIR/templates/example_service_types.erl $OUT/example_service_types.erl", -) - -genrule( - name = "example_service_client_erl", - srcs = [ - "templates/example_service_client.erl", - ], - outs = { - "example_service_client.erl": ["example_service_client.erl"], - }, - cmd = "cp $SRCDIR/templates/example_service_client.erl $OUT/example_service_client.erl", -) - -genrule( - name = "example_service_types_hrl", - srcs = [ - "templates/example_service_types.hrl", - ], - outs = { - "example_service_types.hrl": ["example_service_types.hrl"], - }, - cmd = "cp $SRCDIR/templates/example_service_types.hrl $OUT/example_service_types.hrl", -) - -# Erlang library containing only the generated code -erlang_app( - name = "example_service_generated", - srcs = [ - # Include generated Erlang modules from genrule output - ":example_service_types_erl[example_service_types.erl]", - ":example_service_client_erl[example_service_client.erl]", - ], - includes = [ - # Include generated header files from genrule output - ":example_service_types_hrl[example_service_types.hrl]", - ], -) - -# Erlang application that uses the generated code (non-generated files only) -erlang_application( - name = "codegen_test_app", - srcs = glob(["app_a/src/*.erl"]), - app_name = "codegen_test", - app_src = "app_a/src/codegen_test.app.src", - applications = [ - "kernel", - "stdlib", - ":example_service_generated", - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -# Test to verify the generated code works -erlang_tests( - suites = [ - "app_a/test/codegen_test_SUITE.erl", - ], - deps = [":codegen_test_app"], -) diff --git a/test/test_projects/codegen_test/README.md b/test/test_projects/codegen_test/README.md deleted file mode 100644 index 1f73475d9d..0000000000 --- a/test/test_projects/codegen_test/README.md +++ /dev/null @@ -1,138 +0,0 @@ -# Code Generation Test Project - -This test project demonstrates Buck2-based code generation for Erlang -applications using `genrule`. - -## Project Structure - -``` -codegen_test/ -├── .elp.toml # ELP configuration -├── BUCK # Buck build configuration with genrule -├── README.md # This file -├── templates/ # Erlang template files (input) -│ ├── example_service_types.erl # Type definitions template -│ ├── example_service_client.erl # Client stubs template -│ └── example_service_types.hrl # Header file template -├── generated/ # Pre-generated code (for reference) -│ ├── example_service_types.erl # Generated type module -│ ├── example_service_client.erl # Generated client stubs -│ └── example_service_types.hrl # Generated header file -└── app_a/ - ├── src/ - │ ├── codegen_test.app.src # Application metadata - │ └── example_usage.erl # Example using generated code - └── test/ - └── codegen_test_SUITE.erl # Test suite -``` - -## How It Works - -### 1. Template Files - -The templates directory contains well-formed Erlang files that serve as input to -the code generation process. These are complete, valid Erlang files that are -copied to the output directory during the build. - -### 2. Code Generation - -The code is generated automatically during the build process using a -`genrule`: - -```python -genrule( - name = "example_service_types_erl", - srcs = [ - "templates/example_service_types.erl", - ], - outs = { - "example_service_types.erl": ["example_service_types.erl"], - }, - cmd = "cp $SRCDIR/templates/example_service_types.erl $OUT/example_service_types.erl", -) -``` - -The genrule: - -- Takes the template file as input (`srcs`) -- Defines named outputs using `outs` parameter (creates subtargets for each - file) -- Uses `cp` command to copy template files to `$OUT` -- Outputs files to `$OUT` directory in `buck-out/` - -### 3. Build Integration - -The `BUCK` file references the generated files using subtarget syntax: - -```python -erlang_app( - name = "example_service_generated", - srcs = [ - ":example_service_types_erl[example_service_types.erl]", - ":example_service_client_erl[example_service_client.erl]", - ], - includes = [ - ":example_service_types_hrl[example_service_types.hrl]", - ], -) -``` - -When Buck builds the application: - -1. The genrule runs first, copying the template Erlang files to the output -2. The generated files are placed in - `buck-out/v2/gen/.../example_service_types_erl/` -3. The `erlang_app` consumes these files via subtarget references (`[filename]` - syntax) -4. The files are copied to the application's build directory in `buck-out/` - -### 4. Using Generated Code - -Application code includes the generated header and uses the types: - -```erlang --module(example_usage). --include("example_service_types.hrl"). - -create_sample_user() -> - #user_info{ - user_id = <<"user_123">>, - username = <<"john_doe">>, - age = 25, - is_active = true - }. - -get_user_by_id(UserId) -> - example_service_client:get_user(UserId). -``` - -## Building and Testing - -```bash -# Build just the code generation step -buck2 build fbcode//whatsapp/elp/test/test_projects/codegen_test:example_service_types_erl - -# Build the application (automatically runs code generation) -buck2 build fbcode//whatsapp/elp/test/test_projects/codegen_test:codegen_test_app - -# Run tests -buck2 test fbcode//whatsapp/elp/test/test_projects/codegen_test:codegen_test_SUITE - -# View generated files in buck-out -find buck-out -path "*codegen_test*" -name "example_service_*.erl" -``` - -## Test Coverage - -The test suite (`app_a/test/codegen_test_SUITE.erl`) verifies: - -- Generated record types work correctly -- Generated client functions are callable -- Record fields have correct types and defaults -- Integration with application code - -All tests pass: - -``` -Tests finished: Pass 3. Fail 0. Fatal 0. Skip 0. Build failure 0 -``` diff --git a/test/test_projects/codegen_test/app_a/src/codegen_test.app.src b/test/test_projects/codegen_test/app_a/src/codegen_test.app.src deleted file mode 100644 index 7a38d49a24..0000000000 --- a/test/test_projects/codegen_test/app_a/src/codegen_test.app.src +++ /dev/null @@ -1,14 +0,0 @@ -{application, codegen_test, - [{description, "Test application demonstrating code generation"}, - {vsn, "1.0.0"}, - {registered, []}, - {applications, - [kernel, - stdlib, - example_service_generated - ]}, - {env,[]}, - {modules, []}, - {licenses, ["Apache 2.0"]}, - {links, []} - ]}. diff --git a/test/test_projects/codegen_test/app_a/src/example_usage.erl b/test/test_projects/codegen_test/app_a/src/example_usage.erl deleted file mode 100644 index a624c2089b..0000000000 --- a/test/test_projects/codegen_test/app_a/src/example_usage.erl +++ /dev/null @@ -1,51 +0,0 @@ --module(example_usage). --compile([warn_missing_spec_all]). --moduledoc """ -Example module that demonstrates using generated code. -This module uses the types and client functions generated from -the example_service.schema file. -""". - -%% Include the generated header file --include_lib("example_service_generated/include/example_service_types.hrl"). - -%% API exports --export([ - create_sample_user/0, - create_query_request/1, - get_user_by_id/1 -]). - -%%%=================================================================== -%%% API -%%%=================================================================== - --doc """ -Creates a sample user_info record using generated types -""". --spec create_sample_user() -> #user_info{}. -create_sample_user() -> - #user_info{ - user_id = <<"user_123">>, - username = <<"john_doe">>, - age = 25, - is_active = true - }. - --doc """ -Creates a query_request record -""". --spec create_query_request(binary()) -> #query_request{}. -create_query_request(QueryId) -> - #query_request{ - query_id = QueryId, - filters = [{age, greater_than, 18}] - }. - --doc """ -Uses the generated client to get user information -""". --spec get_user_by_id(binary()) -> {ok, term()} | {error, term()}. -get_user_by_id(UserId) -> - %% This calls the generated client function - example_service_client:get_user(UserId). diff --git a/test/test_projects/codegen_test/app_a/test/codegen_test_SUITE.erl b/test/test_projects/codegen_test/app_a/test/codegen_test_SUITE.erl deleted file mode 100644 index 3c0135dcee..0000000000 --- a/test/test_projects/codegen_test/app_a/test/codegen_test_SUITE.erl +++ /dev/null @@ -1,73 +0,0 @@ -%%% Test suite for code generation functionality --module(codegen_test_SUITE). - --include_lib("stdlib/include/assert.hrl"). --include("example_service_types.hrl"). - -%% CT callbacks --export([all/0, init_per_suite/1, end_per_suite/1]). - -%% Test cases --export([ - test_generated_types/1, - test_generated_client/1, - test_user_record_creation/1 -]). - -%%%=================================================================== -%%% CT Callbacks -%%%=================================================================== - -all() -> - [ - test_generated_types, - test_generated_client, - test_user_record_creation - ]. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -%%%=================================================================== -%%% Test Cases -%%%=================================================================== - -test_generated_types(_Config) -> - %% Test that we can create a user_info record - User = #user_info{ - user_id = <<"test_123">>, - username = <<"testuser">>, - age = 30, - is_active = true - }, - - %% Verify the record fields - ?assertEqual(<<"test_123">>, User#user_info.user_id), - ?assertEqual(<<"testuser">>, User#user_info.username), - ?assertEqual(30, User#user_info.age), - ?assertEqual(true, User#user_info.is_active), - - ok. - -test_generated_client(_Config) -> - %% Test that the generated client module exists and can be called - Result = example_service_client:get_user(<<"user_123">>), - - %% The generated stub returns {ok, generated_response} - ?assertMatch({ok, _}, Result), - - ok. - -test_user_record_creation(_Config) -> - %% Test the example_usage module - User = example_usage:create_sample_user(), - - %% Verify it's a valid user_info record - ?assertMatch(#user_info{}, User), - ?assertEqual(<<"user_123">>, User#user_info.user_id), - ?assertEqual(25, User#user_info.age), - - ok. diff --git a/test/test_projects/codegen_test/generated/example_service_client.erl b/test/test_projects/codegen_test/generated/example_service_client.erl deleted file mode 100644 index 6b38c39425..0000000000 --- a/test/test_projects/codegen_test/generated/example_service_client.erl +++ /dev/null @@ -1,37 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @doc -%%% Auto-generated client for example_service -%%% DO NOT EDIT - Generated by generate_erlang.sh -%%% @end -%%%------------------------------------------------------------------- --module(example_service_client). - --include("example_service_types.hrl"). - -%% API exports --export([get_user/1]). --export([query_users/1]). --export([update_user/2]). - -%%%=================================================================== -%%% API -%%%=================================================================== - - -%% @doc Retrieves user information by user ID --spec get_user(term()) -> {ok, term()} | {error, term()}. -get_user(_UserId) -> - %% Auto-generated client stub - {ok, generated_response}. - -%% @doc Queries users with given filters --spec query_users(term()) -> {ok, term()} | {error, term()}. -query_users(_Request) -> - %% Auto-generated client stub - {ok, generated_response}. - -%% @doc Updates user information --spec update_user(term(), term()) -> {ok, term()} | {error, term()}. -update_user(_UserId, _UserInfo) -> - %% Auto-generated client stub - {ok, generated_response}. diff --git a/test/test_projects/codegen_test/generated/example_service_types.erl b/test/test_projects/codegen_test/generated/example_service_types.erl deleted file mode 100644 index 3f89adcba9..0000000000 --- a/test/test_projects/codegen_test/generated/example_service_types.erl +++ /dev/null @@ -1,55 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @doc -%%% Auto-generated type definitions for example_service -%%% DO NOT EDIT - Generated by generate_erlang.sh -%%% @end -%%%------------------------------------------------------------------- --module(example_service_types). - -%% API exports --export([new_user_info/0]). --export([new_query_request/0]). --export([new_query_response/0]). --export([get_version/0]). - -%% Type exports --export_type([user_info/0]). --export_type([query_request/0]). --export_type([query_response/0]). - -%% Record definitions --record(user_info, {user_id = <<>>, username = <<>>, age = 0, is_active = false}). --record(query_request, {query_id = <<>>, filters = []}). --record(query_response, {results = [], count = 0}). - -%% Type definitions --type user_info() :: #user_info{}. --type query_request() :: #query_request{}. --type query_response() :: #query_response{}. - -%%%=================================================================== -%%% API -%%%=================================================================== - -%% @doc Returns the schema version --spec get_version() -> binary(). -get_version() -> - <<"1.0.0">>. - - -%% @doc Creates a new user_info record --spec new_user_info() -> #user_info{}. -new_user_info() -> - #user_info{}. - - -%% @doc Creates a new query_request record --spec new_query_request() -> #query_request{}. -new_query_request() -> - #query_request{}. - - -%% @doc Creates a new query_response record --spec new_query_response() -> #query_response{}. -new_query_response() -> - #query_response{}. diff --git a/test/test_projects/codegen_test/generated/example_service_types.hrl b/test/test_projects/codegen_test/generated/example_service_types.hrl deleted file mode 100644 index 4c957a0906..0000000000 --- a/test/test_projects/codegen_test/generated/example_service_types.hrl +++ /dev/null @@ -1,27 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @doc -%%% Auto-generated header file for example_service -%%% DO NOT EDIT - Generated by generate_erlang.sh -%%% @end -%%%------------------------------------------------------------------- - - --record(user_info, { - - user_id = <<>> :: binary(), - username = <<>> :: binary(), - age = 0 :: integer(), - is_active = false :: boolean() -}). - --record(query_request, { - - query_id = <<>> :: binary(), - filters = [] :: list() -}). - --record(query_response, { - - results = [] :: list(), - count = 0 :: integer() -}). diff --git a/test/test_projects/codegen_test/templates/example_service_client.erl b/test/test_projects/codegen_test/templates/example_service_client.erl deleted file mode 100644 index ab30a89f74..0000000000 --- a/test/test_projects/codegen_test/templates/example_service_client.erl +++ /dev/null @@ -1,38 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @doc -%%% Auto-generated client for example_service -%%% DO NOT EDIT - Generated by generate_erlang.sh -%%% @end -%%%------------------------------------------------------------------- --module(example_service_client). - --include("example_service_types.hrl"). - -%% API exports --export([get_user/1]). --export([query_users/1]). --export([update_user/2]). - -%%%=================================================================== -%%% API -%%%=================================================================== - - -%% @doc Retrieves user information by user ID --spec get_user(term()) -> {ok, term()} | {error, term()}. -get_user(_UserId) -> - %% Auto-generated client stub - {ok, generated_response}. - -%% @doc Queries users with given filters --spec query_users(term()) -> {ok, term()} | {error, term()}. -query_users(_Request) -> - %% Auto-generated client stub - {ok, generated_response}. - -%% @doc Updates user information --spec update_user(term(), term()) -> {ok, term()} | {error, term()}. -update_user(_UserId, _UserInfo) -> - %% Auto-generated client stub - {ok, generated_response}. - diff --git a/test/test_projects/codegen_test/templates/example_service_types.erl b/test/test_projects/codegen_test/templates/example_service_types.erl deleted file mode 100644 index 833df167c6..0000000000 --- a/test/test_projects/codegen_test/templates/example_service_types.erl +++ /dev/null @@ -1,56 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @doc -%%% Auto-generated type definitions for example_service -%%% DO NOT EDIT - Generated by generate_erlang.sh -%%% @end -%%%------------------------------------------------------------------- --module(example_service_types). - -%% API exports --export([new_user_info/0]). --export([new_query_request/0]). --export([new_query_response/0]). --export([get_version/0]). - -%% Type exports --export_type([user_info/0]). --export_type([query_request/0]). --export_type([query_response/0]). - -%% Record definitions --record(user_info, {user_id = <<>>, username = <<>>, age = 0, is_active = false}). --record(query_request, {query_id = <<>>, filters = []}). --record(query_response, {results = [], count = 0}). - -%% Type definitions --type user_info() :: #user_info{}. --type query_request() :: #query_request{}. --type query_response() :: #query_response{}. - -%%%=================================================================== -%%% API -%%%=================================================================== - -%% @doc Returns the schema version --spec get_version() -> binary(). -get_version() -> - <<"1.0.0">>. - - -%% @doc Creates a new user_info record --spec new_user_info() -> #user_info{}. -new_user_info() -> - #user_info{}. - - -%% @doc Creates a new query_request record --spec new_query_request() -> #query_request{}. -new_query_request() -> - #query_request{}. - - -%% @doc Creates a new query_response record --spec new_query_response() -> #query_response{}. -new_query_response() -> - #query_response{}. - diff --git a/test/test_projects/codegen_test/templates/example_service_types.hrl b/test/test_projects/codegen_test/templates/example_service_types.hrl deleted file mode 100644 index 88a2e7aed2..0000000000 --- a/test/test_projects/codegen_test/templates/example_service_types.hrl +++ /dev/null @@ -1,28 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @doc -%%% Auto-generated header file for example_service -%%% DO NOT EDIT - Generated by generate_erlang.sh -%%% @end -%%%------------------------------------------------------------------- - - --record(user_info, { - - user_id = <<>> :: binary(), - username = <<>> :: binary(), - age = 0 :: integer(), - is_active = false :: boolean() -}). - --record(query_request, { - - query_id = <<>> :: binary(), - filters = [] :: list() -}). - --record(query_response, { - - results = [] :: list(), - count = 0 :: integer() -}). - diff --git a/test/test_projects/diagnostics/.elp.toml b/test/test_projects/diagnostics/.elp.toml deleted file mode 100644 index 504ef547af..0000000000 --- a/test/test_projects/diagnostics/.elp.toml +++ /dev/null @@ -1,8 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//diagnostics/..." ] -source_root = "diagnostics" - -[eqwalizer] -enable_all = false diff --git a/test/test_projects/diagnostics/BUCK b/test/test_projects/diagnostics/BUCK deleted file mode 100644 index 19c15e5acf..0000000000 --- a/test/test_projects/diagnostics/BUCK +++ /dev/null @@ -1,20 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "diagnostics_app_a_target", - srcs = glob(["app_a/src/*.erl"]), - app_name = "diagnostics_app_a", - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "app_a/test/app_a_SUITE.erl", - ], - deps = [":diagnostics_app_a_target"], -) diff --git a/test/test_projects/end_to_end/.elp.toml b/test/test_projects/end_to_end/.elp.toml deleted file mode 100644 index acbcd6146f..0000000000 --- a/test/test_projects/end_to_end/.elp.toml +++ /dev/null @@ -1,7 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = ["root//end_to_end/..."] - -[eqwalizer] -enable_all = false diff --git a/test/test_projects/end_to_end/assist_examples/BUCK b/test/test_projects/end_to_end/assist_examples/BUCK deleted file mode 100644 index 60d39de125..0000000000 --- a/test/test_projects/end_to_end/assist_examples/BUCK +++ /dev/null @@ -1,14 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "assist_examples", - srcs = glob([ - "src/*.erl", - ]), - app_src = "src/assist_examples.app.src", - applications = [], - includes = [], - labels = ["user_application"], - version = "1.0.0", - visibility = ["PUBLIC"], -) diff --git a/test/test_projects/end_to_end/definitions/BUCK b/test/test_projects/end_to_end/definitions/BUCK deleted file mode 100644 index c9e6b204f4..0000000000 --- a/test/test_projects/end_to_end/definitions/BUCK +++ /dev/null @@ -1,14 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "definitions", - srcs = glob([ - "src/*.erl", - ]), - app_src = "src/definitions.app.src", - applications = [], - includes = [], - labels = ["user_application"], - version = "1.0.0", - visibility = ["PUBLIC"], -) diff --git a/test/test_projects/end_to_end/docs/BUCK b/test/test_projects/end_to_end/docs/BUCK deleted file mode 100644 index 7429863b6e..0000000000 --- a/test/test_projects/end_to_end/docs/BUCK +++ /dev/null @@ -1,16 +0,0 @@ -load("@waserver//buck2/whatsapp:erlang.bzl", "erlang_application") - -oncall("vscode_erlang") - -erlang_application( - name = "docs", - srcs = glob([ - "src/*.erl", - ]), - app_src = "src/docs.app.src", - applications = [], - includes = [], - labels = ["user_application"], - version = "1.0.0", - visibility = ["PUBLIC"], -) diff --git a/test/test_projects/end_to_end/hover/BUCK b/test/test_projects/end_to_end/hover/BUCK deleted file mode 100644 index 7732dc473e..0000000000 --- a/test/test_projects/end_to_end/hover/BUCK +++ /dev/null @@ -1,14 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "hover", - srcs = glob([ - "src/*.erl", - ]), - app_src = "src/hover.app.src", - applications = [], - includes = [], - labels = ["user_application"], - version = "1.0.0", - visibility = ["PUBLIC"], -) diff --git a/test/test_projects/end_to_end/single_errors/BUCK b/test/test_projects/end_to_end/single_errors/BUCK deleted file mode 100644 index a8f6e478b0..0000000000 --- a/test/test_projects/end_to_end/single_errors/BUCK +++ /dev/null @@ -1,14 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "single_errors", - srcs = glob([ - "src/*.erl", - ]), - app_src = "src/single_errors.app.src", - applications = [], - includes = [], - labels = ["user_application"], - version = "1.0.0", - visibility = ["PUBLIC"], -) diff --git a/test/test_projects/eqwalizer_callers/.elp.toml b/test/test_projects/eqwalizer_callers/.elp.toml deleted file mode 100644 index 68476bcf2e..0000000000 --- a/test/test_projects/eqwalizer_callers/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//eqwalizer_callers/..." ] -source_root = "eqwalizer_callers" diff --git a/test/test_projects/eqwalizer_callers/BUCK b/test/test_projects/eqwalizer_callers/BUCK deleted file mode 100644 index 32012a0dc0..0000000000 --- a/test/test_projects/eqwalizer_callers/BUCK +++ /dev/null @@ -1,19 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "app_a/test/app_a_SUITE.erl", - ], - deps = [":app_a"], -) diff --git a/test/test_projects/eqwalizer_tests/.elp.toml b/test/test_projects/eqwalizer_tests/.elp.toml deleted file mode 100644 index 5dac3aa6a6..0000000000 --- a/test/test_projects/eqwalizer_tests/.elp.toml +++ /dev/null @@ -1,8 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//eqwalizer_tests/..." ] -source_root = "eqwalizer_tests" - -[eqwalizer] -enable_all = true diff --git a/test/test_projects/eqwalizer_tests/BUCK b/test/test_projects/eqwalizer_tests/BUCK deleted file mode 100644 index 0817873cb0..0000000000 --- a/test/test_projects/eqwalizer_tests/BUCK +++ /dev/null @@ -1,77 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "check", - srcs = glob(["check/src/**/*.erl"]), - applications = [":eqwalizer"], - includes = glob([ - "check/include/*.hrl", - "eqwalizer/include/*.hrl", - ]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "check_gradual", - srcs = glob(["check_gradual/src/*.erl"]), - applications = [":eqwalizer"], - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "check/test/check_SUITE.erl", - ], - deps = [":check"], -) - -erlang_application( - name = "debug", - srcs = glob(["debug/src/*.erl"]), - applications = [":eqwalizer"], - includes = glob(["debug/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "elm_core", - srcs = glob(["elm_core/src/*.erl"]), - applications = [":eqwalizer"], - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "eqwater", - srcs = glob(["eqwater/src/*.erl"]), - applications = [":eqwalizer"], - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "fault_tolerance", - srcs = glob(["fault_tolerance/src/*.erl"]), - applications = [":eqwalizer"], - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "options", - srcs = glob(["options/src/*.erl"]), - applications = [":eqwalizer"], - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "eqwalizer", - srcs = glob(["eqwalizer/src/*.erl"]), - includes = glob(["eqwalizer/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/hierarchical_config/.elp.toml b/test/test_projects/hierarchical_config/.elp.toml deleted file mode 100644 index e4d04eb6e0..0000000000 --- a/test/test_projects/hierarchical_config/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//hierarchical_config/..." ] -source_root = "hierarchical_config" diff --git a/test/test_projects/hierarchical_config/.elp_lint.toml b/test/test_projects/hierarchical_config/.elp_lint.toml deleted file mode 100644 index 6cc536f399..0000000000 --- a/test/test_projects/hierarchical_config/.elp_lint.toml +++ /dev/null @@ -1,5 +0,0 @@ -enabled_lints = [] -disabled_lints = [ - "W0012", - "W0046" -] diff --git a/test/test_projects/hierarchical_config/BUCK b/test/test_projects/hierarchical_config/BUCK deleted file mode 100644 index bc78a42d57..0000000000 --- a/test/test_projects/hierarchical_config/BUCK +++ /dev/null @@ -1,23 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_b", - srcs = glob(["app_b/src/*.erl"]), - app_src = "app_b/src/app_b.app.src", - applications = [ - ], - includes = glob(["app_b/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/hierarchical_config/app_a/.elp_lint.toml b/test/test_projects/hierarchical_config/app_a/.elp_lint.toml deleted file mode 100644 index 7445514e73..0000000000 --- a/test/test_projects/hierarchical_config/app_a/.elp_lint.toml +++ /dev/null @@ -1,4 +0,0 @@ -enabled_lints = [] -disabled_lints = [ - "W0002" -] diff --git a/test/test_projects/hierarchical_config/app_a/src/app_a.erl b/test/test_projects/hierarchical_config/app_a/src/app_a.erl deleted file mode 100644 index 5b856d4f02..0000000000 --- a/test/test_projects/hierarchical_config/app_a/src/app_a.erl +++ /dev/null @@ -1,7 +0,0 @@ --module(app_a). - --define(MACRO_A, 1). --define(MACRO_B, 1). - -main() -> - ?MACRO_A. diff --git a/test/test_projects/hierarchical_config/app_b/src/app_b.erl b/test/test_projects/hierarchical_config/app_b/src/app_b.erl deleted file mode 100644 index ad2453d0de..0000000000 --- a/test/test_projects/hierarchical_config/app_b/src/app_b.erl +++ /dev/null @@ -1,7 +0,0 @@ --module(app_b). - --define(MACRO_A, 1). --define(MACRO_B, 1). - -main() -> - ?MACRO_A. diff --git a/test/test_projects/hierarchical_config/rebar.config b/test/test_projects/hierarchical_config/rebar.config deleted file mode 100644 index 2dcacbc5b3..0000000000 --- a/test/test_projects/hierarchical_config/rebar.config +++ /dev/null @@ -1,7 +0,0 @@ -{project_app_dirs, [ - "app_a", - "app_b" -]}. - -{erl_opts, [debug_info]}. -{deps, []}. diff --git a/test/test_projects/in_place_tests/.elp.toml b/test/test_projects/in_place_tests/.elp.toml deleted file mode 100644 index 70edcc3f03..0000000000 --- a/test/test_projects/in_place_tests/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//in_place_tests/..." ] -source_root = "in_place_tests" diff --git a/test/test_projects/in_place_tests/BUCK b/test/test_projects/in_place_tests/BUCK deleted file mode 100644 index f4f354e7ee..0000000000 --- a/test/test_projects/in_place_tests/BUCK +++ /dev/null @@ -1,19 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "in_place_tests_app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "app_a/test/app_a_SUITE.erl", - ], - deps = [":in_place_tests_app_a"], -) diff --git a/test/test_projects/include_lib_dependency_test/.elp.toml b/test/test_projects/include_lib_dependency_test/.elp.toml deleted file mode 100644 index 9d1c859339..0000000000 --- a/test/test_projects/include_lib_dependency_test/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//include_lib_dependency_test/..." ] -source_root = "include_lib_dependency_test" diff --git a/test/test_projects/include_lib_dependency_test/BUCK b/test/test_projects/include_lib_dependency_test/BUCK deleted file mode 100644 index 54b81c47b5..0000000000 --- a/test/test_projects/include_lib_dependency_test/BUCK +++ /dev/null @@ -1,43 +0,0 @@ -oncall("vscode_erlang") - -# Main application that will try to include_lib from an app it doesn't depend on -erlang_application( - name = "main_app", - srcs = glob(["main_app/src/*.erl"]), - app_src = "main_app/src/main_app.app.src", - applications = [ - # Note: deliberately NOT including :external_app as a dependency - "root//include_lib_dependency_test:normal_dep", - ], - extra_includes = ["root//include_lib_dependency_test:extra_app"], - labels = ["user_application"], - version = "1.0.0", -) - -# External application that main_app will try to include_lib from -erlang_application( - name = "external_app", - srcs = glob(["external_app/src/*.erl"]), - app_src = "external_app/src/external_app.app.src", - includes = glob(["external_app/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "extra_app", - srcs = glob(["extra_app/src/*.erl"]), - app_src = "extra_app/src/extra_app.app.src", - includes = glob(["extra_app/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "normal_dep", - srcs = glob(["normal_dep/src/*.erl"]), - app_src = "normal_dep/src/normal_dep.app.src", - includes = glob(["normal_dep/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/linter/.elp.toml b/test/test_projects/linter/.elp.toml deleted file mode 100644 index 4820625b2d..0000000000 --- a/test/test_projects/linter/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//linter/..." ] -source_root = "linter" diff --git a/test/test_projects/linter/BUCK b/test/test_projects/linter/BUCK deleted file mode 100644 index 2db8750582..0000000000 --- a/test/test_projects/linter/BUCK +++ /dev/null @@ -1,41 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_b", - srcs = glob(["app_b/src/*.erl"]), - app_src = "app_b/src/app_b.app.src", - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "app_a/test/app_a_SUITE.erl", - ], - deps = [":app_a"], -) - -erlang_application( - name = "app_a_test_utils", - srcs = [ - "app_a/test/app_a_test_helpers.erl", - "app_a/test/app_a_test_helpers_not_opted_in.erl", - "app_a/test/app_test_helpers_no_errors.erl", - ], - applications = [":app_a"], - labels = [ - "test_application", - "test_utils", - ], -) diff --git a/test/test_projects/linter_bad_config/.elp.toml b/test/test_projects/linter_bad_config/.elp.toml deleted file mode 100644 index 4820625b2d..0000000000 --- a/test/test_projects/linter_bad_config/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//linter/..." ] -source_root = "linter" diff --git a/test/test_projects/linter_bad_config/BUCK b/test/test_projects/linter_bad_config/BUCK deleted file mode 100644 index a0817a6ad6..0000000000 --- a/test/test_projects/linter_bad_config/BUCK +++ /dev/null @@ -1,12 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/linter_bad_config/linter/.elp.toml b/test/test_projects/linter_bad_config/linter/.elp.toml deleted file mode 100644 index 4820625b2d..0000000000 --- a/test/test_projects/linter_bad_config/linter/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//linter/..." ] -source_root = "linter" diff --git a/test/test_projects/linter_bad_config/linter/BUCK b/test/test_projects/linter_bad_config/linter/BUCK deleted file mode 100644 index 2db8750582..0000000000 --- a/test/test_projects/linter_bad_config/linter/BUCK +++ /dev/null @@ -1,41 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_b", - srcs = glob(["app_b/src/*.erl"]), - app_src = "app_b/src/app_b.app.src", - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "app_a/test/app_a_SUITE.erl", - ], - deps = [":app_a"], -) - -erlang_application( - name = "app_a_test_utils", - srcs = [ - "app_a/test/app_a_test_helpers.erl", - "app_a/test/app_a_test_helpers_not_opted_in.erl", - "app_a/test/app_test_helpers_no_errors.erl", - ], - applications = [":app_a"], - labels = [ - "test_application", - "test_utils", - ], -) diff --git a/test/test_projects/linter_config/.elp.toml b/test/test_projects/linter_config/.elp.toml deleted file mode 100644 index c490cc155e..0000000000 --- a/test/test_projects/linter_config/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//linter_config/..." ] -source_root = "linter_config" diff --git a/test/test_projects/linter_config/.elp_lint.toml b/test/test_projects/linter_config/.elp_lint.toml deleted file mode 100644 index 47886dd507..0000000000 --- a/test/test_projects/linter_config/.elp_lint.toml +++ /dev/null @@ -1,5 +0,0 @@ -[linters.L1260] # Unused record, produced by the Erlang Service -exclude_apps = ["app_b", "app_c"] - -[linters.unused_macro] -exclude_apps = ["app_c"] diff --git a/test/test_projects/linter_config/BUCK b/test/test_projects/linter_config/BUCK deleted file mode 100644 index c1101daea2..0000000000 --- a/test/test_projects/linter_config/BUCK +++ /dev/null @@ -1,25 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_b", - srcs = glob(["app_b/src/*.erl"]), - app_src = "app_b/src/app_b.app.src", - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_c", - srcs = glob(["app_c/src/*.erl"]), - app_src = "app_c/src/app_c.app.src", - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/linter_config/app_a/src/app_a.app.src b/test/test_projects/linter_config/app_a/src/app_a.app.src deleted file mode 100644 index 1381435a46..0000000000 --- a/test/test_projects/linter_config/app_a/src/app_a.app.src +++ /dev/null @@ -1,3 +0,0 @@ -{application, app_a, - [{description, "example app A"}, {vsn, "inplace"}, {applications, [kernel, stdlib]}] -}. diff --git a/test/test_projects/linter_config/app_a/src/app_a.erl b/test/test_projects/linter_config/app_a/src/app_a.erl deleted file mode 100644 index c374c0b518..0000000000 --- a/test/test_projects/linter_config/app_a/src/app_a.erl +++ /dev/null @@ -1,4 +0,0 @@ --module(app_a). - --define(MACRO_A, a). --record(rec_a, {a :: atom()}). diff --git a/test/test_projects/linter_config/app_b/src/app_b.app.src b/test/test_projects/linter_config/app_b/src/app_b.app.src deleted file mode 100644 index 4112b4129f..0000000000 --- a/test/test_projects/linter_config/app_b/src/app_b.app.src +++ /dev/null @@ -1,3 +0,0 @@ -{application, app_b, - [{description, "example app B"}, {vsn, "inplace"}, {applications, [kernel, stdlib]}] -}. diff --git a/test/test_projects/linter_config/app_b/src/app_b.erl b/test/test_projects/linter_config/app_b/src/app_b.erl deleted file mode 100644 index ca7ecf985b..0000000000 --- a/test/test_projects/linter_config/app_b/src/app_b.erl +++ /dev/null @@ -1,4 +0,0 @@ --module(app_b). - --define(MACRO_B, b). --record(rec_b, {b :: atom()}). diff --git a/test/test_projects/linter_config/app_c/src/app_c.app.src b/test/test_projects/linter_config/app_c/src/app_c.app.src deleted file mode 100644 index c278bbce23..0000000000 --- a/test/test_projects/linter_config/app_c/src/app_c.app.src +++ /dev/null @@ -1,3 +0,0 @@ -{application, app_c, - [{description, "example app C"}, {vsn, "inplace"}, {applications, [kernel, stdlib]}] -}. diff --git a/test/test_projects/linter_config/app_c/src/app_c.erl b/test/test_projects/linter_config/app_c/src/app_c.erl deleted file mode 100644 index 57573554b6..0000000000 --- a/test/test_projects/linter_config/app_c/src/app_c.erl +++ /dev/null @@ -1,4 +0,0 @@ --module(app_c). - --define(MACRO_C, c). --record(rec_c, {c :: atom()}). diff --git a/test/test_projects/linter_config/rebar.config b/test/test_projects/linter_config/rebar.config deleted file mode 100644 index d508bd24de..0000000000 --- a/test/test_projects/linter_config/rebar.config +++ /dev/null @@ -1,9 +0,0 @@ -{checkouts_dir, ["."]}. -{project_app_dirs, [ - "app_a", - "app_b", - "app_c" -]}. - -{erl_opts, [debug_info]}. -{deps, []}. diff --git a/test/test_projects/parse_error/.elp.toml b/test/test_projects/parse_error/.elp.toml deleted file mode 100644 index 1a06a42f0d..0000000000 --- a/test/test_projects/parse_error/.elp.toml +++ /dev/null @@ -1,8 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//parse_error/..." ] -source_root = "parse_error" - -[eqwalizer] -enable_all = false diff --git a/test/test_projects/parse_error/BUCK b/test/test_projects/parse_error/BUCK deleted file mode 100644 index ed65c267d0..0000000000 --- a/test/test_projects/parse_error/BUCK +++ /dev/null @@ -1,9 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "elp_test_parse_a", - srcs = glob(["parse_error_a/src/*.erl"]), - app_src = "parse_error_a/src/parse_error_a.app.src", - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/standard/.elp.toml b/test/test_projects/standard/.elp.toml deleted file mode 100644 index f5e2ac1943..0000000000 --- a/test/test_projects/standard/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//standard/..." ] -source_root = "standard" diff --git a/test/test_projects/standard/BUCK b/test/test_projects/standard/BUCK deleted file mode 100644 index 3f1e9ee947..0000000000 --- a/test/test_projects/standard/BUCK +++ /dev/null @@ -1,49 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "elp_test_standard_app_b", - srcs = glob(["app_b/src/*.erl"]), - app_src = "app_b/src/app_b.app.src", - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "elp_test_eqwalizer", - srcs = glob(["eqwalizer/src/*.erl"]), - app_src = "eqwalizer/src/eqwalizer.app.src", - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "app_a/test/app_a_SUITE.erl", - ], - deps = [":app_a"], -) - -erlang_application( - name = "app_a_test_utils", - srcs = [ - "app_a/test/app_a_test_helpers.erl", - "app_a/test/app_a_test_helpers_not_opted_in.erl", - "app_a/test/app_test_helpers_no_errors.erl", - ], - applications = [":app_a"], - labels = [ - "test_application", - "test_utils", - ], -) diff --git a/test/test_projects/standard/app_a/src/app_a.app.src b/test/test_projects/standard/app_a/src/app_a.app.src deleted file mode 100644 index 1381435a46..0000000000 --- a/test/test_projects/standard/app_a/src/app_a.app.src +++ /dev/null @@ -1,3 +0,0 @@ -{application, app_a, - [{description, "example app A"}, {vsn, "inplace"}, {applications, [kernel, stdlib]}] -}. diff --git a/test/test_projects/standard/app_b/src/app_b.app.src b/test/test_projects/standard/app_b/src/app_b.app.src deleted file mode 100644 index 4112b4129f..0000000000 --- a/test/test_projects/standard/app_b/src/app_b.app.src +++ /dev/null @@ -1,3 +0,0 @@ -{application, app_b, - [{description, "example app B"}, {vsn, "inplace"}, {applications, [kernel, stdlib]}] -}. diff --git a/test/test_projects/toolchains/BUCK b/test/test_projects/toolchains/BUCK deleted file mode 100644 index 770ac61f67..0000000000 --- a/test/test_projects/toolchains/BUCK +++ /dev/null @@ -1,5 +0,0 @@ -load("@prelude//toolchains:demo.bzl", "system_demo_toolchains") - -oncall("vscode_erlang") - -system_demo_toolchains() diff --git a/test/test_projects/xref/.elp.toml b/test/test_projects/xref/.elp.toml deleted file mode 100644 index 87c2f17334..0000000000 --- a/test/test_projects/xref/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//xref/..." ] -source_root = "xref" diff --git a/test/test_projects/xref/BUCK b/test/test_projects/xref/BUCK deleted file mode 100644 index bf44968f02..0000000000 --- a/test/test_projects/xref/BUCK +++ /dev/null @@ -1,25 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - applications = [ - ":app_b", - ], - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_b", - srcs = glob(["app_b/src/*.erl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_c", - srcs = glob(["app_c/src/*.erl"]), - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/xref/app_a/src/unavailable_type.erl b/test/test_projects/xref/app_a/src/unavailable_type.erl deleted file mode 100644 index ddf4fc00d2..0000000000 --- a/test/test_projects/xref/app_a/src/unavailable_type.erl +++ /dev/null @@ -1,12 +0,0 @@ --module(unavailable_type). --export([test_types/0]). - --record(my_record, { - field_a :: app_b:my_type_b(), - field_b :: app_c:my_type_c(), - field_c :: binary() -}). - --spec test_types() -> {app_b:my_type_b(), app_c:my_type_c(), #my_record{}}. -test_types() -> - {"hello", 42, #my_record{field_a = "", field_b = 42, field_c = <<>>}}. diff --git a/test/test_projects/xref/app_b/src/app_b.erl b/test/test_projects/xref/app_b/src/app_b.erl deleted file mode 100644 index d56609b179..0000000000 --- a/test/test_projects/xref/app_b/src/app_b.erl +++ /dev/null @@ -1,8 +0,0 @@ --module(app_b). --export([my_function/0]). - --type my_type_b() :: string(). --export_type([my_type_b/0]). - --spec my_function() -> my_type_b(). -my_function() -> "hello from b". diff --git a/test/test_projects/xref/app_c/src/app_c.erl b/test/test_projects/xref/app_c/src/app_c.erl deleted file mode 100644 index 040f77f26f..0000000000 --- a/test/test_projects/xref/app_c/src/app_c.erl +++ /dev/null @@ -1,8 +0,0 @@ --module(app_c). --export([my_function/0]). - --type my_type_c() :: integer(). --export_type([my_type_c/0]). - --spec my_function() -> my_type_c(). -my_function() -> 42. diff --git a/test/test_projects/xref/elp_lint_unavailable_type.toml b/test/test_projects/xref/elp_lint_unavailable_type.toml deleted file mode 100644 index 629a5228bf..0000000000 --- a/test/test_projects/xref/elp_lint_unavailable_type.toml +++ /dev/null @@ -1,2 +0,0 @@ -[linters.unavailable_type] -enabled = true diff --git a/test/test_projects/.gitignore b/test_projects/.gitignore similarity index 85% rename from test/test_projects/.gitignore rename to test_projects/.gitignore index 2672c17cc4..b34578734c 100644 --- a/test/test_projects/.gitignore +++ b/test_projects/.gitignore @@ -3,4 +3,3 @@ *wa.build_info *_build/ *rebar.lock -buck-out/ diff --git a/test/test_projects/README.md b/test_projects/README.md similarity index 100% rename from test/test_projects/README.md rename to test_projects/README.md diff --git a/test_projects/buck_bad_config/.elp.toml b/test_projects/buck_bad_config/.elp.toml new file mode 100644 index 0000000000..a891a3dfc5 --- /dev/null +++ b/test_projects/buck_bad_config/.elp.toml @@ -0,0 +1,8 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/buck_bad_config/..." ] +source_root = "whatsapp/elp/test_projects/buck_bad_config" + +[eqwalizer] +enable_all = false diff --git a/test/test_projects/buck_bad_config/src/bad_app.erl b/test_projects/buck_bad_config/src/bad_app.erl similarity index 100% rename from test/test_projects/buck_bad_config/src/bad_app.erl rename to test_projects/buck_bad_config/src/bad_app.erl diff --git a/test_projects/buck_tests/.elp.toml b/test_projects/buck_tests/.elp.toml new file mode 100644 index 0000000000..acb0799975 --- /dev/null +++ b/test_projects/buck_tests/.elp.toml @@ -0,0 +1,9 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/buck_tests/..." ] +excluded_targets = [ "fbcode//whatsapp/elp/test_projects/buck_tests:test_elp_ignored" ] +source_root = "whatsapp/elp/test_projects/buck_tests" + +[eqwalizer] +enable_all = false diff --git a/test/test_projects/buck_tests/TARGETS.v2_ b/test_projects/buck_tests/TARGETS.v2_ similarity index 100% rename from test/test_projects/buck_tests/TARGETS.v2_ rename to test_projects/buck_tests/TARGETS.v2_ diff --git a/test/test_projects/buck_tests/test_elp/TARGETS.v2_ b/test_projects/buck_tests/test_elp/TARGETS.v2_ similarity index 77% rename from test/test_projects/buck_tests/test_elp/TARGETS.v2_ rename to test_projects/buck_tests/test_elp/TARGETS.v2_ index 7e5bd95db5..83089813da 100644 --- a/test/test_projects/buck_tests/test_elp/TARGETS.v2_ +++ b/test_projects/buck_tests/test_elp/TARGETS.v2_ @@ -7,11 +7,11 @@ erlang_application( ]), app_src = "src/test_elp.app.src", applications = [ - "//buck_tests/test_elp_direct_dep:test_elp_direct_dep", - "//buck_tests:test_elp_no_private_headers", - "//buck_tests:test_elp_no_public_headers", - "//buck_tests:test_elp_flat_outside_target", - "//buck_tests/test_elp_flat_inside_target:test_elp_flat_inside_target", + "//whatsapp/elp/test_projects/buck_tests/test_elp_direct_dep:test_elp_direct_dep", + "//whatsapp/elp/test_projects/buck_tests:test_elp_no_private_headers", + "//whatsapp/elp/test_projects/buck_tests:test_elp_no_public_headers", + "//whatsapp/elp/test_projects/buck_tests:test_elp_flat_outside_target", + "//whatsapp/elp/test_projects/buck_tests/test_elp_flat_inside_target:test_elp_flat_inside_target", ], includes = glob(["include/*.hrl"]), version = "1.0.0", diff --git a/test/test_projects/buck_tests/test_elp/include/test_elp.hrl b/test_projects/buck_tests/test_elp/include/test_elp.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp/include/test_elp.hrl rename to test_projects/buck_tests/test_elp/include/test_elp.hrl diff --git a/test/test_projects/buck_tests/test_elp/src/test_elp.app.src b/test_projects/buck_tests/test_elp/src/test_elp.app.src similarity index 100% rename from test/test_projects/buck_tests/test_elp/src/test_elp.app.src rename to test_projects/buck_tests/test_elp/src/test_elp.app.src diff --git a/test/test_projects/buck_tests/test_elp/src/test_elp.erl b/test_projects/buck_tests/test_elp/src/test_elp.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp/src/test_elp.erl rename to test_projects/buck_tests/test_elp/src/test_elp.erl diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE.erl b/test_projects/buck_tests/test_elp/test/test_elp_SUITE.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_SUITE.erl rename to test_projects/buck_tests/test_elp/test/test_elp_SUITE.erl diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test1.json b/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test1.json similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test1.json rename to test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test1.json diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test2.json b/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test2.json similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test2.json rename to test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test2.json diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_header.hrl b/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_header.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_header.hrl rename to test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_header.hrl diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_module.erl b/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_module.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_module.erl rename to test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_module.erl diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_test_utils.erl b/test_projects/buck_tests/test_elp/test/test_elp_test_utils.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_test_utils.erl rename to test_projects/buck_tests/test_elp/test/test_elp_test_utils.erl diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_test_utils.hrl b/test_projects/buck_tests/test_elp/test/test_elp_test_utils.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_test_utils.hrl rename to test_projects/buck_tests/test_elp/test/test_elp_test_utils.hrl diff --git a/test/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ b/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ similarity index 62% rename from test/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ rename to test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ index a752b99087..d0fea8149b 100644 --- a/test/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ +++ b/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ @@ -5,10 +5,10 @@ erlang_application( "src/*.hrl", ]), applications = [ - "//buck_tests/test_elp_transitive_dep:test_elp_transitive_dep", + "//whatsapp/elp/test_projects/buck_tests/test_elp_transitive_dep:test_elp_transitive_dep", ], extra_includes = [ - "//buck_tests/test_elp:test_elp", + "//whatsapp/elp/test_projects/buck_tests/test_elp:test_elp", ], includes = glob(["include/*.hrl"]), version = "1.0.0", diff --git a/test/test_projects/buck_tests/test_elp_direct_dep/include/test_elp_direct_dep.hrl b/test_projects/buck_tests/test_elp_direct_dep/include/test_elp_direct_dep.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_direct_dep/include/test_elp_direct_dep.hrl rename to test_projects/buck_tests/test_elp_direct_dep/include/test_elp_direct_dep.hrl diff --git a/test/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep.erl b/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep.erl rename to test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep.erl diff --git a/test/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep_private.hrl b/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep_private.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep_private.hrl rename to test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep_private.hrl diff --git a/test/test_projects/buck_tests/test_elp_flat_inside_target/TARGETS.v2_ b/test_projects/buck_tests/test_elp_flat_inside_target/TARGETS.v2_ similarity index 100% rename from test/test_projects/buck_tests/test_elp_flat_inside_target/TARGETS.v2_ rename to test_projects/buck_tests/test_elp_flat_inside_target/TARGETS.v2_ diff --git a/test/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.erl b/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.erl rename to test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.erl diff --git a/test/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.hrl b/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.hrl rename to test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.hrl diff --git a/test/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.erl b/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.erl rename to test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.erl diff --git a/test/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.hrl b/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.hrl rename to test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.hrl diff --git a/test/test_projects/buck_tests/test_elp_ignored/test_elp_ignored.erl b/test_projects/buck_tests/test_elp_ignored/test_elp_ignored.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_ignored/test_elp_ignored.erl rename to test_projects/buck_tests/test_elp_ignored/test_elp_ignored.erl diff --git a/test/test_projects/buck_tests/test_elp_no_private_headers/include/test_elp_no_private_headers.hrl b/test_projects/buck_tests/test_elp_no_private_headers/include/test_elp_no_private_headers.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_no_private_headers/include/test_elp_no_private_headers.hrl rename to test_projects/buck_tests/test_elp_no_private_headers/include/test_elp_no_private_headers.hrl diff --git a/test/test_projects/buck_tests/test_elp_no_private_headers/src/test_elp_no_private_headers.erl b/test_projects/buck_tests/test_elp_no_private_headers/src/test_elp_no_private_headers.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_no_private_headers/src/test_elp_no_private_headers.erl rename to test_projects/buck_tests/test_elp_no_private_headers/src/test_elp_no_private_headers.erl diff --git a/test/test_projects/buck_tests/test_elp_no_public_headers/src/test_elp_no_headers.erl b/test_projects/buck_tests/test_elp_no_public_headers/src/test_elp_no_headers.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_no_public_headers/src/test_elp_no_headers.erl rename to test_projects/buck_tests/test_elp_no_public_headers/src/test_elp_no_headers.erl diff --git a/test/test_projects/buck_tests/test_elp_transitive_dep/TARGETS.v2_ b/test_projects/buck_tests/test_elp_transitive_dep/TARGETS.v2_ similarity index 100% rename from test/test_projects/buck_tests/test_elp_transitive_dep/TARGETS.v2_ rename to test_projects/buck_tests/test_elp_transitive_dep/TARGETS.v2_ diff --git a/test/test_projects/buck_tests/test_elp_transitive_dep/include/test_elp_transitive_dep.hrl b/test_projects/buck_tests/test_elp_transitive_dep/include/test_elp_transitive_dep.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_transitive_dep/include/test_elp_transitive_dep.hrl rename to test_projects/buck_tests/test_elp_transitive_dep/include/test_elp_transitive_dep.hrl diff --git a/test/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep.erl b/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep.erl rename to test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep.erl diff --git a/test/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep_private.hrl b/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep_private.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep_private.hrl rename to test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep_private.hrl diff --git a/test_projects/buck_tests_2/.elp.toml b/test_projects/buck_tests_2/.elp.toml new file mode 100644 index 0000000000..4ea681809f --- /dev/null +++ b/test_projects/buck_tests_2/.elp.toml @@ -0,0 +1,9 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/buck_tests_2/util/app_a/..." ] +excluded_targets = [ "fbcode//whatsapp/elp/test_projects/buck_tests_2:test_elp_ignored" ] +source_root = "whatsapp/elp/test_projects/buck_tests_2" + +[eqwalizer] +enable_all = false diff --git a/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/include/auto_gen_a.hrl b/test_projects/buck_tests_2/auto_gen/auto_gen_a/include/auto_gen_a.hrl similarity index 100% rename from test/test_projects/buck_tests_2/auto_gen/auto_gen_a/include/auto_gen_a.hrl rename to test_projects/buck_tests_2/auto_gen/auto_gen_a/include/auto_gen_a.hrl diff --git a/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl b/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl similarity index 100% rename from test/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl rename to test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl diff --git a/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl b/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl similarity index 100% rename from test/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl rename to test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl diff --git a/test/test_projects/buck_tests_2/generated/out/generated_header.hrl b/test_projects/buck_tests_2/generated/out/generated_header.hrl similarity index 100% rename from test/test_projects/buck_tests_2/generated/out/generated_header.hrl rename to test_projects/buck_tests_2/generated/out/generated_header.hrl diff --git a/test/test_projects/buck_tests_2/util/app_a/include/junk.hrl b/test_projects/buck_tests_2/util/app_a/include/junk.hrl similarity index 100% rename from test/test_projects/buck_tests_2/util/app_a/include/junk.hrl rename to test_projects/buck_tests_2/util/app_a/include/junk.hrl diff --git a/test/test_projects/buck_tests_2/util/app_a/src/app_a.erl b/test_projects/buck_tests_2/util/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/buck_tests_2/util/app_a/src/app_a.erl rename to test_projects/buck_tests_2/util/app_a/src/app_a.erl diff --git a/test/test_projects/custom_build_tool/.elp.toml b/test_projects/custom_build_tool/.elp.toml similarity index 100% rename from test/test_projects/custom_build_tool/.elp.toml rename to test_projects/custom_build_tool/.elp.toml diff --git a/test/test_projects/custom_build_tool/apps/app_a/include/app_a.hrl b/test_projects/custom_build_tool/apps/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/custom_build_tool/apps/app_a/include/app_a.hrl rename to test_projects/custom_build_tool/apps/app_a/include/app_a.hrl diff --git a/test/test_projects/custom_build_tool/apps/app_a/src/app_a.erl b/test_projects/custom_build_tool/apps/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/custom_build_tool/apps/app_a/src/app_a.erl rename to test_projects/custom_build_tool/apps/app_a/src/app_a.erl diff --git a/test/test_projects/custom_build_tool/apps/app_b/src/app_b.erl b/test_projects/custom_build_tool/apps/app_b/src/app_b.erl similarity index 100% rename from test/test_projects/custom_build_tool/apps/app_b/src/app_b.erl rename to test_projects/custom_build_tool/apps/app_b/src/app_b.erl diff --git a/test_projects/diagnostics/.elp.toml b/test_projects/diagnostics/.elp.toml new file mode 100644 index 0000000000..e5ee70c992 --- /dev/null +++ b/test_projects/diagnostics/.elp.toml @@ -0,0 +1,8 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/diagnostics/..." ] +source_root = "whatsapp/elp/test_projects/diagnostics" + +[eqwalizer] +enable_all = false diff --git a/test/test_projects/diagnostics/README.md b/test_projects/diagnostics/README.md similarity index 100% rename from test/test_projects/diagnostics/README.md rename to test_projects/diagnostics/README.md diff --git a/test/test_projects/diagnostics/app_a/extra/app_a.erl b/test_projects/diagnostics/app_a/extra/app_a.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/extra/app_a.erl rename to test_projects/diagnostics/app_a/extra/app_a.erl diff --git a/test/test_projects/diagnostics/app_a/include/app_a.hrl b/test_projects/diagnostics/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/diagnostics/app_a/include/app_a.hrl rename to test_projects/diagnostics/app_a/include/app_a.hrl diff --git a/test/test_projects/diagnostics/app_a/include/broken_diagnostics.hrl b/test_projects/diagnostics/app_a/include/broken_diagnostics.hrl similarity index 100% rename from test/test_projects/diagnostics/app_a/include/broken_diagnostics.hrl rename to test_projects/diagnostics/app_a/include/broken_diagnostics.hrl diff --git a/test/test_projects/diagnostics/app_a/include/diagnostics.hrl b/test_projects/diagnostics/app_a/include/diagnostics.hrl similarity index 100% rename from test/test_projects/diagnostics/app_a/include/diagnostics.hrl rename to test_projects/diagnostics/app_a/include/diagnostics.hrl diff --git a/test/test_projects/diagnostics/app_a/src/app_a.app.src b/test_projects/diagnostics/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/diagnostics/app_a/src/app_a.app.src rename to test_projects/diagnostics/app_a/src/app_a.app.src diff --git a/test/test_projects/diagnostics/app_a/src/app_a.erl b/test_projects/diagnostics/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/app_a.erl rename to test_projects/diagnostics/app_a/src/app_a.erl diff --git a/test/test_projects/diagnostics/app_a/src/broken_parse_trans.erl b/test_projects/diagnostics/app_a/src/broken_parse_trans.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/broken_parse_trans.erl rename to test_projects/diagnostics/app_a/src/broken_parse_trans.erl diff --git a/test/test_projects/diagnostics/app_a/src/cascading.erl b/test_projects/diagnostics/app_a/src/cascading.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/cascading.erl rename to test_projects/diagnostics/app_a/src/cascading.erl diff --git a/test/test_projects/diagnostics/app_a/src/crlf.erl b/test_projects/diagnostics/app_a/src/crlf.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/crlf.erl rename to test_projects/diagnostics/app_a/src/crlf.erl diff --git a/test/test_projects/diagnostics/app_a/src/diagnostics.erl b/test_projects/diagnostics/app_a/src/diagnostics.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/diagnostics.erl rename to test_projects/diagnostics/app_a/src/diagnostics.erl diff --git a/test/test_projects/diagnostics/app_a/src/diagnostics.escript b/test_projects/diagnostics/app_a/src/diagnostics.escript similarity index 100% rename from test/test_projects/diagnostics/app_a/src/diagnostics.escript rename to test_projects/diagnostics/app_a/src/diagnostics.escript diff --git a/test/test_projects/diagnostics/app_a/src/diagnostics_errors.escript b/test_projects/diagnostics/app_a/src/diagnostics_errors.escript similarity index 100% rename from test/test_projects/diagnostics/app_a/src/diagnostics_errors.escript rename to test_projects/diagnostics/app_a/src/diagnostics_errors.escript diff --git a/test/test_projects/diagnostics/app_a/src/diagnostics_warnings.escript b/test_projects/diagnostics/app_a/src/diagnostics_warnings.escript similarity index 100% rename from test/test_projects/diagnostics/app_a/src/diagnostics_warnings.escript rename to test_projects/diagnostics/app_a/src/diagnostics_warnings.escript diff --git a/test/test_projects/diagnostics/app_a/src/erlang_diagnostics_errors_gen.erl b/test_projects/diagnostics/app_a/src/erlang_diagnostics_errors_gen.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/erlang_diagnostics_errors_gen.erl rename to test_projects/diagnostics/app_a/src/erlang_diagnostics_errors_gen.erl diff --git a/test/test_projects/diagnostics/app_a/src/file_attribute.erl b/test_projects/diagnostics/app_a/src/file_attribute.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/file_attribute.erl rename to test_projects/diagnostics/app_a/src/file_attribute.erl diff --git a/test/test_projects/diagnostics/app_a/src/lint_recursive.erl b/test_projects/diagnostics/app_a/src/lint_recursive.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/lint_recursive.erl rename to test_projects/diagnostics/app_a/src/lint_recursive.erl diff --git a/test/test_projects/diagnostics/app_a/src/lints.erl b/test_projects/diagnostics/app_a/src/lints.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/lints.erl rename to test_projects/diagnostics/app_a/src/lints.erl diff --git a/test/test_projects/diagnostics/app_a/src/otp27_docstrings.erl b/test_projects/diagnostics/app_a/src/otp27_docstrings.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/otp27_docstrings.erl rename to test_projects/diagnostics/app_a/src/otp27_docstrings.erl diff --git a/test/test_projects/diagnostics/app_a/src/otp27_sigils.erl b/test_projects/diagnostics/app_a/src/otp27_sigils.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/otp27_sigils.erl rename to test_projects/diagnostics/app_a/src/otp27_sigils.erl diff --git a/test/test_projects/diagnostics/app_a/src/otp_7655.erl b/test_projects/diagnostics/app_a/src/otp_7655.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/otp_7655.erl rename to test_projects/diagnostics/app_a/src/otp_7655.erl diff --git a/test/test_projects/diagnostics/app_a/src/parse_error_a_cascade.erl b/test_projects/diagnostics/app_a/src/parse_error_a_cascade.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/parse_error_a_cascade.erl rename to test_projects/diagnostics/app_a/src/parse_error_a_cascade.erl diff --git a/test/test_projects/diagnostics/app_a/src/suppressed.erl b/test_projects/diagnostics/app_a/src/suppressed.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/suppressed.erl rename to test_projects/diagnostics/app_a/src/suppressed.erl diff --git a/test/test_projects/diagnostics/app_a/src/syntax.erl b/test_projects/diagnostics/app_a/src/syntax.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/syntax.erl rename to test_projects/diagnostics/app_a/src/syntax.erl diff --git a/test/test_projects/diagnostics/app_a/test/app_a_SUITE.erl b/test_projects/diagnostics/app_a/test/app_a_SUITE.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/test/app_a_SUITE.erl rename to test_projects/diagnostics/app_a/test/app_a_SUITE.erl diff --git a/test/test_projects/diagnostics/erlang_ls.config b/test_projects/diagnostics/erlang_ls.config similarity index 100% rename from test/test_projects/diagnostics/erlang_ls.config rename to test_projects/diagnostics/erlang_ls.config diff --git a/test/test_projects/diagnostics/rebar.config b/test_projects/diagnostics/rebar.config similarity index 100% rename from test/test_projects/diagnostics/rebar.config rename to test_projects/diagnostics/rebar.config diff --git a/test/test_projects/diagnostics/test_build_info.json b/test_projects/diagnostics/test_build_info.json similarity index 100% rename from test/test_projects/diagnostics/test_build_info.json rename to test_projects/diagnostics/test_build_info.json diff --git a/test/test_projects/codegen_test/.elp.toml b/test_projects/end_to_end/.elp.toml similarity index 50% rename from test/test_projects/codegen_test/.elp.toml rename to test_projects/end_to_end/.elp.toml index f21fe1bc73..f015956e45 100644 --- a/test/test_projects/codegen_test/.elp.toml +++ b/test_projects/end_to_end/.elp.toml @@ -1,7 +1,7 @@ [buck] enabled = true build_deps = false -included_targets = ["root//codegen_test/..."] +included_targets = ["fbcode//whatsapp/elp/test_projects/end_to_end/..."] [eqwalizer] enable_all = false diff --git a/test/test_projects/end_to_end/assist_examples/src/add_doc.erl b/test_projects/end_to_end/assist_examples/src/add_doc.erl similarity index 100% rename from test/test_projects/end_to_end/assist_examples/src/add_doc.erl rename to test_projects/end_to_end/assist_examples/src/add_doc.erl diff --git a/test/test_projects/end_to_end/assist_examples/src/assist_examples.app.src b/test_projects/end_to_end/assist_examples/src/assist_examples.app.src similarity index 100% rename from test/test_projects/end_to_end/assist_examples/src/assist_examples.app.src rename to test_projects/end_to_end/assist_examples/src/assist_examples.app.src diff --git a/test/test_projects/end_to_end/assist_examples/src/code_completion.erl b/test_projects/end_to_end/assist_examples/src/code_completion.erl similarity index 100% rename from test/test_projects/end_to_end/assist_examples/src/code_completion.erl rename to test_projects/end_to_end/assist_examples/src/code_completion.erl diff --git a/test/test_projects/end_to_end/assist_examples/src/extract_function.erl b/test_projects/end_to_end/assist_examples/src/extract_function.erl similarity index 100% rename from test/test_projects/end_to_end/assist_examples/src/extract_function.erl rename to test_projects/end_to_end/assist_examples/src/extract_function.erl diff --git a/test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl b/test_projects/end_to_end/assist_examples/src/head_mismatch.erl similarity index 100% rename from test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl rename to test_projects/end_to_end/assist_examples/src/head_mismatch.erl diff --git a/test/test_projects/end_to_end/caf/configerator/source/whatsapp/my_caf.erl b/test_projects/end_to_end/caf/configerator/source/whatsapp/my_caf.erl similarity index 100% rename from test/test_projects/end_to_end/caf/configerator/source/whatsapp/my_caf.erl rename to test_projects/end_to_end/caf/configerator/source/whatsapp/my_caf.erl diff --git a/test/test_projects/end_to_end/definitions/README.md b/test_projects/end_to_end/definitions/README.md similarity index 100% rename from test/test_projects/end_to_end/definitions/README.md rename to test_projects/end_to_end/definitions/README.md diff --git a/test/test_projects/end_to_end/definitions/src/definitions.app.src b/test_projects/end_to_end/definitions/src/definitions.app.src similarity index 100% rename from test/test_projects/end_to_end/definitions/src/definitions.app.src rename to test_projects/end_to_end/definitions/src/definitions.app.src diff --git a/test/test_projects/end_to_end/definitions/src/local_def.erl b/test_projects/end_to_end/definitions/src/local_def.erl similarity index 100% rename from test/test_projects/end_to_end/definitions/src/local_def.erl rename to test_projects/end_to_end/definitions/src/local_def.erl diff --git a/test/test_projects/end_to_end/docs/src/docs.app.src b/test_projects/end_to_end/docs/src/docs.app.src similarity index 100% rename from test/test_projects/end_to_end/docs/src/docs.app.src rename to test_projects/end_to_end/docs/src/docs.app.src diff --git a/test/test_projects/end_to_end/docs/src/docs.erl b/test_projects/end_to_end/docs/src/docs.erl similarity index 100% rename from test/test_projects/end_to_end/docs/src/docs.erl rename to test_projects/end_to_end/docs/src/docs.erl diff --git a/test/test_projects/end_to_end/erlang_ls.config b/test_projects/end_to_end/erlang_ls.config similarity index 100% rename from test/test_projects/end_to_end/erlang_ls.config rename to test_projects/end_to_end/erlang_ls.config diff --git a/test/test_projects/end_to_end/fixtures/erlang-stacktrace.txt b/test_projects/end_to_end/fixtures/erlang-stacktrace.txt similarity index 100% rename from test/test_projects/end_to_end/fixtures/erlang-stacktrace.txt rename to test_projects/end_to_end/fixtures/erlang-stacktrace.txt diff --git a/test/test_projects/end_to_end/hover/README.md b/test_projects/end_to_end/hover/README.md similarity index 100% rename from test/test_projects/end_to_end/hover/README.md rename to test_projects/end_to_end/hover/README.md diff --git a/test/test_projects/end_to_end/hover/src/doc_examples.erl b/test_projects/end_to_end/hover/src/doc_examples.erl similarity index 100% rename from test/test_projects/end_to_end/hover/src/doc_examples.erl rename to test_projects/end_to_end/hover/src/doc_examples.erl diff --git a/test/test_projects/end_to_end/hover/src/hover.app.src b/test_projects/end_to_end/hover/src/hover.app.src similarity index 100% rename from test/test_projects/end_to_end/hover/src/hover.app.src rename to test_projects/end_to_end/hover/src/hover.app.src diff --git a/test/test_projects/end_to_end/rebar.config b/test_projects/end_to_end/rebar.config similarity index 100% rename from test/test_projects/end_to_end/rebar.config rename to test_projects/end_to_end/rebar.config diff --git a/test/test_projects/end_to_end/single_errors/README.md b/test_projects/end_to_end/single_errors/README.md similarity index 100% rename from test/test_projects/end_to_end/single_errors/README.md rename to test_projects/end_to_end/single_errors/README.md diff --git a/test/test_projects/end_to_end/single_errors/src/as_you_type.erl b/test_projects/end_to_end/single_errors/src/as_you_type.erl similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/as_you_type.erl rename to test_projects/end_to_end/single_errors/src/as_you_type.erl diff --git a/test/test_projects/end_to_end/single_errors/src/compiler_diagnostics.erl b/test_projects/end_to_end/single_errors/src/compiler_diagnostics.erl similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/compiler_diagnostics.erl rename to test_projects/end_to_end/single_errors/src/compiler_diagnostics.erl diff --git a/test/test_projects/end_to_end/single_errors/src/single_errors.app.src b/test_projects/end_to_end/single_errors/src/single_errors.app.src similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/single_errors.app.src rename to test_projects/end_to_end/single_errors/src/single_errors.app.src diff --git a/test/test_projects/end_to_end/single_errors/src/spec_mismatch.erl b/test_projects/end_to_end/single_errors/src/spec_mismatch.erl similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/spec_mismatch.erl rename to test_projects/end_to_end/single_errors/src/spec_mismatch.erl diff --git a/test/test_projects/end_to_end/single_errors/src/spec_mismatch.erl.2 b/test_projects/end_to_end/single_errors/src/spec_mismatch.erl.2 similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/spec_mismatch.erl.2 rename to test_projects/end_to_end/single_errors/src/spec_mismatch.erl.2 diff --git a/test/test_projects/end_to_end/single_errors/src/types_on_hover.erl b/test_projects/end_to_end/single_errors/src/types_on_hover.erl similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/types_on_hover.erl rename to test_projects/end_to_end/single_errors/src/types_on_hover.erl diff --git a/test/test_projects/end_to_end/single_errors/src/unused_macro.erl b/test_projects/end_to_end/single_errors/src/unused_macro.erl similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/unused_macro.erl rename to test_projects/end_to_end/single_errors/src/unused_macro.erl diff --git a/test/test_projects/eqwalizer/src/eqwalizer.app.src b/test_projects/eqwalizer/src/eqwalizer.app.src similarity index 100% rename from test/test_projects/eqwalizer/src/eqwalizer.app.src rename to test_projects/eqwalizer/src/eqwalizer.app.src diff --git a/test/test_projects/eqwalizer/src/eqwalizer_specs.erl b/test_projects/eqwalizer/src/eqwalizer_specs.erl similarity index 100% rename from test/test_projects/eqwalizer/src/eqwalizer_specs.erl rename to test_projects/eqwalizer/src/eqwalizer_specs.erl diff --git a/test_projects/eqwalizer_callers/.elp.toml b/test_projects/eqwalizer_callers/.elp.toml new file mode 100644 index 0000000000..f4b7f6f6ac --- /dev/null +++ b/test_projects/eqwalizer_callers/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/eqwalizer_callers/..." ] +source_root = "whatsapp/elp/test_projects/eqwalizer_callers" diff --git a/test/test_projects/eqwalizer_callers/.gitignore b/test_projects/eqwalizer_callers/.gitignore similarity index 100% rename from test/test_projects/eqwalizer_callers/.gitignore rename to test_projects/eqwalizer_callers/.gitignore diff --git a/test/test_projects/eqwalizer_callers/app_a/include/app_a.hrl b/test_projects/eqwalizer_callers/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/eqwalizer_callers/app_a/include/app_a.hrl rename to test_projects/eqwalizer_callers/app_a/include/app_a.hrl diff --git a/test/test_projects/eqwalizer_callers/app_a/src/app_a.app.src b/test_projects/eqwalizer_callers/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/eqwalizer_callers/app_a/src/app_a.app.src rename to test_projects/eqwalizer_callers/app_a/src/app_a.app.src diff --git a/test/test_projects/eqwalizer_callers/app_a/src/app_a.erl b/test_projects/eqwalizer_callers/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/eqwalizer_callers/app_a/src/app_a.erl rename to test_projects/eqwalizer_callers/app_a/src/app_a.erl diff --git a/test/test_projects/eqwalizer_callers/app_a/src/app_b.erl b/test_projects/eqwalizer_callers/app_a/src/app_b.erl similarity index 100% rename from test/test_projects/eqwalizer_callers/app_a/src/app_b.erl rename to test_projects/eqwalizer_callers/app_a/src/app_b.erl diff --git a/test/test_projects/eqwalizer_callers/app_a/test/app_a_SUITE.erl b/test_projects/eqwalizer_callers/app_a/test/app_a_SUITE.erl similarity index 100% rename from test/test_projects/eqwalizer_callers/app_a/test/app_a_SUITE.erl rename to test_projects/eqwalizer_callers/app_a/test/app_a_SUITE.erl diff --git a/test/test_projects/eqwalizer_callers/rebar.config b/test_projects/eqwalizer_callers/rebar.config similarity index 100% rename from test/test_projects/eqwalizer_callers/rebar.config rename to test_projects/eqwalizer_callers/rebar.config diff --git a/test/test_projects/eqwalizer_ignore_modules/.elp.toml b/test_projects/eqwalizer_ignore_modules/.elp.toml similarity index 100% rename from test/test_projects/eqwalizer_ignore_modules/.elp.toml rename to test_projects/eqwalizer_ignore_modules/.elp.toml diff --git a/test/test_projects/eqwalizer_ignore_modules/apps/app_a/include/app_a.hrl b/test_projects/eqwalizer_ignore_modules/apps/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/eqwalizer_ignore_modules/apps/app_a/include/app_a.hrl rename to test_projects/eqwalizer_ignore_modules/apps/app_a/include/app_a.hrl diff --git a/test/test_projects/eqwalizer_ignore_modules/apps/app_a/src/another_module_a.erl b/test_projects/eqwalizer_ignore_modules/apps/app_a/src/another_module_a.erl similarity index 100% rename from test/test_projects/eqwalizer_ignore_modules/apps/app_a/src/another_module_a.erl rename to test_projects/eqwalizer_ignore_modules/apps/app_a/src/another_module_a.erl diff --git a/test/test_projects/eqwalizer_ignore_modules/apps/app_a/src/app_a.erl b/test_projects/eqwalizer_ignore_modules/apps/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/eqwalizer_ignore_modules/apps/app_a/src/app_a.erl rename to test_projects/eqwalizer_ignore_modules/apps/app_a/src/app_a.erl diff --git a/test/test_projects/eqwalizer_ignore_modules/apps/app_b/src/app_b.erl b/test_projects/eqwalizer_ignore_modules/apps/app_b/src/app_b.erl similarity index 100% rename from test/test_projects/eqwalizer_ignore_modules/apps/app_b/src/app_b.erl rename to test_projects/eqwalizer_ignore_modules/apps/app_b/src/app_b.erl diff --git a/test_projects/eqwalizer_tests/.elp.toml b/test_projects/eqwalizer_tests/.elp.toml new file mode 100644 index 0000000000..ed5c60502f --- /dev/null +++ b/test_projects/eqwalizer_tests/.elp.toml @@ -0,0 +1,8 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/eqwalizer_tests/..." ] +source_root = "whatsapp/elp/test_projects/eqwalizer_tests" + +[eqwalizer] +enable_all = true diff --git a/test/test_projects/eqwalizer_tests/.gitignore b/test_projects/eqwalizer_tests/.gitignore similarity index 100% rename from test/test_projects/eqwalizer_tests/.gitignore rename to test_projects/eqwalizer_tests/.gitignore diff --git a/test/test_projects/eqwalizer_tests/.rebar.root b/test_projects/eqwalizer_tests/.rebar.root similarity index 100% rename from test/test_projects/eqwalizer_tests/.rebar.root rename to test_projects/eqwalizer_tests/.rebar.root diff --git a/test/test_projects/eqwalizer_tests/check/include/my_header.hrl b/test_projects/eqwalizer_tests/check/include/my_header.hrl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/include/my_header.hrl rename to test_projects/eqwalizer_tests/check/include/my_header.hrl diff --git a/test/test_projects/eqwalizer_tests/check/src/any_fun_type.erl b/test_projects/eqwalizer_tests/check/src/any_fun_type.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/any_fun_type.erl rename to test_projects/eqwalizer_tests/check/src/any_fun_type.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/apply_none.erl b/test_projects/eqwalizer_tests/check/src/apply_none.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/apply_none.erl rename to test_projects/eqwalizer_tests/check/src/apply_none.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/approx.erl b/test_projects/eqwalizer_tests/check/src/approx.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/approx.erl rename to test_projects/eqwalizer_tests/check/src/approx.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/as_pat.erl b/test_projects/eqwalizer_tests/check/src/as_pat.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/as_pat.erl rename to test_projects/eqwalizer_tests/check/src/as_pat.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/auto_imports.erl b/test_projects/eqwalizer_tests/check/src/auto_imports.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/auto_imports.erl rename to test_projects/eqwalizer_tests/check/src/auto_imports.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/behave.erl b/test_projects/eqwalizer_tests/check/src/behave.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/behave.erl rename to test_projects/eqwalizer_tests/check/src/behave.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/binaries.erl b/test_projects/eqwalizer_tests/check/src/binaries.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/binaries.erl rename to test_projects/eqwalizer_tests/check/src/binaries.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/booleans.erl b/test_projects/eqwalizer_tests/check/src/booleans.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/booleans.erl rename to test_projects/eqwalizer_tests/check/src/booleans.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/callbacks1_pos.erl b/test_projects/eqwalizer_tests/check/src/callbacks1_pos.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/callbacks1_pos.erl rename to test_projects/eqwalizer_tests/check/src/callbacks1_pos.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl b/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl similarity index 70% rename from test/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl rename to test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl index 854feec923..8152487669 100644 --- a/test/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl +++ b/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl @@ -3,12 +3,11 @@ %%% This source code is licensed under the Apache 2.0 license found in %%% the LICENSE file in the root directory of this source tree. --module(callbacks3_neg). % @OTP27Only +-module(callbacks3_neg). % @OTPVersionDependent -export([ init/1, handle_call/3, - handle_cast/2, - handle_info/2 + handle_cast/2 ]). -behavior(gen_server). @@ -20,7 +19,3 @@ handle_call(_, _From, State) -> -spec handle_cast(ok, ok) -> wrong_ret. handle_cast(_, _) -> wrong_ret. - --spec handle_info(ok, ok) -> {noreply, ok, wrong_atom}. -handle_info(_, _) -> - {noreply, ok, wrong_atom}. diff --git a/test/test_projects/eqwalizer_tests/check/src/callbacks4_neg.erl b/test_projects/eqwalizer_tests/check/src/callbacks4_neg.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/callbacks4_neg.erl rename to test_projects/eqwalizer_tests/check/src/callbacks4_neg.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/callbacks5_neg.erl b/test_projects/eqwalizer_tests/check/src/callbacks5_neg.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/callbacks5_neg.erl rename to test_projects/eqwalizer_tests/check/src/callbacks5_neg.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/callbacks6_neg.erl b/test_projects/eqwalizer_tests/check/src/callbacks6_neg.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/callbacks6_neg.erl rename to test_projects/eqwalizer_tests/check/src/callbacks6_neg.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/callbacks7_overload_pos.erl b/test_projects/eqwalizer_tests/check/src/callbacks7_overload_pos.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/callbacks7_overload_pos.erl rename to test_projects/eqwalizer_tests/check/src/callbacks7_overload_pos.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/case_predicates.erl b/test_projects/eqwalizer_tests/check/src/case_predicates.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/case_predicates.erl rename to test_projects/eqwalizer_tests/check/src/case_predicates.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/check.app.src b/test_projects/eqwalizer_tests/check/src/check.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/check.app.src rename to test_projects/eqwalizer_tests/check/src/check.app.src diff --git a/test/test_projects/eqwalizer_tests/check/src/compiler_macro.erl b/test_projects/eqwalizer_tests/check/src/compiler_macro.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/compiler_macro.erl rename to test_projects/eqwalizer_tests/check/src/compiler_macro.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/complex_maps.erl b/test_projects/eqwalizer_tests/check/src/complex_maps.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/complex_maps.erl rename to test_projects/eqwalizer_tests/check/src/complex_maps.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/comprehensions.erl b/test_projects/eqwalizer_tests/check/src/comprehensions.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/comprehensions.erl rename to test_projects/eqwalizer_tests/check/src/comprehensions.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/contravariant.erl b/test_projects/eqwalizer_tests/check/src/contravariant.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/contravariant.erl rename to test_projects/eqwalizer_tests/check/src/contravariant.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/custom.erl b/test_projects/eqwalizer_tests/check/src/custom.erl similarity index 99% rename from test/test_projects/eqwalizer_tests/check/src/custom.erl rename to test_projects/eqwalizer_tests/check/src/custom.erl index b6910b0fc7..911bfa3a0a 100644 --- a/test/test_projects/eqwalizer_tests/check/src/custom.erl +++ b/test_projects/eqwalizer_tests/check/src/custom.erl @@ -3,7 +3,7 @@ %%% This source code is licensed under the Apache 2.0 license found in %%% the LICENSE file in the root directory of this source tree. --module(custom). % @OTP27Only +-module(custom). % @OTPVersionDependent -import(maps, [get/2, get/3]). -compile([export_all, nowarn_export_all]). diff --git a/test/test_projects/eqwalizer_tests/check/src/detached_specs1.erl b/test_projects/eqwalizer_tests/check/src/detached_specs1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/detached_specs1.erl rename to test_projects/eqwalizer_tests/check/src/detached_specs1.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/detached_specs2.erl b/test_projects/eqwalizer_tests/check/src/detached_specs2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/detached_specs2.erl rename to test_projects/eqwalizer_tests/check/src/detached_specs2.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dyn_calls.erl b/test_projects/eqwalizer_tests/check/src/dyn_calls.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dyn_calls.erl rename to test_projects/eqwalizer_tests/check/src/dyn_calls.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dyn_remote_funs.erl b/test_projects/eqwalizer_tests/check/src/dyn_remote_funs.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dyn_remote_funs.erl rename to test_projects/eqwalizer_tests/check/src/dyn_remote_funs.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_1.erl b/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_1.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_callbacks_1.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_2.erl b/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_2.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_callbacks_2.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_calls.erl b/test_projects/eqwalizer_tests/check/src/dynamic_calls.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_calls.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_calls.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_catch.erl b/test_projects/eqwalizer_tests/check/src/dynamic_catch.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_catch.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_catch.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_fun.erl b/test_projects/eqwalizer_tests/check/src/dynamic_fun.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_fun.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_fun.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_generics.erl b/test_projects/eqwalizer_tests/check/src/dynamic_generics.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_generics.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_generics.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_local_funs.erl b/test_projects/eqwalizer_tests/check/src/dynamic_local_funs.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_local_funs.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_local_funs.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_receive.erl b/test_projects/eqwalizer_tests/check/src/dynamic_receive.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_receive.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_receive.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_refine.erl b/test_projects/eqwalizer_tests/check/src/dynamic_refine.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_refine.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_refine.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_try_catch.erl b/test_projects/eqwalizer_tests/check/src/dynamic_try_catch.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_try_catch.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_try_catch.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/elab_clause.erl b/test_projects/eqwalizer_tests/check/src/elab_clause.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/elab_clause.erl rename to test_projects/eqwalizer_tests/check/src/elab_clause.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/error_messages.erl b/test_projects/eqwalizer_tests/check/src/error_messages.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/error_messages.erl rename to test_projects/eqwalizer_tests/check/src/error_messages.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/fancy_generics.erl b/test_projects/eqwalizer_tests/check/src/fancy_generics.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/fancy_generics.erl rename to test_projects/eqwalizer_tests/check/src/fancy_generics.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/format.erl b/test_projects/eqwalizer_tests/check/src/format.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/format.erl rename to test_projects/eqwalizer_tests/check/src/format.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/fun_stats.erl b/test_projects/eqwalizer_tests/check/src/fun_stats.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/fun_stats.erl rename to test_projects/eqwalizer_tests/check/src/fun_stats.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/fun_stats2.erl b/test_projects/eqwalizer_tests/check/src/fun_stats2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/fun_stats2.erl rename to test_projects/eqwalizer_tests/check/src/fun_stats2.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/funs.erl b/test_projects/eqwalizer_tests/check/src/funs.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/funs.erl rename to test_projects/eqwalizer_tests/check/src/funs.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/funs2.erl b/test_projects/eqwalizer_tests/check/src/funs2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/funs2.erl rename to test_projects/eqwalizer_tests/check/src/funs2.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/funs_uncommon.erl b/test_projects/eqwalizer_tests/check/src/funs_uncommon.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/funs_uncommon.erl rename to test_projects/eqwalizer_tests/check/src/funs_uncommon.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/generic_fun_application.erl b/test_projects/eqwalizer_tests/check/src/generic_fun_application.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/generic_fun_application.erl rename to test_projects/eqwalizer_tests/check/src/generic_fun_application.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/generics_with_unions.erl b/test_projects/eqwalizer_tests/check/src/generics_with_unions.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/generics_with_unions.erl rename to test_projects/eqwalizer_tests/check/src/generics_with_unions.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_bounded.erl b/test_projects/eqwalizer_tests/check/src/gradual_bounded.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_bounded.erl rename to test_projects/eqwalizer_tests/check/src/gradual_bounded.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_complex_types.erl b/test_projects/eqwalizer_tests/check/src/gradual_complex_types.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_complex_types.erl rename to test_projects/eqwalizer_tests/check/src/gradual_complex_types.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_custom.erl b/test_projects/eqwalizer_tests/check/src/gradual_custom.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_custom.erl rename to test_projects/eqwalizer_tests/check/src/gradual_custom.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_lambdas.erl b/test_projects/eqwalizer_tests/check/src/gradual_lambdas.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_lambdas.erl rename to test_projects/eqwalizer_tests/check/src/gradual_lambdas.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_maybe.erl b/test_projects/eqwalizer_tests/check/src/gradual_maybe.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_maybe.erl rename to test_projects/eqwalizer_tests/check/src/gradual_maybe.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_misc.erl b/test_projects/eqwalizer_tests/check/src/gradual_misc.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_misc.erl rename to test_projects/eqwalizer_tests/check/src/gradual_misc.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_overloaded.erl b/test_projects/eqwalizer_tests/check/src/gradual_overloaded.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_overloaded.erl rename to test_projects/eqwalizer_tests/check/src/gradual_overloaded.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_regression_01.erl b/test_projects/eqwalizer_tests/check/src/gradual_regression_01.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_regression_01.erl rename to test_projects/eqwalizer_tests/check/src/gradual_regression_01.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_untyped.erl b/test_projects/eqwalizer_tests/check/src/gradual_untyped.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_untyped.erl rename to test_projects/eqwalizer_tests/check/src/gradual_untyped.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/guard_b_connections.erl b/test_projects/eqwalizer_tests/check/src/guard_b_connections.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/guard_b_connections.erl rename to test_projects/eqwalizer_tests/check/src/guard_b_connections.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/guards.erl b/test_projects/eqwalizer_tests/check/src/guards.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/guards.erl rename to test_projects/eqwalizer_tests/check/src/guards.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/guards_logic.erl b/test_projects/eqwalizer_tests/check/src/guards_logic.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/guards_logic.erl rename to test_projects/eqwalizer_tests/check/src/guards_logic.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/guards_simple.erl b/test_projects/eqwalizer_tests/check/src/guards_simple.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/guards_simple.erl rename to test_projects/eqwalizer_tests/check/src/guards_simple.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/hints.erl b/test_projects/eqwalizer_tests/check/src/hints.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/hints.erl rename to test_projects/eqwalizer_tests/check/src/hints.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/index1.erl b/test_projects/eqwalizer_tests/check/src/index1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/index1.erl rename to test_projects/eqwalizer_tests/check/src/index1.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/index2.erl b/test_projects/eqwalizer_tests/check/src/index2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/index2.erl rename to test_projects/eqwalizer_tests/check/src/index2.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/iolists.erl b/test_projects/eqwalizer_tests/check/src/iolists.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/iolists.erl rename to test_projects/eqwalizer_tests/check/src/iolists.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/kp_01.erl b/test_projects/eqwalizer_tests/check/src/kp_01.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/kp_01.erl rename to test_projects/eqwalizer_tests/check/src/kp_01.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/kp_02.erl b/test_projects/eqwalizer_tests/check/src/kp_02.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/kp_02.erl rename to test_projects/eqwalizer_tests/check/src/kp_02.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/lists_tests.erl b/test_projects/eqwalizer_tests/check/src/lists_tests.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/lists_tests.erl rename to test_projects/eqwalizer_tests/check/src/lists_tests.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/misc.erl b/test_projects/eqwalizer_tests/check/src/misc.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/misc.erl rename to test_projects/eqwalizer_tests/check/src/misc.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/misc_lib.erl b/test_projects/eqwalizer_tests/check/src/misc_lib.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/misc_lib.erl rename to test_projects/eqwalizer_tests/check/src/misc_lib.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/my_behaviour.erl b/test_projects/eqwalizer_tests/check/src/my_behaviour.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/my_behaviour.erl rename to test_projects/eqwalizer_tests/check/src/my_behaviour.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/my_gradual_behaviour.erl b/test_projects/eqwalizer_tests/check/src/my_gradual_behaviour.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/my_gradual_behaviour.erl rename to test_projects/eqwalizer_tests/check/src/my_gradual_behaviour.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/my_header.erl b/test_projects/eqwalizer_tests/check/src/my_header.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/my_header.erl rename to test_projects/eqwalizer_tests/check/src/my_header.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/neg.erl b/test_projects/eqwalizer_tests/check/src/neg.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/neg.erl rename to test_projects/eqwalizer_tests/check/src/neg.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/nested1/misc_nested1.erl b/test_projects/eqwalizer_tests/check/src/nested1/misc_nested1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/nested1/misc_nested1.erl rename to test_projects/eqwalizer_tests/check/src/nested1/misc_nested1.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/nested1/nested2/misc_nested2.erl b/test_projects/eqwalizer_tests/check/src/nested1/nested2/misc_nested2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/nested1/nested2/misc_nested2.erl rename to test_projects/eqwalizer_tests/check/src/nested1/nested2/misc_nested2.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/nowarn.erl b/test_projects/eqwalizer_tests/check/src/nowarn.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/nowarn.erl rename to test_projects/eqwalizer_tests/check/src/nowarn.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/number_comparisons.erl b/test_projects/eqwalizer_tests/check/src/number_comparisons.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/number_comparisons.erl rename to test_projects/eqwalizer_tests/check/src/number_comparisons.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/numbers.erl b/test_projects/eqwalizer_tests/check/src/numbers.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/numbers.erl rename to test_projects/eqwalizer_tests/check/src/numbers.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/opaque.erl b/test_projects/eqwalizer_tests/check/src/opaque.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/opaque.erl rename to test_projects/eqwalizer_tests/check/src/opaque.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/other.erl b/test_projects/eqwalizer_tests/check/src/other.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/other.erl rename to test_projects/eqwalizer_tests/check/src/other.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/otp28.erl b/test_projects/eqwalizer_tests/check/src/otp28.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/otp28.erl rename to test_projects/eqwalizer_tests/check/src/otp28.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/otp_opaques.erl b/test_projects/eqwalizer_tests/check/src/otp_opaques.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/otp_opaques.erl rename to test_projects/eqwalizer_tests/check/src/otp_opaques.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/overloaded.erl b/test_projects/eqwalizer_tests/check/src/overloaded.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/overloaded.erl rename to test_projects/eqwalizer_tests/check/src/overloaded.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/overloaded_specs_union.erl b/test_projects/eqwalizer_tests/check/src/overloaded_specs_union.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/overloaded_specs_union.erl rename to test_projects/eqwalizer_tests/check/src/overloaded_specs_union.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/parametricity.erl b/test_projects/eqwalizer_tests/check/src/parametricity.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/parametricity.erl rename to test_projects/eqwalizer_tests/check/src/parametricity.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/pats.erl b/test_projects/eqwalizer_tests/check/src/pats.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/pats.erl rename to test_projects/eqwalizer_tests/check/src/pats.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/pinned.erl b/test_projects/eqwalizer_tests/check/src/pinned.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/pinned.erl rename to test_projects/eqwalizer_tests/check/src/pinned.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/pos.erl b/test_projects/eqwalizer_tests/check/src/pos.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/pos.erl rename to test_projects/eqwalizer_tests/check/src/pos.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/records.erl b/test_projects/eqwalizer_tests/check/src/records.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/records.erl rename to test_projects/eqwalizer_tests/check/src/records.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/recursive_aliases.erl b/test_projects/eqwalizer_tests/check/src/recursive_aliases.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/recursive_aliases.erl rename to test_projects/eqwalizer_tests/check/src/recursive_aliases.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/refine.erl b/test_projects/eqwalizer_tests/check/src/refine.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/refine.erl rename to test_projects/eqwalizer_tests/check/src/refine.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/scoping.erl b/test_projects/eqwalizer_tests/check/src/scoping.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/scoping.erl rename to test_projects/eqwalizer_tests/check/src/scoping.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/skip.erl b/test_projects/eqwalizer_tests/check/src/skip.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/skip.erl rename to test_projects/eqwalizer_tests/check/src/skip.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/static_maybe.erl b/test_projects/eqwalizer_tests/check/src/static_maybe.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/static_maybe.erl rename to test_projects/eqwalizer_tests/check/src/static_maybe.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/strict_complex_types.erl b/test_projects/eqwalizer_tests/check/src/strict_complex_types.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/strict_complex_types.erl rename to test_projects/eqwalizer_tests/check/src/strict_complex_types.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/strict_fun.erl b/test_projects/eqwalizer_tests/check/src/strict_fun.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/strict_fun.erl rename to test_projects/eqwalizer_tests/check/src/strict_fun.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/strict_receive.erl b/test_projects/eqwalizer_tests/check/src/strict_receive.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/strict_receive.erl rename to test_projects/eqwalizer_tests/check/src/strict_receive.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/subtype_neg.erl b/test_projects/eqwalizer_tests/check/src/subtype_neg.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/subtype_neg.erl rename to test_projects/eqwalizer_tests/check/src/subtype_neg.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/subtype_pos.erl b/test_projects/eqwalizer_tests/check/src/subtype_pos.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/subtype_pos.erl rename to test_projects/eqwalizer_tests/check/src/subtype_pos.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/t_maps.erl b/test_projects/eqwalizer_tests/check/src/t_maps.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/t_maps.erl rename to test_projects/eqwalizer_tests/check/src/t_maps.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/tagged_tuples.erl b/test_projects/eqwalizer_tests/check/src/tagged_tuples.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/tagged_tuples.erl rename to test_projects/eqwalizer_tests/check/src/tagged_tuples.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/test.erl b/test_projects/eqwalizer_tests/check/src/test.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/test.erl rename to test_projects/eqwalizer_tests/check/src/test.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/tries.erl b/test_projects/eqwalizer_tests/check/src/tries.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/tries.erl rename to test_projects/eqwalizer_tests/check/src/tries.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/tuple_union.erl b/test_projects/eqwalizer_tests/check/src/tuple_union.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/tuple_union.erl rename to test_projects/eqwalizer_tests/check/src/tuple_union.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/type_aliases.erl b/test_projects/eqwalizer_tests/check/src/type_aliases.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/type_aliases.erl rename to test_projects/eqwalizer_tests/check/src/type_aliases.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/type_asserts.erl b/test_projects/eqwalizer_tests/check/src/type_asserts.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/type_asserts.erl rename to test_projects/eqwalizer_tests/check/src/type_asserts.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/type_predicates.erl b/test_projects/eqwalizer_tests/check/src/type_predicates.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/type_predicates.erl rename to test_projects/eqwalizer_tests/check/src/type_predicates.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/united_fun.erl b/test_projects/eqwalizer_tests/check/src/united_fun.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/united_fun.erl rename to test_projects/eqwalizer_tests/check/src/united_fun.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/unspecced.erl b/test_projects/eqwalizer_tests/check/src/unspecced.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/unspecced.erl rename to test_projects/eqwalizer_tests/check/src/unspecced.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/use_dynamic_gradual.erl b/test_projects/eqwalizer_tests/check/src/use_dynamic_gradual.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/use_dynamic_gradual.erl rename to test_projects/eqwalizer_tests/check/src/use_dynamic_gradual.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/use_dynamic_strict.erl b/test_projects/eqwalizer_tests/check/src/use_dynamic_strict.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/use_dynamic_strict.erl rename to test_projects/eqwalizer_tests/check/src/use_dynamic_strict.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/vars1.erl b/test_projects/eqwalizer_tests/check/src/vars1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/vars1.erl rename to test_projects/eqwalizer_tests/check/src/vars1.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/vars2.erl b/test_projects/eqwalizer_tests/check/src/vars2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/vars2.erl rename to test_projects/eqwalizer_tests/check/src/vars2.erl diff --git a/test/test_projects/eqwalizer_tests/check/test/check_SUITE.erl b/test_projects/eqwalizer_tests/check/test/check_SUITE.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/test/check_SUITE.erl rename to test_projects/eqwalizer_tests/check/test/check_SUITE.erl diff --git a/test/test_projects/eqwalizer_tests/debug/include/debug_header.hrl b/test_projects/eqwalizer_tests/debug/include/debug_header.hrl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/include/debug_header.hrl rename to test_projects/eqwalizer_tests/debug/include/debug_header.hrl diff --git a/test/test_projects/eqwalizer_tests/debug/src/attributes.erl b/test_projects/eqwalizer_tests/debug/src/attributes.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/attributes.erl rename to test_projects/eqwalizer_tests/debug/src/attributes.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/debug.app.src b/test_projects/eqwalizer_tests/debug/src/debug.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/debug.app.src rename to test_projects/eqwalizer_tests/debug/src/debug.app.src diff --git a/test/test_projects/eqwalizer_tests/debug/src/debug_header.erl b/test_projects/eqwalizer_tests/debug/src/debug_header.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/debug_header.erl rename to test_projects/eqwalizer_tests/debug/src/debug_header.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/expand.erl b/test_projects/eqwalizer_tests/debug/src/expand.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/expand.erl rename to test_projects/eqwalizer_tests/debug/src/expand.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/expr1.erl b/test_projects/eqwalizer_tests/debug/src/expr1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/expr1.erl rename to test_projects/eqwalizer_tests/debug/src/expr1.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/expr2.erl b/test_projects/eqwalizer_tests/debug/src/expr2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/expr2.erl rename to test_projects/eqwalizer_tests/debug/src/expr2.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/records_wip.erl b/test_projects/eqwalizer_tests/debug/src/records_wip.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/records_wip.erl rename to test_projects/eqwalizer_tests/debug/src/records_wip.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/types1.erl b/test_projects/eqwalizer_tests/debug/src/types1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/types1.erl rename to test_projects/eqwalizer_tests/debug/src/types1.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/types2.erl b/test_projects/eqwalizer_tests/debug/src/types2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/types2.erl rename to test_projects/eqwalizer_tests/debug/src/types2.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/wip_maps.erl b/test_projects/eqwalizer_tests/debug/src/wip_maps.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/wip_maps.erl rename to test_projects/eqwalizer_tests/debug/src/wip_maps.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/basics.erl b/test_projects/eqwalizer_tests/elm_core/src/basics.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/basics.erl rename to test_projects/eqwalizer_tests/elm_core/src/basics.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/elm_core.app.src b/test_projects/eqwalizer_tests/elm_core/src/elm_core.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/elm_core.app.src rename to test_projects/eqwalizer_tests/elm_core/src/elm_core.app.src diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/list.erl b/test_projects/eqwalizer_tests/elm_core/src/list.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/list.erl rename to test_projects/eqwalizer_tests/elm_core/src/list.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/map.erl b/test_projects/eqwalizer_tests/elm_core/src/map.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/map.erl rename to test_projects/eqwalizer_tests/elm_core/src/map.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/map_ffi.erl b/test_projects/eqwalizer_tests/elm_core/src/map_ffi.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/map_ffi.erl rename to test_projects/eqwalizer_tests/elm_core/src/map_ffi.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/maybe.erl b/test_projects/eqwalizer_tests/elm_core/src/maybe.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/maybe.erl rename to test_projects/eqwalizer_tests/elm_core/src/maybe.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/result.erl b/test_projects/eqwalizer_tests/elm_core/src/result.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/result.erl rename to test_projects/eqwalizer_tests/elm_core/src/result.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/tuple.erl b/test_projects/eqwalizer_tests/elm_core/src/tuple.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/tuple.erl rename to test_projects/eqwalizer_tests/elm_core/src/tuple.erl diff --git a/test/test_projects/eqwalizer_tests/eqwalizer/include/eqwalizer.hrl b/test_projects/eqwalizer_tests/eqwalizer/include/eqwalizer.hrl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer/include/eqwalizer.hrl rename to test_projects/eqwalizer_tests/eqwalizer/include/eqwalizer.hrl diff --git a/test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.app.src b/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.app.src rename to test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.app.src diff --git a/test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.erl b/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.erl rename to test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.erl diff --git a/test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer_specs.erl b/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer_specs.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer_specs.erl rename to test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer_specs.erl diff --git a/test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_build_info_prv.erl b/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_build_info_prv.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_build_info_prv.erl rename to test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_build_info_prv.erl diff --git a/test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.app.src b/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.app.src rename to test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.app.src diff --git a/test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.erl b/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.erl rename to test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/readme.md b/test_projects/eqwalizer_tests/eqwater/readme.md similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/readme.md rename to test_projects/eqwalizer_tests/eqwater/readme.md diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl b/test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl rename to test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater.app.src b/test_projects/eqwalizer_tests/eqwater/src/eqwater.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater.app.src rename to test_projects/eqwalizer_tests/eqwater/src/eqwater.app.src diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_aliases.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater_aliases.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater_aliases.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater_aliases.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_generics.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater_generics.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater_generics.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater_generics.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_lists.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater_lists.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater_lists.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater_lists.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl similarity index 89% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl index 68d938f790..78ae852b8a 100644 --- a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl +++ b/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl @@ -59,13 +59,3 @@ map_occ_08_neg(_) -> err. map_occ_09(#{a := undefined}) -> 1; map_occ_09(#{a := Map}) -> Map#{2 => 2}; map_occ_09(_) -> 3. - --spec is_ok(ok) -> ok. -is_ok(ok) -> ok. - --spec map_occ_foreach_neg(#{term() => #{a => ok | err}}) -> ok. -map_occ_foreach_neg(M) -> - maps:foreach(fun - (_, #{a := err}) -> ok; - (_, #{a := V}) -> is_ok(V) - end, M). diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_records.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater_records.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater_records.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater_records.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_sound.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater_sound.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater_sound.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater_sound.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/unlimited_refinement.erl b/test_projects/eqwalizer_tests/eqwater/src/unlimited_refinement.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/unlimited_refinement.erl rename to test_projects/eqwalizer_tests/eqwater/src/unlimited_refinement.erl diff --git a/test/test_projects/eqwalizer_tests/fault_tolerance/.eqwalizer b/test_projects/eqwalizer_tests/fault_tolerance/.eqwalizer similarity index 100% rename from test/test_projects/eqwalizer_tests/fault_tolerance/.eqwalizer rename to test_projects/eqwalizer_tests/fault_tolerance/.eqwalizer diff --git a/test/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.app.src b/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.app.src rename to test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.app.src diff --git a/test/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.erl b/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.erl rename to test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.erl diff --git a/test/test_projects/eqwalizer_tests/options/src/bad_maps.erl b/test_projects/eqwalizer_tests/options/src/bad_maps.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/options/src/bad_maps.erl rename to test_projects/eqwalizer_tests/options/src/bad_maps.erl diff --git a/test/test_projects/eqwalizer_tests/options/src/dynamic_lambdas.erl b/test_projects/eqwalizer_tests/options/src/dynamic_lambdas.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/options/src/dynamic_lambdas.erl rename to test_projects/eqwalizer_tests/options/src/dynamic_lambdas.erl diff --git a/test/test_projects/eqwalizer_tests/options/src/options.app.src b/test_projects/eqwalizer_tests/options/src/options.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/options/src/options.app.src rename to test_projects/eqwalizer_tests/options/src/options.app.src diff --git a/test/test_projects/eqwalizer_tests/options/src/overloaded_specs_dynamic_result.erl b/test_projects/eqwalizer_tests/options/src/overloaded_specs_dynamic_result.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/options/src/overloaded_specs_dynamic_result.erl rename to test_projects/eqwalizer_tests/options/src/overloaded_specs_dynamic_result.erl diff --git a/test/test_projects/eqwalizer_tests/options/src/redundant_guards.erl b/test_projects/eqwalizer_tests/options/src/redundant_guards.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/options/src/redundant_guards.erl rename to test_projects/eqwalizer_tests/options/src/redundant_guards.erl diff --git a/test/test_projects/eqwalizer_tests/options/src/uncovered_clauses.erl b/test_projects/eqwalizer_tests/options/src/uncovered_clauses.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/options/src/uncovered_clauses.erl rename to test_projects/eqwalizer_tests/options/src/uncovered_clauses.erl diff --git a/test/test_projects/eqwalizer_tests/rebar.config b/test_projects/eqwalizer_tests/rebar.config similarity index 100% rename from test/test_projects/eqwalizer_tests/rebar.config rename to test_projects/eqwalizer_tests/rebar.config diff --git a/test_projects/in_place_tests/.elp.toml b/test_projects/in_place_tests/.elp.toml new file mode 100644 index 0000000000..b6c251f03c --- /dev/null +++ b/test_projects/in_place_tests/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/in_place_tests/..." ] +source_root = "whatsapp/elp/test_projects/in_place_tests" diff --git a/test/test_projects/in_place_tests/README.md b/test_projects/in_place_tests/README.md similarity index 100% rename from test/test_projects/in_place_tests/README.md rename to test_projects/in_place_tests/README.md diff --git a/test/test_projects/in_place_tests/app_a/extra/app_a.erl b/test_projects/in_place_tests/app_a/extra/app_a.erl similarity index 100% rename from test/test_projects/in_place_tests/app_a/extra/app_a.erl rename to test_projects/in_place_tests/app_a/extra/app_a.erl diff --git a/test/test_projects/in_place_tests/app_a/include/app_a.hrl b/test_projects/in_place_tests/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/in_place_tests/app_a/include/app_a.hrl rename to test_projects/in_place_tests/app_a/include/app_a.hrl diff --git a/test/test_projects/in_place_tests/app_a/include/broken_diagnostics.hrl b/test_projects/in_place_tests/app_a/include/broken_diagnostics.hrl similarity index 100% rename from test/test_projects/in_place_tests/app_a/include/broken_diagnostics.hrl rename to test_projects/in_place_tests/app_a/include/broken_diagnostics.hrl diff --git a/test/test_projects/in_place_tests/app_a/include/diagnostics.hrl b/test_projects/in_place_tests/app_a/include/diagnostics.hrl similarity index 100% rename from test/test_projects/in_place_tests/app_a/include/diagnostics.hrl rename to test_projects/in_place_tests/app_a/include/diagnostics.hrl diff --git a/test/test_projects/hierarchical_config/app_a/src/app_a.app.src b/test_projects/in_place_tests/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/hierarchical_config/app_a/src/app_a.app.src rename to test_projects/in_place_tests/app_a/src/app_a.app.src diff --git a/test/test_projects/in_place_tests/app_a/src/app_a.erl b/test_projects/in_place_tests/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/in_place_tests/app_a/src/app_a.erl rename to test_projects/in_place_tests/app_a/src/app_a.erl diff --git a/test/test_projects/in_place_tests/app_a/src/lints.erl b/test_projects/in_place_tests/app_a/src/lints.erl similarity index 100% rename from test/test_projects/in_place_tests/app_a/src/lints.erl rename to test_projects/in_place_tests/app_a/src/lints.erl diff --git a/test/test_projects/in_place_tests/app_a/test/app_a_SUITE.erl b/test_projects/in_place_tests/app_a/test/app_a_SUITE.erl similarity index 100% rename from test/test_projects/in_place_tests/app_a/test/app_a_SUITE.erl rename to test_projects/in_place_tests/app_a/test/app_a_SUITE.erl diff --git a/test/test_projects/in_place_tests/erlang_ls.config b/test_projects/in_place_tests/erlang_ls.config similarity index 100% rename from test/test_projects/in_place_tests/erlang_ls.config rename to test_projects/in_place_tests/erlang_ls.config diff --git a/test/test_projects/in_place_tests/rebar.config b/test_projects/in_place_tests/rebar.config similarity index 100% rename from test/test_projects/in_place_tests/rebar.config rename to test_projects/in_place_tests/rebar.config diff --git a/test_projects/include_lib_dependency_test/.elp.toml b/test_projects/include_lib_dependency_test/.elp.toml new file mode 100644 index 0000000000..65e106a9e2 --- /dev/null +++ b/test_projects/include_lib_dependency_test/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/include_lib_dependency_test/..." ] +source_root = "whatsapp/elp/test_projects/include_lib_dependency_test" diff --git a/test/test_projects/include_lib_dependency_test/external_app/include/external_header.hrl b/test_projects/include_lib_dependency_test/external_app/include/external_header.hrl similarity index 100% rename from test/test_projects/include_lib_dependency_test/external_app/include/external_header.hrl rename to test_projects/include_lib_dependency_test/external_app/include/external_header.hrl diff --git a/test/test_projects/include_lib_dependency_test/external_app/src/external_app.app.src b/test_projects/include_lib_dependency_test/external_app/src/external_app.app.src similarity index 100% rename from test/test_projects/include_lib_dependency_test/external_app/src/external_app.app.src rename to test_projects/include_lib_dependency_test/external_app/src/external_app.app.src diff --git a/test/test_projects/include_lib_dependency_test/external_app/src/external_app.erl b/test_projects/include_lib_dependency_test/external_app/src/external_app.erl similarity index 100% rename from test/test_projects/include_lib_dependency_test/external_app/src/external_app.erl rename to test_projects/include_lib_dependency_test/external_app/src/external_app.erl diff --git a/test/test_projects/include_lib_dependency_test/extra_app/include/extra_header.hrl b/test_projects/include_lib_dependency_test/extra_app/include/extra_header.hrl similarity index 100% rename from test/test_projects/include_lib_dependency_test/extra_app/include/extra_header.hrl rename to test_projects/include_lib_dependency_test/extra_app/include/extra_header.hrl diff --git a/test/test_projects/include_lib_dependency_test/extra_app/src/extra_app.app.src b/test_projects/include_lib_dependency_test/extra_app/src/extra_app.app.src similarity index 100% rename from test/test_projects/include_lib_dependency_test/extra_app/src/extra_app.app.src rename to test_projects/include_lib_dependency_test/extra_app/src/extra_app.app.src diff --git a/test/test_projects/include_lib_dependency_test/extra_app/src/extra_app.erl b/test_projects/include_lib_dependency_test/extra_app/src/extra_app.erl similarity index 100% rename from test/test_projects/include_lib_dependency_test/extra_app/src/extra_app.erl rename to test_projects/include_lib_dependency_test/extra_app/src/extra_app.erl diff --git a/test/test_projects/include_lib_dependency_test/main_app/src/main_app.app.src b/test_projects/include_lib_dependency_test/main_app/src/main_app.app.src similarity index 100% rename from test/test_projects/include_lib_dependency_test/main_app/src/main_app.app.src rename to test_projects/include_lib_dependency_test/main_app/src/main_app.app.src diff --git a/test/test_projects/include_lib_dependency_test/main_app/src/main_app.erl b/test_projects/include_lib_dependency_test/main_app/src/main_app.erl similarity index 100% rename from test/test_projects/include_lib_dependency_test/main_app/src/main_app.erl rename to test_projects/include_lib_dependency_test/main_app/src/main_app.erl diff --git a/test/test_projects/include_lib_dependency_test/normal_dep/include/assert.hrl b/test_projects/include_lib_dependency_test/normal_dep/include/assert.hrl similarity index 100% rename from test/test_projects/include_lib_dependency_test/normal_dep/include/assert.hrl rename to test_projects/include_lib_dependency_test/normal_dep/include/assert.hrl diff --git a/test/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.app.src b/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.app.src similarity index 100% rename from test/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.app.src rename to test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.app.src diff --git a/test/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.erl b/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.erl similarity index 100% rename from test/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.erl rename to test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.erl diff --git a/test/test_projects/include_lib_dependency_test/rebar.config b/test_projects/include_lib_dependency_test/rebar.config similarity index 100% rename from test/test_projects/include_lib_dependency_test/rebar.config rename to test_projects/include_lib_dependency_test/rebar.config diff --git a/test_projects/linter/.elp.toml b/test_projects/linter/.elp.toml new file mode 100644 index 0000000000..a887ab835c --- /dev/null +++ b/test_projects/linter/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/linter/..." ] +source_root = "whatsapp/elp/test_projects/linter" diff --git a/test/test_projects/linter/.elp_lint.toml b/test_projects/linter/.elp_lint.toml similarity index 100% rename from test/test_projects/linter/.elp_lint.toml rename to test_projects/linter/.elp_lint.toml diff --git a/test/test_projects/linter/.gitignore b/test_projects/linter/.gitignore similarity index 100% rename from test/test_projects/linter/.gitignore rename to test_projects/linter/.gitignore diff --git a/test/test_projects/linter/app_a/include/app_a.hrl b/test_projects/linter/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/linter/app_a/include/app_a.hrl rename to test_projects/linter/app_a/include/app_a.hrl diff --git a/test/test_projects/in_place_tests/app_a/src/app_a.app.src b/test_projects/linter/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/in_place_tests/app_a/src/app_a.app.src rename to test_projects/linter/app_a/src/app_a.app.src diff --git a/test/test_projects/linter/app_a/src/app_a.erl b/test_projects/linter/app_a/src/app_a.erl similarity index 70% rename from test/test_projects/linter/app_a/src/app_a.erl rename to test_projects/linter/app_a/src/app_a.erl index 86593395dd..167b8e6d6d 100644 --- a/test/test_projects/linter/app_a/src/app_a.erl +++ b/test_projects/linter/app_a/src/app_a.erl @@ -14,9 +14,3 @@ bar() -> app_b:application_env_error(). baz(A,B) -> {A,B}. - -% Some more context, see if it renders - -bat(A,B) -> {A,B}. - -% And some more context, see if it renders diff --git a/test/test_projects/linter/app_a/src/app_a_edoc.erl b/test_projects/linter/app_a/src/app_a_edoc.erl similarity index 100% rename from test/test_projects/linter/app_a/src/app_a_edoc.erl rename to test_projects/linter/app_a/src/app_a_edoc.erl diff --git a/test/test_projects/linter/app_a/src/app_a_ssr.erl b/test_projects/linter/app_a/src/app_a_ssr.erl similarity index 100% rename from test/test_projects/linter/app_a/src/app_a_ssr.erl rename to test_projects/linter/app_a/src/app_a_ssr.erl diff --git a/test/test_projects/linter/app_a/src/app_a_unused_param.erl b/test_projects/linter/app_a/src/app_a_unused_param.erl similarity index 100% rename from test/test_projects/linter/app_a/src/app_a_unused_param.erl rename to test_projects/linter/app_a/src/app_a_unused_param.erl diff --git a/test/test_projects/linter/app_a/src/custom_function_matches.erl b/test_projects/linter/app_a/src/custom_function_matches.erl similarity index 100% rename from test/test_projects/linter/app_a/src/custom_function_matches.erl rename to test_projects/linter/app_a/src/custom_function_matches.erl diff --git a/test/test_projects/linter/app_a/src/expression_updates_literal.erl b/test_projects/linter/app_a/src/expression_updates_literal.erl similarity index 100% rename from test/test_projects/linter/app_a/src/expression_updates_literal.erl rename to test_projects/linter/app_a/src/expression_updates_literal.erl diff --git a/test/test_projects/linter/app_a/src/spelling.erl b/test_projects/linter/app_a/src/spelling.erl similarity index 100% rename from test/test_projects/linter/app_a/src/spelling.erl rename to test_projects/linter/app_a/src/spelling.erl diff --git a/test/test_projects/linter/app_a/test/app_a_SUITE.erl b/test_projects/linter/app_a/test/app_a_SUITE.erl similarity index 100% rename from test/test_projects/linter/app_a/test/app_a_SUITE.erl rename to test_projects/linter/app_a/test/app_a_SUITE.erl diff --git a/test/test_projects/linter/app_a/test/app_a_test_helpers.erl b/test_projects/linter/app_a/test/app_a_test_helpers.erl similarity index 100% rename from test/test_projects/linter/app_a/test/app_a_test_helpers.erl rename to test_projects/linter/app_a/test/app_a_test_helpers.erl diff --git a/test/test_projects/linter/app_a/test/app_a_test_helpers_not_opted_in.erl b/test_projects/linter/app_a/test/app_a_test_helpers_not_opted_in.erl similarity index 100% rename from test/test_projects/linter/app_a/test/app_a_test_helpers_not_opted_in.erl rename to test_projects/linter/app_a/test/app_a_test_helpers_not_opted_in.erl diff --git a/test/test_projects/linter/app_a/test/app_a_unreachable_test_SUITE.erl b/test_projects/linter/app_a/test/app_a_unreachable_test_SUITE.erl similarity index 100% rename from test/test_projects/linter/app_a/test/app_a_unreachable_test_SUITE.erl rename to test_projects/linter/app_a/test/app_a_unreachable_test_SUITE.erl diff --git a/test/test_projects/linter/app_a/test/app_test_helpers_no_errors.erl b/test_projects/linter/app_a/test/app_test_helpers_no_errors.erl similarity index 100% rename from test/test_projects/linter/app_a/test/app_test_helpers_no_errors.erl rename to test_projects/linter/app_a/test/app_test_helpers_no_errors.erl diff --git a/test/test_projects/hierarchical_config/app_b/src/app_b.app.src b/test_projects/linter/app_b/src/app_b.app.src similarity index 100% rename from test/test_projects/hierarchical_config/app_b/src/app_b.app.src rename to test_projects/linter/app_b/src/app_b.app.src diff --git a/test/test_projects/linter/app_b/src/app_b.erl b/test_projects/linter/app_b/src/app_b.erl similarity index 100% rename from test/test_projects/linter/app_b/src/app_b.erl rename to test_projects/linter/app_b/src/app_b.erl diff --git a/test/test_projects/linter/app_b/src/app_b_unused_param.erl b/test_projects/linter/app_b/src/app_b_unused_param.erl similarity index 100% rename from test/test_projects/linter/app_b/src/app_b_unused_param.erl rename to test_projects/linter/app_b/src/app_b_unused_param.erl diff --git a/test/test_projects/linter/elp_lint_adhoc.toml b/test_projects/linter/elp_lint_adhoc.toml similarity index 100% rename from test/test_projects/linter/elp_lint_adhoc.toml rename to test_projects/linter/elp_lint_adhoc.toml diff --git a/test/test_projects/linter/elp_lint_custom_function_matches.toml b/test_projects/linter/elp_lint_custom_function_matches.toml similarity index 100% rename from test/test_projects/linter/elp_lint_custom_function_matches.toml rename to test_projects/linter/elp_lint_custom_function_matches.toml diff --git a/test/test_projects/linter/elp_lint_ssr_adhoc.toml b/test_projects/linter/elp_lint_ssr_adhoc.toml similarity index 100% rename from test/test_projects/linter/elp_lint_ssr_adhoc.toml rename to test_projects/linter/elp_lint_ssr_adhoc.toml diff --git a/test/test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml b/test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml similarity index 100% rename from test/test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml rename to test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml diff --git a/test/test_projects/linter/elp_lint_test1.toml b/test_projects/linter/elp_lint_test1.toml similarity index 100% rename from test/test_projects/linter/elp_lint_test1.toml rename to test_projects/linter/elp_lint_test1.toml diff --git a/test/test_projects/linter/elp_lint_test2.toml b/test_projects/linter/elp_lint_test2.toml similarity index 54% rename from test/test_projects/linter/elp_lint_test2.toml rename to test_projects/linter/elp_lint_test2.toml index 0b70173c8b..22878a22a6 100644 --- a/test/test_projects/linter/elp_lint_test2.toml +++ b/test_projects/linter/elp_lint_test2.toml @@ -1,5 +1,2 @@ enabled_lints =['L1268', 'W0011', 'W0012'] disabled_lints = [] - -[linters.compile-warn-missing-spec] -enabled = true diff --git a/test/test_projects/linter/elp_lint_test_ignore.toml b/test_projects/linter/elp_lint_test_ignore.toml similarity index 100% rename from test/test_projects/linter/elp_lint_test_ignore.toml rename to test_projects/linter/elp_lint_test_ignore.toml diff --git a/test/test_projects/linter/elp_lint_warnings_as_errors.toml b/test_projects/linter/elp_lint_warnings_as_errors.toml similarity index 100% rename from test/test_projects/linter/elp_lint_warnings_as_errors.toml rename to test_projects/linter/elp_lint_warnings_as_errors.toml diff --git a/test/test_projects/linter/rebar.config b/test_projects/linter/rebar.config similarity index 100% rename from test/test_projects/linter/rebar.config rename to test_projects/linter/rebar.config diff --git a/test_projects/linter_bad_config/.elp.toml b/test_projects/linter_bad_config/.elp.toml new file mode 100644 index 0000000000..a887ab835c --- /dev/null +++ b/test_projects/linter_bad_config/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/linter/..." ] +source_root = "whatsapp/elp/test_projects/linter" diff --git a/test/test_projects/linter_bad_config/.elp_lint.toml b/test_projects/linter_bad_config/.elp_lint.toml similarity index 100% rename from test/test_projects/linter_bad_config/.elp_lint.toml rename to test_projects/linter_bad_config/.elp_lint.toml diff --git a/test/test_projects/linter_bad_config/.gitignore b/test_projects/linter_bad_config/.gitignore similarity index 100% rename from test/test_projects/linter_bad_config/.gitignore rename to test_projects/linter_bad_config/.gitignore diff --git a/test/test_projects/linter_bad_config/app_a/include/app_a.hrl b/test_projects/linter_bad_config/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/linter_bad_config/app_a/include/app_a.hrl rename to test_projects/linter_bad_config/app_a/include/app_a.hrl diff --git a/test/test_projects/linter/app_a/src/app_a.app.src b/test_projects/linter_bad_config/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/linter/app_a/src/app_a.app.src rename to test_projects/linter_bad_config/app_a/src/app_a.app.src diff --git a/test/test_projects/linter_bad_config/app_a/src/app_a.erl b/test_projects/linter_bad_config/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/linter_bad_config/app_a/src/app_a.erl rename to test_projects/linter_bad_config/app_a/src/app_a.erl diff --git a/test_projects/linter_bad_config/linter/.elp.toml b/test_projects/linter_bad_config/linter/.elp.toml new file mode 100644 index 0000000000..a887ab835c --- /dev/null +++ b/test_projects/linter_bad_config/linter/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/linter/..." ] +source_root = "whatsapp/elp/test_projects/linter" diff --git a/test/test_projects/linter_bad_config/linter/.elp_lint.toml b/test_projects/linter_bad_config/linter/.elp_lint.toml similarity index 100% rename from test/test_projects/linter_bad_config/linter/.elp_lint.toml rename to test_projects/linter_bad_config/linter/.elp_lint.toml diff --git a/test/test_projects/linter_bad_config/linter/.gitignore b/test_projects/linter_bad_config/linter/.gitignore similarity index 100% rename from test/test_projects/linter_bad_config/linter/.gitignore rename to test_projects/linter_bad_config/linter/.gitignore diff --git a/test/test_projects/linter_bad_config/linter/app_a/include/app_a.hrl b/test_projects/linter_bad_config/linter/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/include/app_a.hrl rename to test_projects/linter_bad_config/linter/app_a/include/app_a.hrl diff --git a/test/test_projects/linter_bad_config/app_a/src/app_a.app.src b/test_projects/linter_bad_config/linter/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/linter_bad_config/app_a/src/app_a.app.src rename to test_projects/linter_bad_config/linter/app_a/src/app_a.app.src diff --git a/test/test_projects/linter_bad_config/linter/app_a/src/app_a.erl b/test_projects/linter_bad_config/linter/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/src/app_a.erl rename to test_projects/linter_bad_config/linter/app_a/src/app_a.erl diff --git a/test/test_projects/linter_bad_config/linter/app_a/src/app_a_unused_param.erl b/test_projects/linter_bad_config/linter/app_a/src/app_a_unused_param.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/src/app_a_unused_param.erl rename to test_projects/linter_bad_config/linter/app_a/src/app_a_unused_param.erl diff --git a/test/test_projects/linter_bad_config/linter/app_a/test/app_a_SUITE.erl b/test_projects/linter_bad_config/linter/app_a/test/app_a_SUITE.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/test/app_a_SUITE.erl rename to test_projects/linter_bad_config/linter/app_a/test/app_a_SUITE.erl diff --git a/test/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers.erl b/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers.erl rename to test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers.erl diff --git a/test/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers_not_opted_in.erl b/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers_not_opted_in.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers_not_opted_in.erl rename to test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers_not_opted_in.erl diff --git a/test/test_projects/linter_bad_config/linter/app_a/test/app_test_helpers_no_errors.erl b/test_projects/linter_bad_config/linter/app_a/test/app_test_helpers_no_errors.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/test/app_test_helpers_no_errors.erl rename to test_projects/linter_bad_config/linter/app_a/test/app_test_helpers_no_errors.erl diff --git a/test/test_projects/linter/app_b/src/app_b.app.src b/test_projects/linter_bad_config/linter/app_b/src/app_b.app.src similarity index 100% rename from test/test_projects/linter/app_b/src/app_b.app.src rename to test_projects/linter_bad_config/linter/app_b/src/app_b.app.src diff --git a/test/test_projects/linter_bad_config/linter/app_b/src/app_b.erl b/test_projects/linter_bad_config/linter/app_b/src/app_b.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_b/src/app_b.erl rename to test_projects/linter_bad_config/linter/app_b/src/app_b.erl diff --git a/test/test_projects/linter_bad_config/linter/app_b/src/app_b_unused_param.erl b/test_projects/linter_bad_config/linter/app_b/src/app_b_unused_param.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_b/src/app_b_unused_param.erl rename to test_projects/linter_bad_config/linter/app_b/src/app_b_unused_param.erl diff --git a/test/test_projects/linter_bad_config/linter/rebar.config b/test_projects/linter_bad_config/linter/rebar.config similarity index 100% rename from test/test_projects/linter_bad_config/linter/rebar.config rename to test_projects/linter_bad_config/linter/rebar.config diff --git a/test/test_projects/linter_bad_config/rebar.config b/test_projects/linter_bad_config/rebar.config similarity index 100% rename from test/test_projects/linter_bad_config/rebar.config rename to test_projects/linter_bad_config/rebar.config diff --git a/test_projects/parse_error/.elp.toml b/test_projects/parse_error/.elp.toml new file mode 100644 index 0000000000..bf2c1ad580 --- /dev/null +++ b/test_projects/parse_error/.elp.toml @@ -0,0 +1,8 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/parse_error/..." ] +source_root = "whatsapp/elp/test_projects/parse_error" + +[eqwalizer] +enable_all = false diff --git a/test/test_projects/parse_error/.gitignore b/test_projects/parse_error/.gitignore similarity index 100% rename from test/test_projects/parse_error/.gitignore rename to test_projects/parse_error/.gitignore diff --git a/test/test_projects/parse_error/.rebar.root b/test_projects/parse_error/.rebar.root similarity index 100% rename from test/test_projects/parse_error/.rebar.root rename to test_projects/parse_error/.rebar.root diff --git a/test/test_projects/parse_error/eqwalizer/src/eqwalizer.app.src b/test_projects/parse_error/eqwalizer/src/eqwalizer.app.src similarity index 100% rename from test/test_projects/parse_error/eqwalizer/src/eqwalizer.app.src rename to test_projects/parse_error/eqwalizer/src/eqwalizer.app.src diff --git a/test/test_projects/parse_error/eqwalizer/src/eqwalizer.erl b/test_projects/parse_error/eqwalizer/src/eqwalizer.erl similarity index 100% rename from test/test_projects/parse_error/eqwalizer/src/eqwalizer.erl rename to test_projects/parse_error/eqwalizer/src/eqwalizer.erl diff --git a/test/test_projects/parse_error/eqwalizer/src/eqwalizer_specs.erl b/test_projects/parse_error/eqwalizer/src/eqwalizer_specs.erl similarity index 100% rename from test/test_projects/parse_error/eqwalizer/src/eqwalizer_specs.erl rename to test_projects/parse_error/eqwalizer/src/eqwalizer_specs.erl diff --git a/test/test_projects/parse_error/parse_error_a/src/parse_error_a.app.src b/test_projects/parse_error/parse_error_a/src/parse_error_a.app.src similarity index 100% rename from test/test_projects/parse_error/parse_error_a/src/parse_error_a.app.src rename to test_projects/parse_error/parse_error_a/src/parse_error_a.app.src diff --git a/test/test_projects/parse_error/parse_error_a/src/parse_error_a.erl b/test_projects/parse_error/parse_error_a/src/parse_error_a.erl similarity index 100% rename from test/test_projects/parse_error/parse_error_a/src/parse_error_a.erl rename to test_projects/parse_error/parse_error_a/src/parse_error_a.erl diff --git a/test/test_projects/parse_error/parse_error_a/src/parse_error_a_bad.erl b/test_projects/parse_error/parse_error_a/src/parse_error_a_bad.erl similarity index 100% rename from test/test_projects/parse_error/parse_error_a/src/parse_error_a_bad.erl rename to test_projects/parse_error/parse_error_a/src/parse_error_a_bad.erl diff --git a/test/test_projects/parse_error/parse_error_a/src/parse_error_a_reference_bad.erl b/test_projects/parse_error/parse_error_a/src/parse_error_a_reference_bad.erl similarity index 100% rename from test/test_projects/parse_error/parse_error_a/src/parse_error_a_reference_bad.erl rename to test_projects/parse_error/parse_error_a/src/parse_error_a_reference_bad.erl diff --git a/test/test_projects/parse_error/parse_error_a/src/parse_error_a_syntax_error.erl b/test_projects/parse_error/parse_error_a/src/parse_error_a_syntax_error.erl similarity index 100% rename from test/test_projects/parse_error/parse_error_a/src/parse_error_a_syntax_error.erl rename to test_projects/parse_error/parse_error_a/src/parse_error_a_syntax_error.erl diff --git a/test/test_projects/parse_error/parse_error_a/src/parse_error_a_worst.erl b/test_projects/parse_error/parse_error_a/src/parse_error_a_worst.erl similarity index 100% rename from test/test_projects/parse_error/parse_error_a/src/parse_error_a_worst.erl rename to test_projects/parse_error/parse_error_a/src/parse_error_a_worst.erl diff --git a/test/test_projects/parse_error/rebar.config b/test_projects/parse_error/rebar.config similarity index 100% rename from test/test_projects/parse_error/rebar.config rename to test_projects/parse_error/rebar.config diff --git a/test_projects/standard/.elp.toml b/test_projects/standard/.elp.toml new file mode 100644 index 0000000000..09ff5a4d5a --- /dev/null +++ b/test_projects/standard/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/standard/..." ] +source_root = "whatsapp/elp/test_projects/standard" diff --git a/test/test_projects/standard/.gitignore b/test_projects/standard/.gitignore similarity index 100% rename from test/test_projects/standard/.gitignore rename to test_projects/standard/.gitignore diff --git a/test/test_projects/standard/.rebar.root b/test_projects/standard/.rebar.root similarity index 100% rename from test/test_projects/standard/.rebar.root rename to test_projects/standard/.rebar.root diff --git a/test/test_projects/standard/app_a/.eqwalizer b/test_projects/standard/app_a/.eqwalizer similarity index 100% rename from test/test_projects/standard/app_a/.eqwalizer rename to test_projects/standard/app_a/.eqwalizer diff --git a/test/test_projects/standard/app_a/extra/app_a.erl b/test_projects/standard/app_a/extra/app_a.erl similarity index 100% rename from test/test_projects/standard/app_a/extra/app_a.erl rename to test_projects/standard/app_a/extra/app_a.erl diff --git a/test/test_projects/standard/app_a/include/app_a.hrl b/test_projects/standard/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/standard/app_a/include/app_a.hrl rename to test_projects/standard/app_a/include/app_a.hrl diff --git a/test/test_projects/linter_bad_config/linter/app_a/src/app_a.app.src b/test_projects/standard/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/src/app_a.app.src rename to test_projects/standard/app_a/src/app_a.app.src diff --git a/test/test_projects/standard/app_a/src/app_a.erl b/test_projects/standard/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a.erl rename to test_projects/standard/app_a/src/app_a.erl diff --git a/test/test_projects/standard/app_a/src/app_a_errors_generated.erl b/test_projects/standard/app_a/src/app_a_errors_generated.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_errors_generated.erl rename to test_projects/standard/app_a/src/app_a_errors_generated.erl diff --git a/test/test_projects/standard/app_a/src/app_a_fixme.erl b/test_projects/standard/app_a/src/app_a_fixme.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_fixme.erl rename to test_projects/standard/app_a/src/app_a_fixme.erl diff --git a/test/test_projects/standard/app_a/src/app_a_ignored.erl b/test_projects/standard/app_a/src/app_a_ignored.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_ignored.erl rename to test_projects/standard/app_a/src/app_a_ignored.erl diff --git a/test/test_projects/standard/app_a/src/app_a_lists.erl b/test_projects/standard/app_a/src/app_a_lists.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_lists.erl rename to test_projects/standard/app_a/src/app_a_lists.erl diff --git a/test/test_projects/standard/app_a/src/app_a_mod2.erl b/test_projects/standard/app_a/src/app_a_mod2.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_mod2.erl rename to test_projects/standard/app_a/src/app_a_mod2.erl diff --git a/test/test_projects/standard/app_a/src/app_a_no_errors.erl b/test_projects/standard/app_a/src/app_a_no_errors.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_no_errors.erl rename to test_projects/standard/app_a/src/app_a_no_errors.erl diff --git a/test/test_projects/standard/app_a/src/app_a_no_errors_generated.erl b/test_projects/standard/app_a/src/app_a_no_errors_generated.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_no_errors_generated.erl rename to test_projects/standard/app_a/src/app_a_no_errors_generated.erl diff --git a/test/test_projects/standard/app_a/src/app_a_no_errors_opted_in.erl b/test_projects/standard/app_a/src/app_a_no_errors_opted_in.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_no_errors_opted_in.erl rename to test_projects/standard/app_a/src/app_a_no_errors_opted_in.erl diff --git a/test/test_projects/standard/app_a/test/app_a_SUITE.erl b/test_projects/standard/app_a/test/app_a_SUITE.erl similarity index 100% rename from test/test_projects/standard/app_a/test/app_a_SUITE.erl rename to test_projects/standard/app_a/test/app_a_SUITE.erl diff --git a/test/test_projects/standard/app_a/test/app_a_test_helpers.erl b/test_projects/standard/app_a/test/app_a_test_helpers.erl similarity index 100% rename from test/test_projects/standard/app_a/test/app_a_test_helpers.erl rename to test_projects/standard/app_a/test/app_a_test_helpers.erl diff --git a/test/test_projects/standard/app_a/test/app_a_test_helpers_not_opted_in.erl b/test_projects/standard/app_a/test/app_a_test_helpers_not_opted_in.erl similarity index 100% rename from test/test_projects/standard/app_a/test/app_a_test_helpers_not_opted_in.erl rename to test_projects/standard/app_a/test/app_a_test_helpers_not_opted_in.erl diff --git a/test/test_projects/standard/app_a/test/app_test_helpers_no_errors.erl b/test_projects/standard/app_a/test/app_test_helpers_no_errors.erl similarity index 100% rename from test/test_projects/standard/app_a/test/app_test_helpers_no_errors.erl rename to test_projects/standard/app_a/test/app_test_helpers_no_errors.erl diff --git a/test/test_projects/linter_bad_config/linter/app_b/src/app_b.app.src b/test_projects/standard/app_b/src/app_b.app.src similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_b/src/app_b.app.src rename to test_projects/standard/app_b/src/app_b.app.src diff --git a/test/test_projects/standard/app_b/src/app_b.erl b/test_projects/standard/app_b/src/app_b.erl similarity index 100% rename from test/test_projects/standard/app_b/src/app_b.erl rename to test_projects/standard/app_b/src/app_b.erl diff --git a/test/test_projects/standard/eqwalizer/src/eqwalizer.app.src b/test_projects/standard/eqwalizer/src/eqwalizer.app.src similarity index 100% rename from test/test_projects/standard/eqwalizer/src/eqwalizer.app.src rename to test_projects/standard/eqwalizer/src/eqwalizer.app.src diff --git a/test/test_projects/standard/eqwalizer/src/eqwalizer.erl b/test_projects/standard/eqwalizer/src/eqwalizer.erl similarity index 100% rename from test/test_projects/standard/eqwalizer/src/eqwalizer.erl rename to test_projects/standard/eqwalizer/src/eqwalizer.erl diff --git a/test/test_projects/standard/eqwalizer/src/eqwalizer_specs.erl b/test_projects/standard/eqwalizer/src/eqwalizer_specs.erl similarity index 100% rename from test/test_projects/standard/eqwalizer/src/eqwalizer_specs.erl rename to test_projects/standard/eqwalizer/src/eqwalizer_specs.erl diff --git a/test/test_projects/standard/erlang_ls.config b/test_projects/standard/erlang_ls.config similarity index 100% rename from test/test_projects/standard/erlang_ls.config rename to test_projects/standard/erlang_ls.config diff --git a/test/test_projects/standard/rebar.config b/test_projects/standard/rebar.config similarity index 100% rename from test/test_projects/standard/rebar.config rename to test_projects/standard/rebar.config diff --git a/website/docs/erlang-error-index/w/W0045.md b/website/docs/erlang-error-index/w/W0045.md index c68f83ef4d..13c908d8a0 100644 --- a/website/docs/erlang-error-index/w/W0045.md +++ b/website/docs/erlang-error-index/w/W0045.md @@ -8,7 +8,7 @@ sidebar_position: 45 ```erlang -module(my_module). - %% ^^^^^^^^^ warning: A module with this name exists elsewhere + %% ^^^^^^^^^ warning: Duplicate module name ``` ## Explanation diff --git a/website/docs/erlang-error-index/w/W0048.md b/website/docs/erlang-error-index/w/W0048.md index a6e1631148..42d21cec9c 100644 --- a/website/docs/erlang-error-index/w/W0048.md +++ b/website/docs/erlang-error-index/w/W0048.md @@ -9,7 +9,7 @@ sidebar_position: 48 ```erlang -module(main). -dialyzer({nowarn_function, foo/0}). -%% ^^^^^^^^^ 💡 warning: Avoid using the -dialyzer attribute. +%% ^^^^^^^^^ 💡 warning: Avoid -dialyzer attribute. ``` ## Explanation diff --git a/website/docs/erlang-error-index/w/W0050.md b/website/docs/erlang-error-index/w/W0050.md index 8c8210dcca..a0d43d7171 100644 --- a/website/docs/erlang-error-index/w/W0050.md +++ b/website/docs/erlang-error-index/w/W0050.md @@ -20,26 +20,40 @@ size(Input) -> ## Explanation -The [`size/1`](https://www.erlang.org/doc/apps/erts/erlang#size/1) BIF can be -used to return the size tuples, binaries and bitstrings. +The [`size/1`](https://www.erlang.org/doc/apps/erts/erlang#size/1) BIF returns +the size for both tuples and binaries. -However, this BIF is not optimized by the -[JIT](https://www.erlang.org/doc/apps/erts/beamasm.html); it may report -inaccurate values for bitstrings, and its use can result in worse types for -[dialyzer](https://www.erlang.org/doc/apps/dialyzer/dialyzer.html). +The BIF is not optimized by the +[JIT](https://www.erlang.org/doc/apps/erts/beamasm.html) though, and its use can +result in worse types for +[dialyzer](https://www.erlang.org/doc/apps/dialyzer/dialyzer.html) and +[eqWAlizer](https://github.com/WhatsApp/eqwalizer). -What to do instead: +When one knows that the value being tested must be a tuple, `tuple_size/1` +should always be preferred. -- For tuples, use `tuple_size/1`. +When one knows that the value being tested must be a binary, `byte_size/1` +should be preferred. However, `byte_size/1` also accepts a bitstring (rounding +up size to a whole number of bytes), so one must make sure that the call to +`byte_size/1` is preceded by a call to `is_binary/1` to ensure that bitstrings +are rejected. Note that the compiler removes redundant calls to `is_binary/1`, +so if one is not sure whether previous code had made sure that the argument is a +binary, it does not harm to add an `is_binary/1` test immediately before the +call to `byte_size/1`. -- For binaries, use `byte_size/1`. - -- For bitstrings, use `byte_size/1`, but please notice that while `byte_size/1` - rounds _up_ to the nearest byte, `size/1` would round _down_: +For the above use case, a better approach would be: ```erlang -4 = byte_size(<<0:25>>). -3 = size(<<0:25>>). +-module(main). +-export([size/1]). + +-type input() :: tuple() | binary(). + +-spec size(input()) -> non_neg_integer(). +size(Input) when is_tuple(Input) -> + erlang:tuple_size(Input); +size(Input) when is_binary(Input) -> + erlang:byte_size(Input). ``` For more information, see the Erlang diff --git a/website/docs/erlang-error-index/w/W0056.md b/website/docs/erlang-error-index/w/W0056.md deleted file mode 100644 index 14848f5898..0000000000 --- a/website/docs/erlang-error-index/w/W0056.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -sidebar_position: 56 ---- - -# W0056 - Use `lists:reverse/2` instead of `lists:reverse/1 ++ Tail` - -## Warning - -```erlang -reverse_and_append(List, Tail) -> - lists:reverse(List) ++ Tail. -%% ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0056: Use `lists:reverse/2` instead of `lists:reverse/1 ++ Tail` for better performance. -``` - -## Explanation - -The warning indicates that you are using the pattern `lists:reverse(List) ++ Tail`, which is inefficient. This pattern first reverses the list, creating an intermediate reversed list, and then appends the tail to it using the `++` operator. - -The Erlang standard library provides a more efficient function `lists:reverse/2` that performs both operations in a single pass without creating the intermediate reversed list. - -### Why This Matters - -- **Performance**: Using `lists:reverse/1` followed by `++` creates an unnecessary intermediate data structure -- **Memory**: The intermediate reversed list consumes additional memory that is immediately discarded -- **Idiomatic Erlang**: `lists:reverse/2` is the idiomatic way to reverse and prepend in Erlang - -### Fix - -Replace the pattern with `lists:reverse/2`: - -```erlang -reverse_and_append(List, Tail) -> - lists:reverse(List, Tail). -``` - -### How lists:reverse/2 Works - -The second argument to `lists:reverse/2` acts as an accumulator that gets prepended to the reversed list: - -```erlang -lists:reverse([1, 2, 3], [4, 5, 6]). -% Returns: [3, 2, 1, 4, 5, 6] -``` - -This is equivalent to `lists:reverse([1, 2, 3]) ++ [4, 5, 6]` but significantly more efficient. diff --git a/website/docs/erlang-error-index/w/W0057.md b/website/docs/erlang-error-index/w/W0057.md deleted file mode 100644 index 990c4648b6..0000000000 --- a/website/docs/erlang-error-index/w/W0057.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -sidebar_position: 57 ---- - -# W0057 - Undefined macro - -## Error - -```erlang --module(example). - -foo() -> - ?UNDEFINED_MACRO. -%% ^^^^^^^^^^^^^^^^ error: W0057: undefined macro 'UNDEFINED_MACRO' - -bar(X) -> - ?UNDEFINED_WITH_ARGS(X, 42). -%% ^^^^^^^^^^^^^^^^^^^^ error: W0057: undefined macro 'UNDEFINED_WITH_ARGS/2' -``` - -This diagnostic is triggered when a macro usage cannot be resolved in ELP native -diagnostic processing. The macro is referenced in the code but has not been defined -in the current file or any included header files. - -**Important:** This diagnostic corresponds to Erlang service diagnostics -**E1507** (for macros without arguments) and **E1508** (for macros with -arguments). W0057 only appears when the corresponding Erlang service diagnostic -does not appear. If you see W0057 in a Buck project, it is likely a sign that -the project is not defined properly in your TARGETS/BUCK file. - -## Common Causes - -1. **Missing macro definition**: The macro has not been defined with - `-define()`. -2. **Missing include file**: The macro is defined in a header file that has not - been included. -3. **Typo in macro name**: The macro name is misspelled. -4. **Conditional compilation**: The macro is defined within a conditional block - (e.g., `-ifdef()`) that is not active. - -## Fix - -### Define the macro - -If the macro is not defined anywhere, add a `-define()` directive: - -```erlang --module(example). - --define(UNDEFINED_MACRO, 42). --define(UNDEFINED_WITH_ARGS(X, Y), X + Y). - -foo() -> - ?UNDEFINED_MACRO. - -bar(X) -> - ?UNDEFINED_WITH_ARGS(X, 42). -``` - -### Include the header file - -If the macro is defined in a header file, add the appropriate `-include()` or -`-include_lib()` directive: - -```erlang --module(example). - --include("macros.hrl"). - -foo() -> - ?UNDEFINED_MACRO. -``` - -### Fix typos - -If the macro name is misspelled, correct it to match the definition: - -```erlang --module(example). - --define(DEFINED_MACRO, 42). - -foo() -> - ?DEFINED_MACRO. % Fixed typo -``` - -## Relationship to Erlang Service Diagnostics - -W0057 is filtered out when the Erlang service reports the corresponding -diagnostics: - -- **E1507**: undefined macro (without arguments) -- **E1508**: undefined macro (with arguments) - -When both diagnostics detect the same issue, only the Erlang service diagnostic -will be shown to avoid duplication. - -## Buck Project Configuration - -If you see W0057 in a Buck project, this typically indicates that your TARGETS -file is not properly configured. The Erlang service relies on Buck to understand -the project structure, dependencies, and include paths. Check that: - -- All application dependencies are declared in the `deps` attribute -- Include paths are properly configured -- The macro definition is in an accessible dependency diff --git a/website/docs/erlang-error-index/w/W0058.md b/website/docs/erlang-error-index/w/W0058.md deleted file mode 100644 index acad4c2d79..0000000000 --- a/website/docs/erlang-error-index/w/W0058.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -sidebar_position: 58 ---- - -# W0058 - Can't find include file - -## Error - -```erlang --module(example). - --include("missing_header.hrl"). -%% error: W0058: can't find include file "missing_header.hrl" - --include_lib("missing_app/include/header.hrl"). -%% error: W0058: can't find include lib "missing_app/include/header.hrl" -``` - -This diagnostic is triggered when an include file referenced by `-include()` or -`-include_lib()` cannot be resolved by the ELP native diagnostic processing. -The file path cannot be found in the search paths available to ELP. - -**Important:** This diagnostic corresponds to Erlang service diagnostic -**E1516** (can't find include file/lib). W0058 only appears when the -corresponding Erlang service diagnostic does not appear. If you see W0058 in a -Buck project, it is likely a sign that the project is not defined properly in -your TARGETS file. - -## Common Causes - -1. **Missing file**: The include file does not exist at the specified path. -2. **Incorrect path**: The path to the include file is incorrect or misspelled. -3. **Missing application dependency**: For `-include_lib()`, the referenced - application is not listed as a dependency. -4. **Incorrect include path configuration**: The directory containing the header - file is not in the configured include paths. - -## Fix - -### Verify the file exists - -Make sure the include file exists at the expected location. - -### Fix the path - -Correct the path to match the actual file location: - -```erlang --module(example). - -% Correct path to the include file --include("correct_header.hrl"). - -% Correct application name and path --include_lib("correct_app/include/header.hrl"). -``` - -### Add missing dependency - -For `-include_lib()`, ensure the application is listed as a dependency in your -build configuration: - -**rebar.config:** - -```erlang -{deps, [ - missing_app -]}. -``` - -**Buck TARGETS file:** - -```python -erlang_app( - name = "my_app", - deps = [ - "//path/to:missing_app", - ], -) -``` - -### Configure include paths - -Ensure the directory containing the header file is in your project's include -paths configuration. - -## Relationship to Erlang Service Diagnostics - -W0058 is filtered out when the Erlang service reports the corresponding -diagnostic: - -- **E1516**: can't find include file/lib - -When both diagnostics detect the same issue, only the Erlang service diagnostic -will be shown to avoid duplication. - -## Buck Project Configuration - -If you see W0058 in a Buck project, this typically indicates that your TARGETS -file is not properly configured. The Erlang service relies on Buck to understand -the project structure, dependencies, and include paths. Check that: - -- All application dependencies are declared in the `deps` attribute -- For `-include_lib()` directives, the referenced application is included as a - dependency -- Include paths are properly configured with the `include` or `include_lib` - attributes -- The header file is defined in a dependency of the buck target holding the current file diff --git a/website/docs/erlang-error-index/w/W0059.md b/website/docs/erlang-error-index/w/W0059.md deleted file mode 100644 index fd2e990cb3..0000000000 --- a/website/docs/erlang-error-index/w/W0059.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -sidebar_position: 59 ---- - -# W0059: Unavailable Type - -## Error - -```erlang --module(main). --spec foo() -> dep:nonexistent_type(). -%% ^^^^^^^^^^^^^^^^^^^^^^ warning: W0059: Type 'dep:nonexistent_type/0' is not available through dependencies. -foo() -> ok. -``` - -## Explanation - -This diagnostic warns you when your code references a type that either: - -1. Does not exist (is undefined) -2. Is not accessible because it's from a module outside your application's dependencies -3. Exists but is not exported from the defining module - - -### What This Diagnostic Checks - -The diagnostic examines: - -- Type specifications (`-spec` attributes) -- Type definitions (`-type` and `-opaque` attributes) -- Callback specifications (`-callback` attributes) - -## How to Fix - -* Check if the type actually exists -* Verify the name and arity of the type -* Add the application that defines the type to your application's dependencies or move the type definition to an application that is already a dependency diff --git a/website/docs/erlang-error-index/w/W0060.md b/website/docs/erlang-error-index/w/W0060.md deleted file mode 100644 index 91b972dacf..0000000000 --- a/website/docs/erlang-error-index/w/W0060.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -sidebar_position: 60 ---- - -# W0060 - Bound Variable in LHS - -## Error - -```erlang -handle_request(Message) -> - Message = next_action(). -%% ^^^^^^^ 💡 warning: W0060: Match on a bound variable -``` - -## Explanation - -This diagnostic flags cases where a variable that is already bound appears on the left-hand side (LHS) of a match expression. This can be problematic if the binding is not intentional and can lead to subtle bugs. - -Consider the following code snippet: - -```erlang showLineNumbers -foo() -> - AA = foo(), - AA = bar(). -``` - -The pattern on line `3` will only match if and only if the result of the call to `bar/0` is the same as the call to `foo/0`. This behaviour could be intentional or not. If not, it can easily lead to bugs. - -An alternative, more explicit, way to express that behaviour - when intentional - could be: - -```erlang showLineNumbers -foo() -> - AA = foo(), - BB = bar(), - AA = BB. -``` - -Or using an assertion: - -```erlang showLineNumbers -foo() -> - AA = foo(), - ?assertEqual(AA, bar()). -``` - -## Semantic highlighting - -Note that we also have semantic highlighting of the more general case, where a bound variable appears in any pattern. diff --git a/website/docs/get-started/configure-project/elp-toml.md b/website/docs/get-started/configure-project/elp-toml.md index 90a9eb5f1e..931d207989 100644 --- a/website/docs/get-started/configure-project/elp-toml.md +++ b/website/docs/get-started/configure-project/elp-toml.md @@ -111,21 +111,9 @@ Configure the interaction between ELP and the [Buck2](https://buck2.build/) build tool. See [this presentation](https://youtu.be/4ALgsBqNBhQ) for details about Erlang support for Buck2. -| Key | Type | Description | Default | -| ----------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------ | ---------------------- | -| enabled | Boolean | Discover the project using Buck2 | | -| test_application_labels | Array of Strings | Buck2 labels that identify test application targets. Targets with any of these labels will be treated as test utilities. | `["test_application"]` | - -The `test_application_labels` setting allows you to customize which Buck2 labels -indicate test applications. This is useful for: - -Example usage: - -```toml -[buck] -enabled = true -test_application_labels = ["test_application", "integration_test", "e2e_test"] -``` +| Key | Type | Description | +| ------- | ------- | -------------------------------- | +| enabled | Boolean | Discover the project using Buck2 | :::warning diff --git a/website/docs/get-started/editors/emacs.md b/website/docs/get-started/editors/emacs.md index fab357f4a4..5111167df6 100644 --- a/website/docs/get-started/editors/emacs.md +++ b/website/docs/get-started/editors/emacs.md @@ -4,22 +4,17 @@ sidebar_position: 2 # Emacs -The ELP project can be used as a -[language server](https://microsoft.github.io/language-server-protocol/overviews/lsp/overview/) -in the Emacs text editor via the [eglot](https://github.com/joaotavora/eglot) or -[lsp-mode](https://emacs-lsp.github.io/lsp-mode/) LSP clients. +The ELP project can be used as a [language server](https://microsoft.github.io/language-server-protocol/overviews/lsp/overview/) in the Emacs text editor via the [eglot](https://github.com/joaotavora/eglot) or [lsp-mode](https://emacs-lsp.github.io/lsp-mode/) LSP clients. ## Eglot -Eglot is part of Emacs core since Emacs 29. For earlier versions it can be -installed with the `eglot` package. +Eglot is part of Emacs core since Emacs 29. +For earlier versions it can be installed with the `eglot` package. ### Configuration ```elisp (use-package eglot - :ensure t - :hook ((erlang-mode . eglot-ensure)) :config ;; Remove default LSP server @@ -28,81 +23,14 @@ installed with the `eglot` package. ;; Enable ELP (add-to-list 'eglot-server-programs - '(erlang-mode . ("elp" "server")))) + '(erlang-mode . ("elp" "server")) ``` -Refer to the -[manual](https://elpa.gnu.org/devel/doc/eglot.html#Customization-Variables) for -additional configuration options. - -### Semantic tokens - -Semantic token support has been added to eglot, but is not yet in the released -version. But it is possible to install the updated version of eglot. - -To do so, add - -```elisp -(add-to-list 'package-archives '("gnu-devel" . "https://elpa.gnu.org/devel/")) -``` - -to your `init.el`, then run `M-x eglot-upgrade-eglot` - -Once upgraded, add the following to the `(use-package` entry for `eglot` - -```elisp -(setq-default eglot-workspace-configuration - ;; Run `elp config` to see that options can be used here - ;; Use `eglot-show-workspace-configuration` to see what is sent - '(:elp (:highlightDynamic (:enable t) - :typesOnHover (:enable t) )) - - eglot-semantic-token-modifiers - '("bound" "exported_function" "exported_type" "deprecated_function" "type_dynamic")) - - ;; Each face name arises as a template from the modifiers as - ;; "eglot-semantic-%s-face" - (defface eglot-semantic-bound-face - '((t :underline t)) - "The face modification to use for bound variables in patterns." - :group 'eglot-semantic-semantic-tokens) - - (defface eglot-semantic-exported_function-face - '((t :underline t)) - "The face modification to use for exported functions." - :group 'eglot-semantic-semantic-tokens) - - (defface eglot-semantic-exported_type-face - '((t :underline t)) - "The face modification to use for exported types." - :group 'eglot-semantic-semantic-tokens) - - (defface eglot-semantic-deprecated_function-face - '((t :strike-through t)) - "The face modification to use for deprecated functions." - :group 'eglot-semantic-semantic-tokens) - - (defface eglot-semantic-type_dynamic-face - '((t (:weight bold))) - "The face modification to use for dynamic types." - :group 'eglot-semantic-semantic-tokens) - - ;; Bare eglot makes the refresh a no-op. Provide our own version for - ;; when Eqwalizer gets its results. - (cl-defmethod eglot-handle-request - (server (_method (eql workspace/semanticTokens/refresh)) &rest args) - "Handle workspace/semanticTokens/refresh by refreshing font-lock." - (dolist (buffer (eglot--managed-buffers server)) - (eglot--when-live-buffer buffer - (eglot--widening (font-lock-flush))))) -``` +Refer to the [manual](https://elpa.gnu.org/devel/doc/eglot.html#Customization-Variables) for additional configuration options. ## lsp-mode -Install the `lsp-mode` package, which is a generic Emacs client for LSP servers. -You can follow -[these instructions](https://emacs-lsp.github.io/lsp-mode/page/installation/) to -install it. +Install the `lsp-mode` package, which is a generic Emacs client for LSP servers. You can follow [these instructions](https://emacs-lsp.github.io/lsp-mode/page/installation/) to install it. ### Configuration @@ -124,21 +52,13 @@ Add the following to your emacs `.emacs` file or equivalent. ) ``` -For a list of available configuration option, please refer to -[this page](https://emacs-lsp.github.io/lsp-mode/page/lsp-erlang-elp/) and to -the -[`lsp-mode` settings documentation](https://emacs-lsp.github.io/lsp-mode/page/settings/mode/). - -There is also a -[`.dotemacs`](https://github.com/WhatsApp/erlang-language-platform/blob/main/editors/emacs/dotemacs.el) -file in the ELP repository that you can use as a reference. +For a list of available configuration option, please refer to [this page](https://emacs-lsp.github.io/lsp-mode/page/lsp-erlang-elp/) and to the [`lsp-mode` settings documentation](https://emacs-lsp.github.io/lsp-mode/page/settings/mode/). ## Troubleshooting #### The following servers support current file but do not have automatic installation -Ensure that the `elp` executable is available in your `PATH` via Emacs. A -workaround is: +Ensure that the `elp` executable is available in your `PATH` via Emacs. A workaround is: ```elisp ;; Ensure your Emacs environment looks like your user's shell one diff --git a/website/docs/get-started/install.md b/website/docs/get-started/install.md index 74cc3b9159..4c8adb7bb1 100644 --- a/website/docs/get-started/install.md +++ b/website/docs/get-started/install.md @@ -4,26 +4,9 @@ sidebar_position: 2 # Install ELP -The easiest way to install ELP on Mac is [using Homebrew](#using-homebrew-mac). -For other platforms, you can install [from binary](#from-binary). It is also +The easiest way to install to ELP is [from binary](#from-binary). It is also possible to compile it [from source](#from-source). -## Using Homebrew (Mac) - -Mac users can install ELP using the dedicated Homebrew formula: - -``` -brew install erlang-language-platform -``` - -This will install the latest version of ELP and make it available in your PATH. - -For more information about the Homebrew formula, visit: -https://formulae.brew.sh/formula/erlang-language-platform - -Follow [these steps](cli.md#verify-elp-is-correctly-installed) to verify ELP is -correctly installed. - ## From Binary Visit our diff --git a/website/package.json b/website/package.json index 49a34973ca..4053a7477f 100644 --- a/website/package.json +++ b/website/package.json @@ -16,12 +16,12 @@ "write-heading-ids": "docusaurus write-heading-ids" }, "dependencies": { - "@docusaurus/core": "3.9.2", - "@docusaurus/preset-classic": "3.9.2", + "@docusaurus/core": "3.6.3", + "@docusaurus/preset-classic": "3.6.3", "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", - "docusaurus-plugin-internaldocs-fb": "^1.18.4", "prism-react-renderer": "^2.3.0", + "docusaurus-plugin-internaldocs-fb": "^1.18.4", "react": "^18.0.0", "react-dom": "^18.0.0" }, @@ -62,11 +62,6 @@ "brace-expansion": ">=1.1.12", "webpack-dev-server": ">=5.2.1", "on-headers": ">=1.1.0", - "mermaid": ">=11.10.0", - "glob": ">=10.5.0", - "node-forge": ">=1.3.2", - "mdast-util-to-hast": ">=13.2.1", - "remark-rehype": ">=11.0.0", - "express": ">=4.22.0" + "mermaid": ">=11.10.0" } } diff --git a/website/yarn.lock b/website/yarn.lock index 1ac9f2033a..c07cd453c7 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -2,191 +2,274 @@ # yarn lockfile v1 -"@ai-sdk/gateway@2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@ai-sdk/gateway/-/gateway-2.0.9.tgz#33b77dfee9a068df7bd8e11b4e10b9f1ee4228dd" - integrity sha512-E6x4h5CPPPJ0za1r5HsLtHbeI+Tp3H+YFtcH8G3dSSPFE6w+PZINzB4NxLZmg1QqSeA5HTP3ZEzzsohp0o2GEw== +"@algolia/autocomplete-core@1.17.7": + version "1.17.7" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz#2c410baa94a47c5c5f56ed712bb4a00ebe24088b" + integrity sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q== dependencies: - "@ai-sdk/provider" "2.0.0" - "@ai-sdk/provider-utils" "3.0.17" - "@vercel/oidc" "3.0.3" + "@algolia/autocomplete-plugin-algolia-insights" "1.17.7" + "@algolia/autocomplete-shared" "1.17.7" -"@ai-sdk/provider-utils@3.0.17": - version "3.0.17" - resolved "https://registry.yarnpkg.com/@ai-sdk/provider-utils/-/provider-utils-3.0.17.tgz#2f3d0be398d3f165efe8dd252b63aea6ac3896d1" - integrity sha512-TR3Gs4I3Tym4Ll+EPdzRdvo/rc8Js6c4nVhFLuvGLX/Y4V9ZcQMa/HTiYsHEgmYrf1zVi6Q145UEZUfleOwOjw== +"@algolia/autocomplete-plugin-algolia-insights@1.17.7": + version "1.17.7" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz#7d2b105f84e7dd8f0370aa4c4ab3b704e6760d82" + integrity sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A== dependencies: - "@ai-sdk/provider" "2.0.0" - "@standard-schema/spec" "^1.0.0" - eventsource-parser "^3.0.6" + "@algolia/autocomplete-shared" "1.17.7" -"@ai-sdk/provider@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@ai-sdk/provider/-/provider-2.0.0.tgz#b853c739d523b33675bc74b6c506b2c690bc602b" - integrity sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA== +"@algolia/autocomplete-preset-algolia@1.17.7": + version "1.17.7" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz#c9badc0d73d62db5bf565d839d94ec0034680ae9" + integrity sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA== dependencies: - json-schema "^0.4.0" + "@algolia/autocomplete-shared" "1.17.7" -"@ai-sdk/react@^2.0.30": - version "2.0.93" - resolved "https://registry.yarnpkg.com/@ai-sdk/react/-/react-2.0.93.tgz#c81f8550a2ac44799c7527a75be19b1c3cf60dac" - integrity sha512-2TzhpQr10HuWxpqyHpSAUMRUqD1G2O73J2sAaJChomVDbjr7BwpM0mdR3aRamCXNtuLiJmTFQhbNzw8fXMBdYw== +"@algolia/autocomplete-shared@1.17.7": + version "1.17.7" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz#105e84ad9d1a31d3fb86ba20dc890eefe1a313a0" + integrity sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg== + +"@algolia/cache-browser-local-storage@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.24.0.tgz#97bc6d067a9fd932b9c922faa6b7fd6e546e1348" + integrity sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww== dependencies: - "@ai-sdk/provider-utils" "3.0.17" - ai "5.0.93" - swr "^2.2.5" - throttleit "2.1.0" + "@algolia/cache-common" "4.24.0" -"@algolia/abtesting@1.10.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@algolia/abtesting/-/abtesting-1.10.0.tgz#7f4c915d3e3188e6af101e6f4e829cda795d3caf" - integrity sha512-mQT3jwuTgX8QMoqbIR7mPlWkqQqBPQaPabQzm37xg2txMlaMogK/4hCiiESGdg39MlHZOVHeV+0VJuE7f5UK8A== +"@algolia/cache-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.24.0.tgz#81a8d3a82ceb75302abb9b150a52eba9960c9744" + integrity sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g== + +"@algolia/cache-in-memory@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.24.0.tgz#ffcf8872f3a10cb85c4f4641bdffd307933a6e44" + integrity sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w== dependencies: - "@algolia/client-common" "5.44.0" - "@algolia/requester-browser-xhr" "5.44.0" - "@algolia/requester-fetch" "5.44.0" - "@algolia/requester-node-http" "5.44.0" + "@algolia/cache-common" "4.24.0" -"@algolia/autocomplete-core@1.19.2": - version "1.19.2" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.19.2.tgz#702df67a08cb3cfe8c33ee1111ef136ec1a9e232" - integrity sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw== +"@algolia/client-abtesting@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@algolia/client-abtesting/-/client-abtesting-5.15.0.tgz#6414895e2246dc7b7facd97bd98c3abe13cabe59" + integrity sha512-FaEM40iuiv1mAipYyiptP4EyxkJ8qHfowCpEeusdHUC4C7spATJYArD2rX3AxkVeREkDIgYEOuXcwKUbDCr7Nw== dependencies: - "@algolia/autocomplete-plugin-algolia-insights" "1.19.2" - "@algolia/autocomplete-shared" "1.19.2" + "@algolia/client-common" "5.15.0" + "@algolia/requester-browser-xhr" "5.15.0" + "@algolia/requester-fetch" "5.15.0" + "@algolia/requester-node-http" "5.15.0" -"@algolia/autocomplete-plugin-algolia-insights@1.19.2": - version "1.19.2" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.2.tgz#3584b625b9317e333d1ae43664d02358e175c52d" - integrity sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg== +"@algolia/client-account@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.24.0.tgz#eba7a921d828e7c8c40a32d4add21206c7fe12f1" + integrity sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA== dependencies: - "@algolia/autocomplete-shared" "1.19.2" + "@algolia/client-common" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/transporter" "4.24.0" -"@algolia/autocomplete-shared@1.19.2": - version "1.19.2" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.2.tgz#c0b7b8dc30a5c65b70501640e62b009535e4578f" - integrity sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w== - -"@algolia/client-abtesting@5.44.0": - version "5.44.0" - resolved "https://registry.yarnpkg.com/@algolia/client-abtesting/-/client-abtesting-5.44.0.tgz#33e35fb59bfdb5bef26eb38902de5bdae3766e1e" - integrity sha512-KY5CcrWhRTUo/lV7KcyjrZkPOOF9bjgWpMj9z98VA+sXzVpZtkuskBLCKsWYFp2sbwchZFTd3wJM48H0IGgF7g== +"@algolia/client-analytics@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.24.0.tgz#9d2576c46a9093a14e668833c505ea697a1a3e30" + integrity sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg== dependencies: - "@algolia/client-common" "5.44.0" - "@algolia/requester-browser-xhr" "5.44.0" - "@algolia/requester-fetch" "5.44.0" - "@algolia/requester-node-http" "5.44.0" + "@algolia/client-common" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" -"@algolia/client-analytics@5.44.0": - version "5.44.0" - resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-5.44.0.tgz#2fdf0d41ac39fd071a9cde7c9a118b2ffb3ce8d9" - integrity sha512-LKOCE8S4ewI9bN3ot9RZoYASPi8b78E918/DVPW3HHjCMUe6i+NjbNG6KotU4RpP6AhRWZjjswbOkWelUO+OoA== +"@algolia/client-analytics@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-5.15.0.tgz#7ca1043cba7ac225d30e8bb52579504946b95f58" + integrity sha512-lho0gTFsQDIdCwyUKTtMuf9nCLwq9jOGlLGIeQGKDxXF7HbiAysFIu5QW/iQr1LzMgDyM9NH7K98KY+BiIFriQ== dependencies: - "@algolia/client-common" "5.44.0" - "@algolia/requester-browser-xhr" "5.44.0" - "@algolia/requester-fetch" "5.44.0" - "@algolia/requester-node-http" "5.44.0" + "@algolia/client-common" "5.15.0" + "@algolia/requester-browser-xhr" "5.15.0" + "@algolia/requester-fetch" "5.15.0" + "@algolia/requester-node-http" "5.15.0" -"@algolia/client-common@5.44.0": - version "5.44.0" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-5.44.0.tgz#aacc0fe3d07afae0d70bf7581b39d377f0bc0b7a" - integrity sha512-1yyJm4OYC2cztbS28XYVWwLXdwpLsMG4LoZLOltVglQ2+hc/i9q9fUDZyjRa2Bqt4DmkIfezagfMrokhyH4uxQ== - -"@algolia/client-insights@5.44.0": - version "5.44.0" - resolved "https://registry.yarnpkg.com/@algolia/client-insights/-/client-insights-5.44.0.tgz#350f93bab703fa102acf82685364732937369025" - integrity sha512-wVQWK6jYYsbEOjIMI+e5voLGPUIbXrvDj392IckXaCPvQ6vCMTXakQqOYCd+znQdL76S+3wHDo77HZWiAYKrtA== +"@algolia/client-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.24.0.tgz#77c46eee42b9444a1d1c1583a83f7df4398a649d" + integrity sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA== dependencies: - "@algolia/client-common" "5.44.0" - "@algolia/requester-browser-xhr" "5.44.0" - "@algolia/requester-fetch" "5.44.0" - "@algolia/requester-node-http" "5.44.0" + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" -"@algolia/client-personalization@5.44.0": - version "5.44.0" - resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-5.44.0.tgz#b2c20dc59026babd695c571eb6015a8b46acb892" - integrity sha512-lkgRjOjOkqmIkebHjHpU9rLJcJNUDMm+eVSW/KJQYLjGqykEZxal+nYJJTBbLceEU2roByP/+27ZmgIwCdf0iA== - dependencies: - "@algolia/client-common" "5.44.0" - "@algolia/requester-browser-xhr" "5.44.0" - "@algolia/requester-fetch" "5.44.0" - "@algolia/requester-node-http" "5.44.0" +"@algolia/client-common@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-5.15.0.tgz#cd47ae07a3afc7065438a2dab29f8434f848928e" + integrity sha512-IofrVh213VLsDkPoSKMeM9Dshrv28jhDlBDLRcVJQvlL8pzue7PEB1EZ4UoJFYS3NSn7JOcJ/V+olRQzXlJj1w== -"@algolia/client-query-suggestions@5.44.0": - version "5.44.0" - resolved "https://registry.yarnpkg.com/@algolia/client-query-suggestions/-/client-query-suggestions-5.44.0.tgz#d39d0b21fe6b38f8dab2f1f201db6d6e5225908f" - integrity sha512-sYfhgwKu6NDVmZHL1WEKVLsOx/jUXCY4BHKLUOcYa8k4COCs6USGgz6IjFkUf+niwq8NCECMmTC4o/fVQOalsA== +"@algolia/client-insights@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@algolia/client-insights/-/client-insights-5.15.0.tgz#f3bead0edd10e69365895da4a96044064b504f4d" + integrity sha512-bDDEQGfFidDi0UQUCbxXOCdphbVAgbVmxvaV75cypBTQkJ+ABx/Npw7LkFGw1FsoVrttlrrQbwjvUB6mLVKs/w== dependencies: - "@algolia/client-common" "5.44.0" - "@algolia/requester-browser-xhr" "5.44.0" - "@algolia/requester-fetch" "5.44.0" - "@algolia/requester-node-http" "5.44.0" + "@algolia/client-common" "5.15.0" + "@algolia/requester-browser-xhr" "5.15.0" + "@algolia/requester-fetch" "5.15.0" + "@algolia/requester-node-http" "5.15.0" -"@algolia/client-search@5.44.0": - version "5.44.0" - resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-5.44.0.tgz#04ca43ee8181bf16f9df085286214ad3c06de126" - integrity sha512-/FRKUM1G4xn3vV8+9xH1WJ9XknU8rkBGlefruq9jDhYUAvYozKimhrmC2pRqw/RyHhPivmgZCRuC8jHP8piz4Q== +"@algolia/client-personalization@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.24.0.tgz#8b47789fb1cb0f8efbea0f79295b7c5a3850f6ae" + integrity sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w== dependencies: - "@algolia/client-common" "5.44.0" - "@algolia/requester-browser-xhr" "5.44.0" - "@algolia/requester-fetch" "5.44.0" - "@algolia/requester-node-http" "5.44.0" + "@algolia/client-common" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/client-personalization@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-5.15.0.tgz#e962793ebf737a5ffa4867d2dfdfe17924be3833" + integrity sha512-LfaZqLUWxdYFq44QrasCDED5bSYOswpQjSiIL7Q5fYlefAAUO95PzBPKCfUhSwhb4rKxigHfDkd81AvEicIEoA== + dependencies: + "@algolia/client-common" "5.15.0" + "@algolia/requester-browser-xhr" "5.15.0" + "@algolia/requester-fetch" "5.15.0" + "@algolia/requester-node-http" "5.15.0" + +"@algolia/client-query-suggestions@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@algolia/client-query-suggestions/-/client-query-suggestions-5.15.0.tgz#d9a2d0d0660241bdae5fc36a6f1fcf339abbafeb" + integrity sha512-wu8GVluiZ5+il8WIRsGKu8VxMK9dAlr225h878GGtpTL6VBvwyJvAyLdZsfFIpY0iN++jiNb31q2C1PlPL+n/A== + dependencies: + "@algolia/client-common" "5.15.0" + "@algolia/requester-browser-xhr" "5.15.0" + "@algolia/requester-fetch" "5.15.0" + "@algolia/requester-node-http" "5.15.0" + +"@algolia/client-search@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.24.0.tgz#75e6c02d33ef3e0f34afd9962c085b856fc4a55f" + integrity sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA== + dependencies: + "@algolia/client-common" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/client-search@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-5.15.0.tgz#8645f5bc87a959b8008e021d8b31d55a47920b94" + integrity sha512-Z32gEMrRRpEta5UqVQA612sLdoqY3AovvUPClDfMxYrbdDAebmGDVPtSogUba1FZ4pP5dx20D3OV3reogLKsRA== + dependencies: + "@algolia/client-common" "5.15.0" + "@algolia/requester-browser-xhr" "5.15.0" + "@algolia/requester-fetch" "5.15.0" + "@algolia/requester-node-http" "5.15.0" "@algolia/events@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@algolia/events/-/events-4.0.1.tgz#fd39e7477e7bc703d7f893b556f676c032af3950" integrity sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ== -"@algolia/ingestion@1.44.0": - version "1.44.0" - resolved "https://registry.yarnpkg.com/@algolia/ingestion/-/ingestion-1.44.0.tgz#f6bd13216c5a589414f43f9bec78db55cb022d90" - integrity sha512-5+S5ynwMmpTpCLXGjTDpeIa81J+R4BLH0lAojOhmeGSeGEHQTqacl/4sbPyDTcidvnWhaqtyf8m42ue6lvISAw== +"@algolia/ingestion@1.15.0": + version "1.15.0" + resolved "https://registry.yarnpkg.com/@algolia/ingestion/-/ingestion-1.15.0.tgz#a3f3ec2139042f8597c2a975430a6f77cd764db3" + integrity sha512-MkqkAxBQxtQ5if/EX2IPqFA7LothghVyvPoRNA/meS2AW2qkHwcxjuiBxv4H6mnAVEPfJlhu9rkdVz9LgCBgJg== dependencies: - "@algolia/client-common" "5.44.0" - "@algolia/requester-browser-xhr" "5.44.0" - "@algolia/requester-fetch" "5.44.0" - "@algolia/requester-node-http" "5.44.0" + "@algolia/client-common" "5.15.0" + "@algolia/requester-browser-xhr" "5.15.0" + "@algolia/requester-fetch" "5.15.0" + "@algolia/requester-node-http" "5.15.0" -"@algolia/monitoring@1.44.0": - version "1.44.0" - resolved "https://registry.yarnpkg.com/@algolia/monitoring/-/monitoring-1.44.0.tgz#423fa61d68826a72cd5c468b45b232d8ba379775" - integrity sha512-xhaTN8pXJjR6zkrecg4Cc9YZaQK2LKm2R+LkbAq+AYGBCWJxtSGlNwftozZzkUyq4AXWoyoc0x2SyBtq5LRtqQ== - dependencies: - "@algolia/client-common" "5.44.0" - "@algolia/requester-browser-xhr" "5.44.0" - "@algolia/requester-fetch" "5.44.0" - "@algolia/requester-node-http" "5.44.0" +"@algolia/logger-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.24.0.tgz#28d439976019ec0a46ba7a1a739ef493d4ef8123" + integrity sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA== -"@algolia/recommend@5.44.0": - version "5.44.0" - resolved "https://registry.yarnpkg.com/@algolia/recommend/-/recommend-5.44.0.tgz#7e52b3e612bfd5bf82d14e05f577888a038279fa" - integrity sha512-GNcite/uOIS7wgRU1MT7SdNIupGSW+vbK9igIzMePvD2Dl8dy0O3urKPKIbTuZQqiVH1Cb84y5cgLvwNrdCj/Q== +"@algolia/logger-console@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.24.0.tgz#c6ff486036cd90b81d07a95aaba04461da7e1c65" + integrity sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg== dependencies: - "@algolia/client-common" "5.44.0" - "@algolia/requester-browser-xhr" "5.44.0" - "@algolia/requester-fetch" "5.44.0" - "@algolia/requester-node-http" "5.44.0" + "@algolia/logger-common" "4.24.0" -"@algolia/requester-browser-xhr@5.44.0": - version "5.44.0" - resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.44.0.tgz#a007b2c7b665224b04e61a1246fa015f06bd4100" - integrity sha512-YZHBk72Cd7pcuNHzbhNzF/FbbYszlc7JhZlDyQAchnX5S7tcemSS96F39Sy8t4O4WQLpFvUf1MTNedlitWdOsQ== +"@algolia/monitoring@1.15.0": + version "1.15.0" + resolved "https://registry.yarnpkg.com/@algolia/monitoring/-/monitoring-1.15.0.tgz#1eb58722ec9ea6e5de3621150f97a43571bd312e" + integrity sha512-QPrFnnGLMMdRa8t/4bs7XilPYnoUXDY8PMQJ1sf9ZFwhUysYYhQNX34/enoO0LBjpoOY6rLpha39YQEFbzgKyQ== dependencies: - "@algolia/client-common" "5.44.0" + "@algolia/client-common" "5.15.0" + "@algolia/requester-browser-xhr" "5.15.0" + "@algolia/requester-fetch" "5.15.0" + "@algolia/requester-node-http" "5.15.0" -"@algolia/requester-fetch@5.44.0": - version "5.44.0" - resolved "https://registry.yarnpkg.com/@algolia/requester-fetch/-/requester-fetch-5.44.0.tgz#055202db6b1ab37e042f207acb9e7f788e710089" - integrity sha512-B9WHl+wQ7uf46t9cq+vVM/ypVbOeuldVDq9OtKsX2ApL2g/htx6ImB9ugDOOJmB5+fE31/XPTuCcYz/j03+idA== +"@algolia/recommend@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/recommend/-/recommend-4.24.0.tgz#8a3f78aea471ee0a4836b78fd2aad4e9abcaaf34" + integrity sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw== dependencies: - "@algolia/client-common" "5.44.0" + "@algolia/cache-browser-local-storage" "4.24.0" + "@algolia/cache-common" "4.24.0" + "@algolia/cache-in-memory" "4.24.0" + "@algolia/client-common" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/logger-common" "4.24.0" + "@algolia/logger-console" "4.24.0" + "@algolia/requester-browser-xhr" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/requester-node-http" "4.24.0" + "@algolia/transporter" "4.24.0" -"@algolia/requester-node-http@5.44.0": - version "5.44.0" - resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-5.44.0.tgz#3e2f56491303d1a94d172e98a1560af350950c01" - integrity sha512-MULm0qeAIk4cdzZ/ehJnl1o7uB5NMokg83/3MKhPq0Pk7+I0uELGNbzIfAkvkKKEYcHALemKdArtySF9eKzh/A== +"@algolia/recommend@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@algolia/recommend/-/recommend-5.15.0.tgz#8f3359ee7e855849ac3872f67c0672f6835c8f79" + integrity sha512-5eupMwSqMLDObgSMF0XG958zR6GJP3f7jHDQ3/WlzCM9/YIJiWIUoJFGsko9GYsA5xbLDHE/PhWtq4chcCdaGQ== dependencies: - "@algolia/client-common" "5.44.0" + "@algolia/client-common" "5.15.0" + "@algolia/requester-browser-xhr" "5.15.0" + "@algolia/requester-fetch" "5.15.0" + "@algolia/requester-node-http" "5.15.0" + +"@algolia/requester-browser-xhr@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz#313c5edab4ed73a052e75803855833b62dd19c16" + integrity sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA== + dependencies: + "@algolia/requester-common" "4.24.0" + +"@algolia/requester-browser-xhr@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.15.0.tgz#5ffdccdf5cd7814ed3486bed418edb6db25c32a2" + integrity sha512-Po/GNib6QKruC3XE+WKP1HwVSfCDaZcXu48kD+gwmtDlqHWKc7Bq9lrS0sNZ456rfCKhXksOmMfUs4wRM/Y96w== + dependencies: + "@algolia/client-common" "5.15.0" + +"@algolia/requester-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.24.0.tgz#1c60c198031f48fcdb9e34c4057a3ea987b9a436" + integrity sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA== + +"@algolia/requester-fetch@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-fetch/-/requester-fetch-5.15.0.tgz#2ce94d4855090fac192b208d95eeea22e1ca4489" + integrity sha512-rOZ+c0P7ajmccAvpeeNrUmEKoliYFL8aOR5qGW5pFq3oj3Iept7Y5mEtEsOBYsRt6qLnaXn4zUKf+N8nvJpcIw== + dependencies: + "@algolia/client-common" "5.15.0" + +"@algolia/requester-node-http@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz#4461593714031d02aa7da221c49df675212f482f" + integrity sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw== + dependencies: + "@algolia/requester-common" "4.24.0" + +"@algolia/requester-node-http@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-5.15.0.tgz#e2020afcdaea56dc204bc6c82daab41478b32d87" + integrity sha512-b1jTpbFf9LnQHEJP5ddDJKE2sAlhYd7EVSOWgzo/27n/SfCoHfqD0VWntnWYD83PnOKvfe8auZ2+xCb0TXotrQ== + dependencies: + "@algolia/client-common" "5.15.0" + +"@algolia/transporter@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.24.0.tgz#226bb1f8af62430374c1972b2e5c8580ab275102" + integrity sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA== + dependencies: + "@algolia/cache-common" "4.24.0" + "@algolia/logger-common" "4.24.0" + "@algolia/requester-common" "4.24.0" "@ampproject/remapping@^2.2.0": version "2.3.0" @@ -209,7 +292,7 @@ resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-8.1.1.tgz#95b1947d292a9a2efffba2081796dcaa05ecedfb" integrity sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ== -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2", "@babel/code-frame@^7.8.3": version "7.26.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== @@ -1163,136 +1246,92 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== -"@csstools/cascade-layer-name-parser@^2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.5.tgz#43f962bebead0052a9fed1a2deeb11f85efcbc72" - integrity sha512-p1ko5eHgV+MgXFVa4STPKpvPxr6ReS8oS2jzTukjR74i5zJNyWO1ZM1m8YKBXnzDKWfBN1ztLYlHxbVemDD88A== +"@csstools/cascade-layer-name-parser@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.4.tgz#64d128529397aa1e1c986f685713363b262b81b1" + integrity sha512-7DFHlPuIxviKYZrOiwVU/PiHLm3lLUR23OMuEEtfEOQTOp9hzQ2JjdY6X5H18RVuUPJqSCI+qNnD5iOLMVE0bA== -"@csstools/color-helpers@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-5.1.0.tgz#106c54c808cabfd1ab4c602d8505ee584c2996ef" - integrity sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA== +"@csstools/color-helpers@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-5.0.1.tgz#829f1c76f5800b79c51c709e2f36821b728e0e10" + integrity sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA== -"@csstools/css-calc@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-2.1.4.tgz#8473f63e2fcd6e459838dd412401d5948f224c65" - integrity sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ== +"@csstools/css-calc@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-2.1.0.tgz#3f28b8f8f736b8f78abbc75eebd55c756207e773" + integrity sha512-X69PmFOrjTZfN5ijxtI8hZ9kRADFSLrmmQ6hgDJ272Il049WGKpDY64KhrFm/7rbWve0z81QepawzjkKlqkNGw== -"@csstools/css-color-parser@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz#4e386af3a99dd36c46fef013cfe4c1c341eed6f0" - integrity sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA== +"@csstools/css-color-parser@^3.0.6": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-3.0.6.tgz#e646838f6aab4618aeea7ba0c4921a254e180276" + integrity sha512-S/IjXqTHdpI4EtzGoNCHfqraXF37x12ZZHA1Lk7zoT5pm2lMjFuqhX/89L7dqX4CcMacKK+6ZCs5TmEGb/+wKw== dependencies: - "@csstools/color-helpers" "^5.1.0" - "@csstools/css-calc" "^2.1.4" + "@csstools/color-helpers" "^5.0.1" + "@csstools/css-calc" "^2.1.0" -"@csstools/css-parser-algorithms@^3.0.5": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz#5755370a9a29abaec5515b43c8b3f2cf9c2e3076" - integrity sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ== - -"@csstools/css-tokenizer@^3.0.4": +"@csstools/css-parser-algorithms@^3.0.4": version "3.0.4" - resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz#333fedabc3fd1a8e5d0100013731cf19e6a8c5d3" - integrity sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw== + resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz#74426e93bd1c4dcab3e441f5cc7ba4fb35d94356" + integrity sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A== -"@csstools/media-query-list-parser@^4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz#7aec77bcb89c2da80ef207e73f474ef9e1b3cdf1" - integrity sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ== +"@csstools/css-tokenizer@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz#a5502c8539265fecbd873c1e395a890339f119c2" + integrity sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw== -"@csstools/postcss-alpha-function@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@csstools/postcss-alpha-function/-/postcss-alpha-function-1.0.1.tgz#7989605711de7831bc7cd75b94c9b5bac9c3728e" - integrity sha512-isfLLwksH3yHkFXfCI2Gcaqg7wGGHZZwunoJzEZk0yKYIokgre6hYVFibKL3SYAoR1kBXova8LB+JoO5vZzi9w== - dependencies: - "@csstools/css-color-parser" "^3.1.0" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" - "@csstools/utilities" "^2.0.0" +"@csstools/media-query-list-parser@^4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz#e80e17eba1693fceafb8d6f2cfc68c0e7a9ab78a" + integrity sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A== -"@csstools/postcss-cascade-layers@^5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.2.tgz#dd2c70db3867b88975f2922da3bfbae7d7a2cae7" - integrity sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg== +"@csstools/postcss-cascade-layers@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.1.tgz#9640313e64b5e39133de7e38a5aa7f40dc259597" + integrity sha512-XOfhI7GShVcKiKwmPAnWSqd2tBR0uxt+runAxttbSp/LY2U16yAVPmAf7e9q4JJ0d+xMNmpwNDLBXnmRCl3HMQ== dependencies: "@csstools/selector-specificity" "^5.0.0" postcss-selector-parser "^7.0.0" -"@csstools/postcss-color-function-display-p3-linear@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@csstools/postcss-color-function-display-p3-linear/-/postcss-color-function-display-p3-linear-1.0.1.tgz#3017ff5e1f65307d6083e58e93d76724fb1ebf9f" - integrity sha512-E5qusdzhlmO1TztYzDIi8XPdPoYOjoTY6HBYBCYSj+Gn4gQRBlvjgPQXzfzuPQqt8EhkC/SzPKObg4Mbn8/xMg== +"@csstools/postcss-color-function@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-color-function/-/postcss-color-function-4.0.6.tgz#dabd1e516ccd4c7bd5803e37075a503b5f7f0ac4" + integrity sha512-EcvXfC60cTIumzpsxWuvVjb7rsJEHPvqn3jeMEBUaE3JSc4FRuP7mEQ+1eicxWmIrs3FtzMH9gR3sgA5TH+ebQ== dependencies: - "@csstools/css-color-parser" "^3.1.0" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" "@csstools/utilities" "^2.0.0" -"@csstools/postcss-color-function@^4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@csstools/postcss-color-function/-/postcss-color-function-4.0.12.tgz#a7c85a98c77b522a194a1bbb00dd207f40c7a771" - integrity sha512-yx3cljQKRaSBc2hfh8rMZFZzChaFgwmO2JfFgFr1vMcF3C/uyy5I4RFIBOIWGq1D+XbKCG789CGkG6zzkLpagA== +"@csstools/postcss-color-mix-function@^3.0.6": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.6.tgz#d971832ec30b3b60363bceddfeb4b90c7cc0f4b8" + integrity sha512-jVKdJn4+JkASYGhyPO+Wa5WXSx1+oUgaXb3JsjJn/BlrtFh5zjocCY7pwWi0nuP24V1fY7glQsxEYcYNy0dMFg== dependencies: - "@csstools/css-color-parser" "^3.1.0" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" "@csstools/utilities" "^2.0.0" -"@csstools/postcss-color-mix-function@^3.0.12": - version "3.0.12" - resolved "https://registry.yarnpkg.com/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.12.tgz#2f1ee9f8208077af069545c9bd79bb9733382c2a" - integrity sha512-4STERZfCP5Jcs13P1U5pTvI9SkgLgfMUMhdXW8IlJWkzOOOqhZIjcNhWtNJZes2nkBDsIKJ0CJtFtuaZ00moag== +"@csstools/postcss-content-alt-text@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.4.tgz#76f4687fb15ed45bc1139bb71e5775779762897a" + integrity sha512-YItlZUOuZJCBlRaCf8Aucc1lgN41qYGALMly0qQllrxYJhiyzlI6RxOTMUvtWk+KhS8GphMDsDhKQ7KTPfEMSw== dependencies: - "@csstools/css-color-parser" "^3.1.0" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" "@csstools/utilities" "^2.0.0" -"@csstools/postcss-color-mix-variadic-function-arguments@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@csstools/postcss-color-mix-variadic-function-arguments/-/postcss-color-mix-variadic-function-arguments-1.0.2.tgz#b4012b62a4eaa24d694172bb7137f9d2319cb8f2" - integrity sha512-rM67Gp9lRAkTo+X31DUqMEq+iK+EFqsidfecmhrteErxJZb6tUoJBVQca1Vn1GpDql1s1rD1pKcuYzMsg7Z1KQ== +"@csstools/postcss-exponential-functions@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.5.tgz#0c39f75df3357ee1e444b0aa0ede4e12aafea0e9" + integrity sha512-mi8R6dVfA2nDoKM3wcEi64I8vOYEgQVtVKCfmLHXupeLpACfGAided5ddMt5f+CnEodNu4DifuVwb0I6fQDGGQ== dependencies: - "@csstools/css-color-parser" "^3.1.0" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" - "@csstools/utilities" "^2.0.0" - -"@csstools/postcss-content-alt-text@^2.0.8": - version "2.0.8" - resolved "https://registry.yarnpkg.com/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.8.tgz#1d52da1762893c32999ff76839e48d6ec7c7a4cb" - integrity sha512-9SfEW9QCxEpTlNMnpSqFaHyzsiRpZ5J5+KqCu1u5/eEJAWsMhzT40qf0FIbeeglEvrGRMdDzAxMIz3wqoGSb+Q== - dependencies: - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" - "@csstools/utilities" "^2.0.0" - -"@csstools/postcss-contrast-color-function@^2.0.12": - version "2.0.12" - resolved "https://registry.yarnpkg.com/@csstools/postcss-contrast-color-function/-/postcss-contrast-color-function-2.0.12.tgz#ca46986d095c60f208d9e3f24704d199c9172637" - integrity sha512-YbwWckjK3qwKjeYz/CijgcS7WDUCtKTd8ShLztm3/i5dhh4NaqzsbYnhm4bjrpFpnLZ31jVcbK8YL77z3GBPzA== - dependencies: - "@csstools/css-color-parser" "^3.1.0" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" - "@csstools/utilities" "^2.0.0" - -"@csstools/postcss-exponential-functions@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.9.tgz#fc03d1272888cb77e64cc1a7d8a33016e4f05c69" - integrity sha512-abg2W/PI3HXwS/CZshSa79kNWNZHdJPMBXeZNyPQFbbj8sKO3jXxOt/wF7juJVjyDTc6JrvaUZYFcSBZBhaxjw== - dependencies: - "@csstools/css-calc" "^2.1.4" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" + "@csstools/css-calc" "^2.1.0" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" "@csstools/postcss-font-format-keywords@^4.0.0": version "4.0.0" @@ -1302,67 +1341,67 @@ "@csstools/utilities" "^2.0.0" postcss-value-parser "^4.2.0" -"@csstools/postcss-gamut-mapping@^2.0.11": - version "2.0.11" - resolved "https://registry.yarnpkg.com/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.11.tgz#be0e34c9f0142852cccfc02b917511f0d677db8b" - integrity sha512-fCpCUgZNE2piVJKC76zFsgVW1apF6dpYsqGyH8SIeCcM4pTEsRTWTLCaJIMKFEundsCKwY1rwfhtrio04RJ4Dw== +"@csstools/postcss-gamut-mapping@^2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.6.tgz#04ec6a50fdbca2a30dec56e6bb780c79621e47a7" + integrity sha512-0ke7fmXfc8H+kysZz246yjirAH6JFhyX9GTlyRnM0exHO80XcA9zeJpy5pOp5zo/AZiC/q5Pf+Hw7Pd6/uAoYA== dependencies: - "@csstools/css-color-parser" "^3.1.0" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" -"@csstools/postcss-gradients-interpolation-method@^5.0.12": - version "5.0.12" - resolved "https://registry.yarnpkg.com/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.12.tgz#0955cce4d97203b861bf66742bbec611b2f3661c" - integrity sha512-jugzjwkUY0wtNrZlFeyXzimUL3hN4xMvoPnIXxoZqxDvjZRiSh+itgHcVUWzJ2VwD/VAMEgCLvtaJHX+4Vj3Ow== +"@csstools/postcss-gradients-interpolation-method@^5.0.6": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.6.tgz#67fa61ada95e4534687fa76cd2d15ac74386560e" + integrity sha512-Itrbx6SLUzsZ6Mz3VuOlxhbfuyLTogG5DwEF1V8dAi24iMuvQPIHd7Ti+pNDp7j6WixndJGZaoNR0f9VSzwuTg== dependencies: - "@csstools/css-color-parser" "^3.1.0" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" "@csstools/utilities" "^2.0.0" -"@csstools/postcss-hwb-function@^4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.12.tgz#07f7ecb08c50e094673bd20eaf7757db0162beee" - integrity sha512-mL/+88Z53KrE4JdePYFJAQWFrcADEqsLprExCM04GDNgHIztwFzj0Mbhd/yxMBngq0NIlz58VVxjt5abNs1VhA== +"@csstools/postcss-hwb-function@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.6.tgz#c40f557a54ed45e75c601a9ba7a08d315f64dbd7" + integrity sha512-927Pqy3a1uBP7U8sTfaNdZVB0mNXzIrJO/GZ8us9219q9n06gOqCdfZ0E6d1P66Fm0fYHvxfDbfcUuwAn5UwhQ== dependencies: - "@csstools/css-color-parser" "^3.1.0" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" "@csstools/utilities" "^2.0.0" -"@csstools/postcss-ic-unit@^4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.4.tgz#2ee2da0690db7edfbc469279711b9e69495659d2" - integrity sha512-yQ4VmossuOAql65sCPppVO1yfb7hDscf4GseF0VCA/DTDaBc0Wtf8MTqVPfjGYlT5+2buokG0Gp7y0atYZpwjg== +"@csstools/postcss-ic-unit@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.0.tgz#b60ec06500717c337447c39ae7fe7952eeb9d48f" + integrity sha512-9QT5TDGgx7wD3EEMN3BSUG6ckb6Eh5gSPT5kZoVtUuAonfPmLDJyPhqR4ntPpMYhUKAMVKAg3I/AgzqHMSeLhA== dependencies: - "@csstools/postcss-progressive-custom-properties" "^4.2.1" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" "@csstools/utilities" "^2.0.0" postcss-value-parser "^4.2.0" -"@csstools/postcss-initial@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@csstools/postcss-initial/-/postcss-initial-2.0.1.tgz#c385bd9d8ad31ad159edd7992069e97ceea4d09a" - integrity sha512-L1wLVMSAZ4wovznquK0xmC7QSctzO4D0Is590bxpGqhqjboLXYA16dWZpfwImkdOgACdQ9PqXsuRroW6qPlEsg== +"@csstools/postcss-initial@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-initial/-/postcss-initial-2.0.0.tgz#a86f5fc59ab9f16f1422dade4c58bd941af5df22" + integrity sha512-dv2lNUKR+JV+OOhZm9paWzYBXOCi+rJPqJ2cJuhh9xd8USVrd0cBEPczla81HNOyThMQWeCcdln3gZkQV2kYxA== -"@csstools/postcss-is-pseudo-class@^5.0.3": - version "5.0.3" - resolved "https://registry.yarnpkg.com/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.3.tgz#d34e850bcad4013c2ed7abe948bfa0448aa8eb74" - integrity sha512-jS/TY4SpG4gszAtIg7Qnf3AS2pjcUM5SzxpApOrlndMeGhIbaTzWBzzP/IApXoNWEW7OhcjkRT48jnAUIFXhAQ== +"@csstools/postcss-is-pseudo-class@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.1.tgz#12041448fedf01090dd4626022c28b7f7623f58e" + integrity sha512-JLp3POui4S1auhDR0n8wHd/zTOWmMsmK3nQd3hhL6FhWPaox5W7j1se6zXOG/aP07wV2ww0lxbKYGwbBszOtfQ== dependencies: "@csstools/selector-specificity" "^5.0.0" postcss-selector-parser "^7.0.0" -"@csstools/postcss-light-dark-function@^2.0.11": - version "2.0.11" - resolved "https://registry.yarnpkg.com/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.11.tgz#0df448aab9a33cb9a085264ff1f396fb80c4437d" - integrity sha512-fNJcKXJdPM3Lyrbmgw2OBbaioU7yuKZtiXClf4sGdQttitijYlZMD5K7HrC/eF83VRWRrYq6OZ0Lx92leV2LFA== +"@csstools/postcss-light-dark-function@^2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.7.tgz#807c170cd28eebb0c00e64dfc6ab0bf418f19209" + integrity sha512-ZZ0rwlanYKOHekyIPaU+sVm3BEHCe+Ha0/px+bmHe62n0Uc1lL34vbwrLYn6ote8PHlsqzKeTQdIejQCJ05tfw== dependencies: - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" "@csstools/utilities" "^2.0.0" "@csstools/postcss-logical-float-and-clear@^3.0.0": @@ -1387,32 +1426,32 @@ dependencies: postcss-value-parser "^4.2.0" -"@csstools/postcss-logical-viewport-units@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.4.tgz#016d98a8b7b5f969e58eb8413447eb801add16fc" - integrity sha512-q+eHV1haXA4w9xBwZLKjVKAWn3W2CMqmpNpZUk5kRprvSiBEGMgrNH3/sJZ8UA3JgyHaOt3jwT9uFa4wLX4EqQ== +"@csstools/postcss-logical-viewport-units@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.3.tgz#f6cc63520ca2a6eb76b9cd946070c38dda66d733" + integrity sha512-OC1IlG/yoGJdi0Y+7duz/kU/beCwO+Gua01sD6GtOtLi7ByQUpcIqs7UE/xuRPay4cHgOMatWdnDdsIDjnWpPw== dependencies: - "@csstools/css-tokenizer" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" "@csstools/utilities" "^2.0.0" -"@csstools/postcss-media-minmax@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.9.tgz#184252d5b93155ae526689328af6bdf3fc113987" - integrity sha512-af9Qw3uS3JhYLnCbqtZ9crTvvkR+0Se+bBqSr7ykAnl9yKhk6895z9rf+2F4dClIDJWxgn0iZZ1PSdkhrbs2ig== +"@csstools/postcss-media-minmax@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.5.tgz#66970aa8d8057f84b88aff21f385194fbe03eb11" + integrity sha512-sdh5i5GToZOIAiwhdntRWv77QDtsxP2r2gXW/WbLSCoLr00KTq/yiF1qlQ5XX2+lmiFa8rATKMcbwl3oXDMNew== dependencies: - "@csstools/css-calc" "^2.1.4" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/media-query-list-parser" "^4.0.3" + "@csstools/css-calc" "^2.1.0" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/media-query-list-parser" "^4.0.2" -"@csstools/postcss-media-queries-aspect-ratio-number-values@^3.0.5": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.5.tgz#f485c31ec13d6b0fb5c528a3474334a40eff5f11" - integrity sha512-zhAe31xaaXOY2Px8IYfoVTB3wglbJUVigGphFLj6exb7cjZRH9A6adyE22XfFK3P2PzwRk0VDeTJmaxpluyrDg== +"@csstools/postcss-media-queries-aspect-ratio-number-values@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.4.tgz#d71102172c74baf3f892fac88cf1ea46a961600d" + integrity sha512-AnGjVslHMm5xw9keusQYvjVWvuS7KWK+OJagaG0+m9QnIjZsrysD2kJP/tr/UJIyYtMCtu8OkUd+Rajb4DqtIQ== dependencies: - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/media-query-list-parser" "^4.0.3" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/media-query-list-parser" "^4.0.2" "@csstools/postcss-nested-calc@^4.0.0": version "4.0.0" @@ -1429,42 +1468,42 @@ dependencies: postcss-value-parser "^4.2.0" -"@csstools/postcss-oklab-function@^4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.12.tgz#416640ef10227eea1375b47b72d141495950971d" - integrity sha512-HhlSmnE1NKBhXsTnNGjxvhryKtO7tJd1w42DKOGFD6jSHtYOrsJTQDKPMwvOfrzUAk8t7GcpIfRyM7ssqHpFjg== +"@csstools/postcss-oklab-function@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.6.tgz#17e8dfb6422dfd8d77256def5d5be8335ea7af34" + integrity sha512-Hptoa0uX+XsNacFBCIQKTUBrFKDiplHan42X73EklG6XmQLG7/aIvxoNhvZ7PvOWMt67Pw3bIlUY2nD6p5vL8A== dependencies: - "@csstools/css-color-parser" "^3.1.0" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" "@csstools/utilities" "^2.0.0" -"@csstools/postcss-progressive-custom-properties@^4.2.1": - version "4.2.1" - resolved "https://registry.yarnpkg.com/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.2.1.tgz#c39780b9ff0d554efb842b6bd75276aa6f1705db" - integrity sha512-uPiiXf7IEKtUQXsxu6uWtOlRMXd2QWWy5fhxHDnPdXKCQckPP3E34ZgDoZ62r2iT+UOgWsSbM4NvHE5m3mAEdw== +"@csstools/postcss-progressive-custom-properties@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.0.0.tgz#ecdb85bcdb1852d73970a214a376684a91f82bdc" + integrity sha512-XQPtROaQjomnvLUSy/bALTR5VCtTVUFwYs1SblvYgLSeTo2a/bMNwUwo2piXw5rTv/FEYiy5yPSXBqg9OKUx7Q== dependencies: postcss-value-parser "^4.2.0" -"@csstools/postcss-random-function@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@csstools/postcss-random-function/-/postcss-random-function-2.0.1.tgz#3191f32fe72936e361dadf7dbfb55a0209e2691e" - integrity sha512-q+FQaNiRBhnoSNo+GzqGOIBKoHQ43lYz0ICrV+UudfWnEF6ksS6DsBIJSISKQT2Bvu3g4k6r7t0zYrk5pDlo8w== +"@csstools/postcss-random-function@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-random-function/-/postcss-random-function-1.0.1.tgz#73a0b62b5dbbc03c25a28f085235eb61b09a2fb0" + integrity sha512-Ab/tF8/RXktQlFwVhiC70UNfpFQRhtE5fQQoP2pO+KCPGLsLdWFiOuHgSRtBOqEshCVAzR4H6o38nhvRZq8deA== dependencies: - "@csstools/css-calc" "^2.1.4" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" + "@csstools/css-calc" "^2.1.0" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" -"@csstools/postcss-relative-color-syntax@^3.0.12": - version "3.0.12" - resolved "https://registry.yarnpkg.com/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.12.tgz#ced792450102441f7c160e1d106f33e4b44181f8" - integrity sha512-0RLIeONxu/mtxRtf3o41Lq2ghLimw0w9ByLWnnEVuy89exmEEq8bynveBxNW3nyHqLAFEeNtVEmC1QK9MZ8Huw== +"@csstools/postcss-relative-color-syntax@^3.0.6": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.6.tgz#4b8bc219b34b16f5abdbbcf09ac13e65bff6ef16" + integrity sha512-yxP618Xb+ji1I624jILaYM62uEmZcmbdmFoZHoaThw896sq0vU39kqTTF+ZNic9XyPtPMvq0vyvbgmHaszq8xg== dependencies: - "@csstools/css-color-parser" "^3.1.0" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" "@csstools/utilities" "^2.0.0" "@csstools/postcss-scope-pseudo-class@^4.0.1": @@ -1474,50 +1513,50 @@ dependencies: postcss-selector-parser "^7.0.0" -"@csstools/postcss-sign-functions@^1.1.4": - version "1.1.4" - resolved "https://registry.yarnpkg.com/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.4.tgz#a9ac56954014ae4c513475b3f1b3e3424a1e0c12" - integrity sha512-P97h1XqRPcfcJndFdG95Gv/6ZzxUBBISem0IDqPZ7WMvc/wlO+yU0c5D/OCpZ5TJoTt63Ok3knGk64N+o6L2Pg== +"@csstools/postcss-sign-functions@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.0.tgz#a524fae1374b0e167729f612ca875d7b1b334262" + integrity sha512-SLcc20Nujx/kqbSwDmj6oaXgpy3UjFhBy1sfcqPgDkHfOIfUtUVH7OXO+j7BU4v/At5s61N5ZX6shvgPwluhsA== dependencies: - "@csstools/css-calc" "^2.1.4" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" + "@csstools/css-calc" "^2.1.0" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" -"@csstools/postcss-stepped-value-functions@^4.0.9": - version "4.0.9" - resolved "https://registry.yarnpkg.com/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.9.tgz#36036f1a0e5e5ee2308e72f3c9cb433567c387b9" - integrity sha512-h9btycWrsex4dNLeQfyU3y3w40LMQooJWFMm/SK9lrKguHDcFl4VMkncKKoXi2z5rM9YGWbUQABI8BT2UydIcA== +"@csstools/postcss-stepped-value-functions@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.5.tgz#4d68633d502fbe2b6ef3898e368e3540488a0d8a" + integrity sha512-G6SJ6hZJkhxo6UZojVlLo14MohH4J5J7z8CRBrxxUYy9JuZiIqUo5TBYyDGcE0PLdzpg63a7mHSJz3VD+gMwqw== dependencies: - "@csstools/css-calc" "^2.1.4" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" + "@csstools/css-calc" "^2.1.0" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" -"@csstools/postcss-text-decoration-shorthand@^4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.3.tgz#fae1b70f07d1b7beb4c841c86d69e41ecc6f743c" - integrity sha512-KSkGgZfx0kQjRIYnpsD7X2Om9BUXX/Kii77VBifQW9Ih929hK0KNjVngHDH0bFB9GmfWcR9vJYJJRvw/NQjkrA== +"@csstools/postcss-text-decoration-shorthand@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.1.tgz#251fab0939d50c6fd73bb2b830b2574188efa087" + integrity sha512-xPZIikbx6jyzWvhms27uugIc0I4ykH4keRvoa3rxX5K7lEhkbd54rjj/dv60qOCTisoS+3bmwJTeyV1VNBrXaw== dependencies: - "@csstools/color-helpers" "^5.1.0" + "@csstools/color-helpers" "^5.0.1" postcss-value-parser "^4.2.0" -"@csstools/postcss-trigonometric-functions@^4.0.9": - version "4.0.9" - resolved "https://registry.yarnpkg.com/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.9.tgz#3f94ed2e319b57f2c59720b64e4d0a8a6fb8c3b2" - integrity sha512-Hnh5zJUdpNrJqK9v1/E3BbrQhaDTj5YiX7P61TOvUhoDHnUmsNNxcDAgkQ32RrcWx9GVUvfUNPcUkn8R3vIX6A== +"@csstools/postcss-trigonometric-functions@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.5.tgz#267b95a8bd45536e0360596b6da660a9eb6aac83" + integrity sha512-/YQThYkt5MLvAmVu7zxjhceCYlKrYddK6LEmK5I4ojlS6BmO9u2yO4+xjXzu2+NPYmHSTtP4NFSamBCMmJ1NJA== dependencies: - "@csstools/css-calc" "^2.1.4" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" + "@csstools/css-calc" "^2.1.0" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" "@csstools/postcss-unset-value@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz#7caa981a34196d06a737754864baf77d64de4bba" integrity sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA== -"@csstools/selector-resolve-nested@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.1.0.tgz#848c6f44cb65e3733e478319b9342b7aa436fac7" - integrity sha512-mf1LEW0tJLKfWyvn5KdDrhpxHyuxpbNwTIwOYLIvsTffeyOf85j5oIzfG0yosxDgx/sswlqBnESYUcQH0vgZ0g== +"@csstools/selector-resolve-nested@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.0.0.tgz#704a9b637975680e025e069a4c58b3beb3e2752a" + integrity sha512-ZoK24Yku6VJU1gS79a5PFmC8yn3wIapiKmPgun0hZgEI5AOqgH2kiPRsPz1qkGv4HL+wuDLH83yQyk6inMYrJQ== "@csstools/selector-specificity@^5.0.0": version "5.0.0" @@ -1534,34 +1573,25 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@docsearch/core@4.3.1": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@docsearch/core/-/core-4.3.1.tgz#88a97a6fe4d4025269b6dee8b9d070b76758ad82" - integrity sha512-ktVbkePE+2h9RwqCUMbWXOoebFyDOxHqImAqfs+lC8yOU+XwEW4jgvHGJK079deTeHtdhUNj0PXHSnhJINvHzQ== +"@docsearch/css@3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.8.0.tgz#c70a1a326249d878ab7c630d7a908c6769a38db3" + integrity sha512-pieeipSOW4sQ0+bE5UFC51AOZp9NGxg89wAlZ1BAQFaiRAGK1IKUaPQ0UGZeNctJXyqZ1UvBtOQh2HH+U5GtmA== -"@docsearch/css@4.3.2": - version "4.3.2" - resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-4.3.2.tgz#d47d25336c9516b419245fa74e8dd5ae84a17492" - integrity sha512-K3Yhay9MgkBjJJ0WEL5MxnACModX9xuNt3UlQQkDEDZJZ0+aeWKtOkxHNndMRkMBnHdYvQjxkm6mdlneOtU1IQ== - -"@docsearch/react@^3.9.0 || ^4.1.0": - version "4.3.2" - resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-4.3.2.tgz#450b8341cb5cca03737a00075d4dfd3a904a3e3e" - integrity sha512-74SFD6WluwvgsOPqifYOviEEVwDxslxfhakTlra+JviaNcs7KK/rjsPj89kVEoQc9FUxRkAofaJnHIR7pb4TSQ== +"@docsearch/react@^3.5.2": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.8.0.tgz#c32165e34fadea8a0283c8b61cd73e6e1844797d" + integrity sha512-WnFK720+iwTVt94CxY3u+FgX6exb3BfN5kE9xUY6uuAH/9W/UFboBZFLlrw/zxFRHoHZCOXRtOylsXF+6LHI+Q== dependencies: - "@ai-sdk/react" "^2.0.30" - "@algolia/autocomplete-core" "1.19.2" - "@docsearch/core" "4.3.1" - "@docsearch/css" "4.3.2" - ai "^5.0.30" - algoliasearch "^5.28.0" - marked "^16.3.0" - zod "^4.1.8" + "@algolia/autocomplete-core" "1.17.7" + "@algolia/autocomplete-preset-algolia" "1.17.7" + "@docsearch/css" "3.8.0" + algoliasearch "^5.12.0" -"@docusaurus/babel@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/babel/-/babel-3.9.2.tgz#f956c638baeccf2040e482c71a742bc7e35fdb22" - integrity sha512-GEANdi/SgER+L7Japs25YiGil/AUDnFFHaCGPBbundxoWtCkA2lmy7/tFmgED4y1htAy6Oi4wkJEQdGssnw9MA== +"@docusaurus/babel@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/babel/-/babel-3.6.3.tgz#016714fe7a8807d0fc2f7180eace5e82bebbb8a6" + integrity sha512-7dW9Hat9EHYCVicFXYA4hjxBY38+hPuCURL8oRF9fySRm7vzNWuEOghA1TXcykuXZp0HLG2td4RhDxCvGG7tNw== dependencies: "@babel/core" "^7.25.9" "@babel/generator" "^7.25.9" @@ -1573,54 +1603,55 @@ "@babel/runtime" "^7.25.9" "@babel/runtime-corejs3" "^7.25.9" "@babel/traverse" "^7.25.9" - "@docusaurus/logger" "3.9.2" - "@docusaurus/utils" "3.9.2" + "@docusaurus/logger" "3.6.3" + "@docusaurus/utils" "3.6.3" babel-plugin-dynamic-import-node "^2.3.3" fs-extra "^11.1.1" tslib "^2.6.0" -"@docusaurus/bundler@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/bundler/-/bundler-3.9.2.tgz#0ca82cda4acf13a493e3f66061aea351e9d356cf" - integrity sha512-ZOVi6GYgTcsZcUzjblpzk3wH1Fya2VNpd5jtHoCCFcJlMQ1EYXZetfAnRHLcyiFeBABaI1ltTYbOBtH/gahGVA== +"@docusaurus/bundler@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/bundler/-/bundler-3.6.3.tgz#f09c2e29613f988b874a4be2247708e121b7fc5c" + integrity sha512-47JLuc8D4wA+6VOvmMd5fUC9rFppBQpQOnxDYiVXffm/DeV/wmm3sbpNd5Y+O+G2+nevLTRnvCm/qyancv0Y3A== dependencies: "@babel/core" "^7.25.9" - "@docusaurus/babel" "3.9.2" - "@docusaurus/cssnano-preset" "3.9.2" - "@docusaurus/logger" "3.9.2" - "@docusaurus/types" "3.9.2" - "@docusaurus/utils" "3.9.2" + "@docusaurus/babel" "3.6.3" + "@docusaurus/cssnano-preset" "3.6.3" + "@docusaurus/logger" "3.6.3" + "@docusaurus/types" "3.6.3" + "@docusaurus/utils" "3.6.3" babel-loader "^9.2.1" - clean-css "^5.3.3" + clean-css "^5.3.2" copy-webpack-plugin "^11.0.0" - css-loader "^6.11.0" + css-loader "^6.8.1" css-minimizer-webpack-plugin "^5.0.1" cssnano "^6.1.2" file-loader "^6.2.0" html-minifier-terser "^7.2.0" - mini-css-extract-plugin "^2.9.2" + mini-css-extract-plugin "^2.9.1" null-loader "^4.0.1" - postcss "^8.5.4" - postcss-loader "^7.3.4" - postcss-preset-env "^10.2.1" + postcss "^8.4.26" + postcss-loader "^7.3.3" + postcss-preset-env "^10.1.0" + react-dev-utils "^12.0.1" terser-webpack-plugin "^5.3.9" tslib "^2.6.0" url-loader "^4.1.1" webpack "^5.95.0" webpackbar "^6.0.1" -"@docusaurus/core@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-3.9.2.tgz#cc970f29b85a8926d63c84f8cffdcda43ed266ff" - integrity sha512-HbjwKeC+pHUFBfLMNzuSjqFE/58+rLVKmOU3lxQrpsxLBOGosYco/Q0GduBb0/jEMRiyEqjNT/01rRdOMWq5pw== +"@docusaurus/core@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-3.6.3.tgz#6bf968ee26a36d71387bab293f27ccffc0e428b6" + integrity sha512-xL7FRY9Jr5DWqB6pEnqgKqcMPJOX5V0pgWXi5lCiih11sUBmcFKM7c3+GyxcVeeWFxyYSDP3grLTWqJoP4P9Vw== dependencies: - "@docusaurus/babel" "3.9.2" - "@docusaurus/bundler" "3.9.2" - "@docusaurus/logger" "3.9.2" - "@docusaurus/mdx-loader" "3.9.2" - "@docusaurus/utils" "3.9.2" - "@docusaurus/utils-common" "3.9.2" - "@docusaurus/utils-validation" "3.9.2" + "@docusaurus/babel" "3.6.3" + "@docusaurus/bundler" "3.6.3" + "@docusaurus/logger" "3.6.3" + "@docusaurus/mdx-loader" "3.6.3" + "@docusaurus/utils" "3.6.3" + "@docusaurus/utils-common" "3.6.3" + "@docusaurus/utils-validation" "3.6.3" boxen "^6.2.1" chalk "^4.1.2" chokidar "^3.5.3" @@ -1628,68 +1659,69 @@ combine-promises "^1.1.0" commander "^5.1.0" core-js "^3.31.1" + del "^6.1.1" detect-port "^1.5.1" escape-html "^1.0.3" eta "^2.2.0" eval "^0.1.8" - execa "5.1.1" fs-extra "^11.1.1" html-tags "^3.3.1" html-webpack-plugin "^5.6.0" leven "^3.1.0" lodash "^4.17.21" - open "^8.4.0" p-map "^4.0.0" prompts "^2.4.2" - react-helmet-async "npm:@slorber/react-helmet-async@1.3.0" + react-dev-utils "^12.0.1" + react-helmet-async "^1.3.0" react-loadable "npm:@docusaurus/react-loadable@6.0.0" react-loadable-ssr-addon-v5-slorber "^1.0.1" react-router "^5.3.4" react-router-config "^5.1.1" react-router-dom "^5.3.4" + rtl-detect "^1.0.4" semver "^7.5.4" serve-handler "^6.1.6" - tinypool "^1.0.2" + shelljs "^0.8.5" tslib "^2.6.0" update-notifier "^6.0.2" webpack "^5.95.0" webpack-bundle-analyzer "^4.10.2" - webpack-dev-server "^5.2.2" + webpack-dev-server "^4.15.2" webpack-merge "^6.0.1" -"@docusaurus/cssnano-preset@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-3.9.2.tgz#523aab65349db3c51a77f2489048d28527759428" - integrity sha512-8gBKup94aGttRduABsj7bpPFTX7kbwu+xh3K9NMCF5K4bWBqTFYW+REKHF6iBVDHRJ4grZdIPbvkiHd/XNKRMQ== +"@docusaurus/cssnano-preset@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-3.6.3.tgz#ea19b307183ec20dea4927efc4ddf249150b8c6a" + integrity sha512-qP7SXrwZ+23GFJdPN4aIHQrZW+oH/7tzwEuc/RNL0+BdZdmIjYQqUxdXsjE4lFxLNZjj0eUrSNYIS6xwfij+5Q== dependencies: cssnano-preset-advanced "^6.1.2" - postcss "^8.5.4" + postcss "^8.4.38" postcss-sort-media-queries "^5.2.0" tslib "^2.6.0" -"@docusaurus/logger@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-3.9.2.tgz#6ec6364b90f5a618a438cc9fd01ac7376869f92a" - integrity sha512-/SVCc57ByARzGSU60c50rMyQlBuMIJCjcsJlkphxY6B0GV4UH3tcA1994N8fFfbJ9kX3jIBe/xg3XP5qBtGDbA== +"@docusaurus/logger@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-3.6.3.tgz#c6e514c9429487ef38be2f2129b2b842740d92fd" + integrity sha512-xSubJixcNyMV9wMV4q0s47CBz3Rlc5jbcCCuij8pfQP8qn/DIpt0ks8W6hQWzHAedg/J/EwxxUOUrnEoKzJo8g== dependencies: chalk "^4.1.2" tslib "^2.6.0" -"@docusaurus/mdx-loader@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-3.9.2.tgz#78d238de6c6203fa811cc2a7e90b9b79e111408c" - integrity sha512-wiYoGwF9gdd6rev62xDU8AAM8JuLI/hlwOtCzMmYcspEkzecKrP8J8X+KpYnTlACBUUtXNJpSoCwFWJhLRevzQ== +"@docusaurus/mdx-loader@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-3.6.3.tgz#127babc7cdb26d37c723bc3ae518bda17ce40160" + integrity sha512-3iJdiDz9540ppBseeI93tWTDtUGVkxzh59nMq4ignylxMuXBLK8dFqVeaEor23v1vx6TrGKZ2FuLaTB+U7C0QQ== dependencies: - "@docusaurus/logger" "3.9.2" - "@docusaurus/utils" "3.9.2" - "@docusaurus/utils-validation" "3.9.2" + "@docusaurus/logger" "3.6.3" + "@docusaurus/utils" "3.6.3" + "@docusaurus/utils-validation" "3.6.3" "@mdx-js/mdx" "^3.0.0" "@slorber/remark-comment" "^1.0.0" escape-html "^1.0.3" estree-util-value-to-estree "^3.0.1" file-loader "^6.2.0" fs-extra "^11.1.1" - image-size "^2.0.2" + image-size "^1.0.2" mdast-util-mdx "^3.0.0" mdast-util-to-string "^4.0.0" rehype-raw "^7.0.0" @@ -1705,209 +1737,182 @@ vfile "^6.0.1" webpack "^5.88.1" -"@docusaurus/module-type-aliases@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-3.9.2.tgz#993c7cb0114363dea5ef6855e989b3ad4b843a34" - integrity sha512-8qVe2QA9hVLzvnxP46ysuofJUIc/yYQ82tvA/rBTrnpXtCjNSFLxEZfd5U8cYZuJIVlkPxamsIgwd5tGZXfvew== +"@docusaurus/module-type-aliases@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-3.6.3.tgz#1f7030b1cf1f658cf664d41b6eadba93bbe51d87" + integrity sha512-MjaXX9PN/k5ugNvfRZdWyKWq4FsrhN4LEXaj0pEmMebJuBNlFeGyKQUa9DRhJHpadNaiMLrbo9m3U7Ig5YlsZg== dependencies: - "@docusaurus/types" "3.9.2" + "@docusaurus/types" "3.6.3" "@types/history" "^4.7.11" "@types/react" "*" "@types/react-router-config" "*" "@types/react-router-dom" "*" - react-helmet-async "npm:@slorber/react-helmet-async@1.3.0" + react-helmet-async "*" react-loadable "npm:@docusaurus/react-loadable@6.0.0" -"@docusaurus/plugin-content-blog@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.9.2.tgz#d5ce51eb7757bdab0515e2dd26a793ed4e119df9" - integrity sha512-3I2HXy3L1QcjLJLGAoTvoBnpOwa6DPUa3Q0dMK19UTY9mhPkKQg/DYhAGTiBUKcTR0f08iw7kLPqOhIgdV3eVQ== +"@docusaurus/plugin-content-blog@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.6.3.tgz#d6a597e4bfdeb3f1f6ce06d2ac86207296988cc9" + integrity sha512-k0ogWwwJU3pFRFfvW1kRVHxzf2DutLGaaLjAnHVEU6ju+aRP0Z5ap/13DHyPOfHeE4WKpn/M0TqjdwZAcY3kAw== dependencies: - "@docusaurus/core" "3.9.2" - "@docusaurus/logger" "3.9.2" - "@docusaurus/mdx-loader" "3.9.2" - "@docusaurus/theme-common" "3.9.2" - "@docusaurus/types" "3.9.2" - "@docusaurus/utils" "3.9.2" - "@docusaurus/utils-common" "3.9.2" - "@docusaurus/utils-validation" "3.9.2" + "@docusaurus/core" "3.6.3" + "@docusaurus/logger" "3.6.3" + "@docusaurus/mdx-loader" "3.6.3" + "@docusaurus/theme-common" "3.6.3" + "@docusaurus/types" "3.6.3" + "@docusaurus/utils" "3.6.3" + "@docusaurus/utils-common" "3.6.3" + "@docusaurus/utils-validation" "3.6.3" cheerio "1.0.0-rc.12" feed "^4.2.2" fs-extra "^11.1.1" lodash "^4.17.21" - schema-dts "^1.1.2" + reading-time "^1.5.0" srcset "^4.0.0" tslib "^2.6.0" unist-util-visit "^5.0.0" utility-types "^3.10.0" webpack "^5.88.1" -"@docusaurus/plugin-content-docs@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.9.2.tgz#cd8f2d1c06e53c3fa3d24bdfcb48d237bf2d6b2e" - integrity sha512-C5wZsGuKTY8jEYsqdxhhFOe1ZDjH0uIYJ9T/jebHwkyxqnr4wW0jTkB72OMqNjsoQRcb0JN3PcSeTwFlVgzCZg== +"@docusaurus/plugin-content-docs@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.6.3.tgz#aae044d2af6996d1a6de8d815aca8a83b485e0a5" + integrity sha512-r2wS8y/fsaDcxkm20W5bbYJFPzdWdEaTWVYjNxlHlcmX086eqQR1Fomlg9BHTJ0dLXPzAlbC8EN4XqMr3QzNCQ== dependencies: - "@docusaurus/core" "3.9.2" - "@docusaurus/logger" "3.9.2" - "@docusaurus/mdx-loader" "3.9.2" - "@docusaurus/module-type-aliases" "3.9.2" - "@docusaurus/theme-common" "3.9.2" - "@docusaurus/types" "3.9.2" - "@docusaurus/utils" "3.9.2" - "@docusaurus/utils-common" "3.9.2" - "@docusaurus/utils-validation" "3.9.2" + "@docusaurus/core" "3.6.3" + "@docusaurus/logger" "3.6.3" + "@docusaurus/mdx-loader" "3.6.3" + "@docusaurus/module-type-aliases" "3.6.3" + "@docusaurus/theme-common" "3.6.3" + "@docusaurus/types" "3.6.3" + "@docusaurus/utils" "3.6.3" + "@docusaurus/utils-common" "3.6.3" + "@docusaurus/utils-validation" "3.6.3" "@types/react-router-config" "^5.0.7" combine-promises "^1.1.0" fs-extra "^11.1.1" js-yaml "^4.1.0" lodash "^4.17.21" - schema-dts "^1.1.2" tslib "^2.6.0" utility-types "^3.10.0" webpack "^5.88.1" -"@docusaurus/plugin-content-pages@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.9.2.tgz#22db6c88ade91cec0a9e87a00b8089898051b08d" - integrity sha512-s4849w/p4noXUrGpPUF0BPqIAfdAe76BLaRGAGKZ1gTDNiGxGcpsLcwJ9OTi1/V8A+AzvsmI9pkjie2zjIQZKA== +"@docusaurus/plugin-content-pages@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.6.3.tgz#0a5a43d1677ee519f63a54634653c54ddf41f475" + integrity sha512-eHrmTgjgLZsuqfsYr5X2xEwyIcck0wseSofWrjTwT9FLOWp+KDmMAuVK+wRo7sFImWXZk3oV/xX/g9aZrhD7OA== dependencies: - "@docusaurus/core" "3.9.2" - "@docusaurus/mdx-loader" "3.9.2" - "@docusaurus/types" "3.9.2" - "@docusaurus/utils" "3.9.2" - "@docusaurus/utils-validation" "3.9.2" + "@docusaurus/core" "3.6.3" + "@docusaurus/mdx-loader" "3.6.3" + "@docusaurus/types" "3.6.3" + "@docusaurus/utils" "3.6.3" + "@docusaurus/utils-validation" "3.6.3" fs-extra "^11.1.1" tslib "^2.6.0" webpack "^5.88.1" -"@docusaurus/plugin-css-cascade-layers@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.9.2.tgz#358c85f63f1c6a11f611f1b8889d9435c11b22f8" - integrity sha512-w1s3+Ss+eOQbscGM4cfIFBlVg/QKxyYgj26k5AnakuHkKxH6004ZtuLe5awMBotIYF2bbGDoDhpgQ4r/kcj4rQ== +"@docusaurus/plugin-debug@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-3.6.3.tgz#4e62ddfbae4d597b073f8e3c632cc12d012339e3" + integrity sha512-zB9GXfIZNPRfzKnNjU6xGVrqn9bPXuGhpjgsuc/YtcTDjnjhasg38NdYd5LEqXex5G/zIorQgWB3n6x/Ut62vQ== dependencies: - "@docusaurus/core" "3.9.2" - "@docusaurus/types" "3.9.2" - "@docusaurus/utils" "3.9.2" - "@docusaurus/utils-validation" "3.9.2" - tslib "^2.6.0" - -"@docusaurus/plugin-debug@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-3.9.2.tgz#b5df4db115583f5404a252dbf66f379ff933e53c" - integrity sha512-j7a5hWuAFxyQAkilZwhsQ/b3T7FfHZ+0dub6j/GxKNFJp2h9qk/P1Bp7vrGASnvA9KNQBBL1ZXTe7jlh4VdPdA== - dependencies: - "@docusaurus/core" "3.9.2" - "@docusaurus/types" "3.9.2" - "@docusaurus/utils" "3.9.2" + "@docusaurus/core" "3.6.3" + "@docusaurus/types" "3.6.3" + "@docusaurus/utils" "3.6.3" fs-extra "^11.1.1" - react-json-view-lite "^2.3.0" + react-json-view-lite "^1.2.0" tslib "^2.6.0" -"@docusaurus/plugin-google-analytics@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.9.2.tgz#857fe075fdeccdf6959e62954d9efe39769fa247" - integrity sha512-mAwwQJ1Us9jL/lVjXtErXto4p4/iaLlweC54yDUK1a97WfkC6Z2k5/769JsFgwOwOP+n5mUQGACXOEQ0XDuVUw== +"@docusaurus/plugin-google-analytics@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.6.3.tgz#63648d469b1e3c50fad8878e7a7db9856e503d5f" + integrity sha512-rCDNy1QW8Dag7nZq67pcum0bpFLrwvxJhYuVprhFh8BMBDxV0bY+bAkGHbSf68P3Bk9C3hNOAXX1srGLIDvcTA== dependencies: - "@docusaurus/core" "3.9.2" - "@docusaurus/types" "3.9.2" - "@docusaurus/utils-validation" "3.9.2" + "@docusaurus/core" "3.6.3" + "@docusaurus/types" "3.6.3" + "@docusaurus/utils-validation" "3.6.3" tslib "^2.6.0" -"@docusaurus/plugin-google-gtag@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.9.2.tgz#df75b1a90ae9266b0471909ba0265f46d5dcae62" - integrity sha512-YJ4lDCphabBtw19ooSlc1MnxtYGpjFV9rEdzjLsUnBCeis2djUyCozZaFhCg6NGEwOn7HDDyMh0yzcdRpnuIvA== +"@docusaurus/plugin-google-gtag@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.6.3.tgz#8a1388b4123904be17e661ea7aa71d798d0c046e" + integrity sha512-+OyDvhM6rqVkQOmLVkQWVJAizEEfkPzVWtIHXlWPOCFGK9X4/AWeBSrU0WG4iMg9Z4zD4YDRrU+lvI4s6DSC+w== dependencies: - "@docusaurus/core" "3.9.2" - "@docusaurus/types" "3.9.2" - "@docusaurus/utils-validation" "3.9.2" + "@docusaurus/core" "3.6.3" + "@docusaurus/types" "3.6.3" + "@docusaurus/utils-validation" "3.6.3" "@types/gtag.js" "^0.0.12" tslib "^2.6.0" -"@docusaurus/plugin-google-tag-manager@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.9.2.tgz#d1a3cf935acb7d31b84685e92d70a1d342946677" - integrity sha512-LJtIrkZN/tuHD8NqDAW1Tnw0ekOwRTfobWPsdO15YxcicBo2ykKF0/D6n0vVBfd3srwr9Z6rzrIWYrMzBGrvNw== +"@docusaurus/plugin-google-tag-manager@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.6.3.tgz#38cbe416803f29782807cebf3ebf240cb47c3c74" + integrity sha512-1M6UPB13gWUtN2UHX083/beTn85PlRI9ABItTl/JL1FJ5dJTWWFXXsHf9WW/6hrVwthwTeV/AGbGKvLKV+IlCA== dependencies: - "@docusaurus/core" "3.9.2" - "@docusaurus/types" "3.9.2" - "@docusaurus/utils-validation" "3.9.2" + "@docusaurus/core" "3.6.3" + "@docusaurus/types" "3.6.3" + "@docusaurus/utils-validation" "3.6.3" tslib "^2.6.0" -"@docusaurus/plugin-sitemap@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.9.2.tgz#e1d9f7012942562cc0c6543d3cb2cdc4ae713dc4" - integrity sha512-WLh7ymgDXjG8oPoM/T4/zUP7KcSuFYRZAUTl8vR6VzYkfc18GBM4xLhcT+AKOwun6kBivYKUJf+vlqYJkm+RHw== +"@docusaurus/plugin-sitemap@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.6.3.tgz#0458e6f7476ab6fd1466e01b153a3211d3223c53" + integrity sha512-94qOO4M9Fwv9KfVQJsgbe91k+fPJ4byf1L3Ez8TUa6TAFPo/BrLwQ80zclHkENlL1824TuxkcMKv33u6eydQCg== dependencies: - "@docusaurus/core" "3.9.2" - "@docusaurus/logger" "3.9.2" - "@docusaurus/types" "3.9.2" - "@docusaurus/utils" "3.9.2" - "@docusaurus/utils-common" "3.9.2" - "@docusaurus/utils-validation" "3.9.2" + "@docusaurus/core" "3.6.3" + "@docusaurus/logger" "3.6.3" + "@docusaurus/types" "3.6.3" + "@docusaurus/utils" "3.6.3" + "@docusaurus/utils-common" "3.6.3" + "@docusaurus/utils-validation" "3.6.3" fs-extra "^11.1.1" sitemap "^7.1.1" tslib "^2.6.0" -"@docusaurus/plugin-svgr@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-svgr/-/plugin-svgr-3.9.2.tgz#62857ed79d97c0150d25f7e7380fdee65671163a" - integrity sha512-n+1DE+5b3Lnf27TgVU5jM1d4x5tUh2oW5LTsBxJX4PsAPV0JGcmI6p3yLYtEY0LRVEIJh+8RsdQmRE66wSV8mw== +"@docusaurus/preset-classic@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-3.6.3.tgz#072298b5b6d0de7d0346b1e9b550a30ef2add56d" + integrity sha512-VHSYWROT3flvNNI1SrnMOtW1EsjeHNK9dhU6s9eY5hryZe79lUqnZJyze/ymDe2LXAqzyj6y5oYvyBoZZk6ErA== dependencies: - "@docusaurus/core" "3.9.2" - "@docusaurus/types" "3.9.2" - "@docusaurus/utils" "3.9.2" - "@docusaurus/utils-validation" "3.9.2" - "@svgr/core" "8.1.0" - "@svgr/webpack" "^8.1.0" - tslib "^2.6.0" - webpack "^5.88.1" + "@docusaurus/core" "3.6.3" + "@docusaurus/plugin-content-blog" "3.6.3" + "@docusaurus/plugin-content-docs" "3.6.3" + "@docusaurus/plugin-content-pages" "3.6.3" + "@docusaurus/plugin-debug" "3.6.3" + "@docusaurus/plugin-google-analytics" "3.6.3" + "@docusaurus/plugin-google-gtag" "3.6.3" + "@docusaurus/plugin-google-tag-manager" "3.6.3" + "@docusaurus/plugin-sitemap" "3.6.3" + "@docusaurus/theme-classic" "3.6.3" + "@docusaurus/theme-common" "3.6.3" + "@docusaurus/theme-search-algolia" "3.6.3" + "@docusaurus/types" "3.6.3" -"@docusaurus/preset-classic@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-3.9.2.tgz#85cc4f91baf177f8146c9ce896dfa1f0fd377050" - integrity sha512-IgyYO2Gvaigi21LuDIe+nvmN/dfGXAiMcV/murFqcpjnZc7jxFAxW+9LEjdPt61uZLxG4ByW/oUmX/DDK9t/8w== +"@docusaurus/theme-classic@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-3.6.3.tgz#00599a9de5fd5c122fd1b8c59d3b755878f2a72c" + integrity sha512-1RRLK1tSArI2c00qugWYO3jRocjOZwGF1mBzPPylDVRwWCS/rnWWR91ChdbbaxIupRJ+hX8ZBYrwr5bbU0oztQ== dependencies: - "@docusaurus/core" "3.9.2" - "@docusaurus/plugin-content-blog" "3.9.2" - "@docusaurus/plugin-content-docs" "3.9.2" - "@docusaurus/plugin-content-pages" "3.9.2" - "@docusaurus/plugin-css-cascade-layers" "3.9.2" - "@docusaurus/plugin-debug" "3.9.2" - "@docusaurus/plugin-google-analytics" "3.9.2" - "@docusaurus/plugin-google-gtag" "3.9.2" - "@docusaurus/plugin-google-tag-manager" "3.9.2" - "@docusaurus/plugin-sitemap" "3.9.2" - "@docusaurus/plugin-svgr" "3.9.2" - "@docusaurus/theme-classic" "3.9.2" - "@docusaurus/theme-common" "3.9.2" - "@docusaurus/theme-search-algolia" "3.9.2" - "@docusaurus/types" "3.9.2" - -"@docusaurus/theme-classic@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-3.9.2.tgz#6e514f99a0ff42b80afcf42d5e5d042618311ce0" - integrity sha512-IGUsArG5hhekXd7RDb11v94ycpJpFdJPkLnt10fFQWOVxAtq5/D7hT6lzc2fhyQKaaCE62qVajOMKL7OiAFAIA== - dependencies: - "@docusaurus/core" "3.9.2" - "@docusaurus/logger" "3.9.2" - "@docusaurus/mdx-loader" "3.9.2" - "@docusaurus/module-type-aliases" "3.9.2" - "@docusaurus/plugin-content-blog" "3.9.2" - "@docusaurus/plugin-content-docs" "3.9.2" - "@docusaurus/plugin-content-pages" "3.9.2" - "@docusaurus/theme-common" "3.9.2" - "@docusaurus/theme-translations" "3.9.2" - "@docusaurus/types" "3.9.2" - "@docusaurus/utils" "3.9.2" - "@docusaurus/utils-common" "3.9.2" - "@docusaurus/utils-validation" "3.9.2" + "@docusaurus/core" "3.6.3" + "@docusaurus/logger" "3.6.3" + "@docusaurus/mdx-loader" "3.6.3" + "@docusaurus/module-type-aliases" "3.6.3" + "@docusaurus/plugin-content-blog" "3.6.3" + "@docusaurus/plugin-content-docs" "3.6.3" + "@docusaurus/plugin-content-pages" "3.6.3" + "@docusaurus/theme-common" "3.6.3" + "@docusaurus/theme-translations" "3.6.3" + "@docusaurus/types" "3.6.3" + "@docusaurus/utils" "3.6.3" + "@docusaurus/utils-common" "3.6.3" + "@docusaurus/utils-validation" "3.6.3" "@mdx-js/react" "^3.0.0" clsx "^2.0.0" + copy-text-to-clipboard "^3.2.0" infima "0.2.0-alpha.45" lodash "^4.17.21" nprogress "^0.2.0" - postcss "^8.5.4" + postcss "^8.4.26" prism-react-renderer "^2.3.0" prismjs "^1.29.0" react-router-dom "^5.3.4" @@ -1915,15 +1920,15 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@docusaurus/theme-common@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-3.9.2.tgz#487172c6fef9815c2746ef62a71e4f5b326f9ba5" - integrity sha512-6c4DAbR6n6nPbnZhY2V3tzpnKnGL+6aOsLvFL26VRqhlczli9eWG0VDUNoCQEPnGwDMhPS42UhSAnz5pThm5Ag== +"@docusaurus/theme-common@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-3.6.3.tgz#a8a6ebd2b0fd7a5cca4d0c6a2f9ccff905fa7438" + integrity sha512-b8ZkhczXHDxWWyvz+YJy4t/PlPbEogTTbgnHoflYnH7rmRtyoodTsu8WVM12la5LmlMJBclBXFl29OH8kPE7gg== dependencies: - "@docusaurus/mdx-loader" "3.9.2" - "@docusaurus/module-type-aliases" "3.9.2" - "@docusaurus/utils" "3.9.2" - "@docusaurus/utils-common" "3.9.2" + "@docusaurus/mdx-loader" "3.6.3" + "@docusaurus/module-type-aliases" "3.6.3" + "@docusaurus/utils" "3.6.3" + "@docusaurus/utils-common" "3.6.3" "@types/history" "^4.7.11" "@types/react" "*" "@types/react-router-config" "*" @@ -1933,21 +1938,21 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@docusaurus/theme-search-algolia@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.9.2.tgz#420fd5b27fc1673b48151fdc9fe7167ba135ed50" - integrity sha512-GBDSFNwjnh5/LdkxCKQHkgO2pIMX1447BxYUBG2wBiajS21uj64a+gH/qlbQjDLxmGrbrllBrtJkUHxIsiwRnw== +"@docusaurus/theme-search-algolia@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.6.3.tgz#1a3331a489f392f5b032c4efc5f431e57eddf7ce" + integrity sha512-rt+MGCCpYgPyWCGXtbxlwFbTSobu15jWBTPI2LHsHNa5B0zSmOISX6FWYAPt5X1rNDOqMGM0FATnh7TBHRohVA== dependencies: - "@docsearch/react" "^3.9.0 || ^4.1.0" - "@docusaurus/core" "3.9.2" - "@docusaurus/logger" "3.9.2" - "@docusaurus/plugin-content-docs" "3.9.2" - "@docusaurus/theme-common" "3.9.2" - "@docusaurus/theme-translations" "3.9.2" - "@docusaurus/utils" "3.9.2" - "@docusaurus/utils-validation" "3.9.2" - algoliasearch "^5.37.0" - algoliasearch-helper "^3.26.0" + "@docsearch/react" "^3.5.2" + "@docusaurus/core" "3.6.3" + "@docusaurus/logger" "3.6.3" + "@docusaurus/plugin-content-docs" "3.6.3" + "@docusaurus/theme-common" "3.6.3" + "@docusaurus/theme-translations" "3.6.3" + "@docusaurus/utils" "3.6.3" + "@docusaurus/utils-validation" "3.6.3" + algoliasearch "^4.18.0" + algoliasearch-helper "^3.13.3" clsx "^2.0.0" eta "^2.2.0" fs-extra "^11.1.1" @@ -1955,62 +1960,61 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@docusaurus/theme-translations@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-3.9.2.tgz#238cd69c2da92d612be3d3b4f95944c1d0f1e041" - integrity sha512-vIryvpP18ON9T9rjgMRFLr2xJVDpw1rtagEGf8Ccce4CkTrvM/fRB8N2nyWYOW5u3DdjkwKw5fBa+3tbn9P4PA== +"@docusaurus/theme-translations@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-3.6.3.tgz#6e473835ea016ce4acd7d2997f411811db8c4f6b" + integrity sha512-Gb0regclToVlngSIIwUCtBMQBq48qVUaN1XQNKW4XwlsgUyk0vP01LULdqbem7czSwIeBAFXFoORJ0RPX7ht/w== dependencies: fs-extra "^11.1.1" tslib "^2.6.0" -"@docusaurus/types@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-3.9.2.tgz#e482cf18faea0d1fa5ce0e3f1e28e0f32d2593eb" - integrity sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q== +"@docusaurus/types@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-3.6.3.tgz#e87592e31616da1b8dc473e4c8205c61885a1518" + integrity sha512-xD9oTGDrouWzefkhe9ogB2fDV96/82cRpNGx2HIvI5L87JHNhQVIWimQ/3JIiiX/TEd5S9s+VO6FFguwKNRVow== dependencies: "@mdx-js/mdx" "^3.0.0" "@types/history" "^4.7.11" - "@types/mdast" "^4.0.2" "@types/react" "*" commander "^5.1.0" joi "^17.9.2" - react-helmet-async "npm:@slorber/react-helmet-async@1.3.0" + react-helmet-async "^1.3.0" utility-types "^3.10.0" webpack "^5.95.0" webpack-merge "^5.9.0" -"@docusaurus/utils-common@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-3.9.2.tgz#e89bfcf43d66359f43df45293fcdf22814847460" - integrity sha512-I53UC1QctruA6SWLvbjbhCpAw7+X7PePoe5pYcwTOEXD/PxeP8LnECAhTHHwWCblyUX5bMi4QLRkxvyZ+IT8Aw== +"@docusaurus/utils-common@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-3.6.3.tgz#57f840bd6f0928cf10060198cb421f1b9212c8f5" + integrity sha512-v4nKDaANLgT3pMBewHYEMAl/ufY0LkXao1QkFWzI5huWFOmNQ2UFzv2BiKeHX5Ownis0/w6cAyoxPhVdDonlSQ== dependencies: - "@docusaurus/types" "3.9.2" + "@docusaurus/types" "3.6.3" tslib "^2.6.0" -"@docusaurus/utils-validation@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-3.9.2.tgz#04aec285604790806e2fc5aa90aa950dc7ba75ae" - integrity sha512-l7yk3X5VnNmATbwijJkexdhulNsQaNDwoagiwujXoxFbWLcxHQqNQ+c/IAlzrfMMOfa/8xSBZ7KEKDesE/2J7A== +"@docusaurus/utils-validation@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-3.6.3.tgz#3eca7125235eb90983ff660b97a71f331e331f57" + integrity sha512-bhEGGiN5BE38h21vjqD70Gxg++j+PfYVddDUE5UFvLDup68QOcpD33CLr+2knPorlxRbEaNfz6HQDUMQ3HuqKw== dependencies: - "@docusaurus/logger" "3.9.2" - "@docusaurus/utils" "3.9.2" - "@docusaurus/utils-common" "3.9.2" + "@docusaurus/logger" "3.6.3" + "@docusaurus/utils" "3.6.3" + "@docusaurus/utils-common" "3.6.3" fs-extra "^11.2.0" joi "^17.9.2" js-yaml "^4.1.0" lodash "^4.17.21" tslib "^2.6.0" -"@docusaurus/utils@3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-3.9.2.tgz#ffab7922631c7e0febcb54e6d499f648bf8a89eb" - integrity sha512-lBSBiRruFurFKXr5Hbsl2thmGweAPmddhF3jb99U4EMDA5L+e5Y1rAkOS07Nvrup7HUMBDrCV45meaxZnt28nQ== +"@docusaurus/utils@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-3.6.3.tgz#8dcb1969e4011a84dfb0a031da806dadddebf0ea" + integrity sha512-0R/FR3bKVl4yl8QwbL4TYFfR+OXBRpVUaTJdENapBGR3YMwfM6/JnhGilWQO8AOwPJGtGoDK7ib8+8UF9f3OZQ== dependencies: - "@docusaurus/logger" "3.9.2" - "@docusaurus/types" "3.9.2" - "@docusaurus/utils-common" "3.9.2" + "@docusaurus/logger" "3.6.3" + "@docusaurus/types" "3.6.3" + "@docusaurus/utils-common" "3.6.3" + "@svgr/webpack" "^8.1.0" escape-string-regexp "^4.0.0" - execa "5.1.1" file-loader "^6.2.0" fs-extra "^11.1.1" github-slugger "^1.5.0" @@ -2020,9 +2024,9 @@ js-yaml "^4.1.0" lodash "^4.17.21" micromatch "^4.0.5" - p-queue "^6.6.2" prompts "^2.4.2" resolve-pathname "^3.0.0" + shelljs "^0.8.5" tslib "^2.6.0" url-loader "^4.1.1" utility-types "^3.10.0" @@ -2059,18 +2063,6 @@ local-pkg "^1.0.0" mlly "^1.7.4" -"@isaacs/balanced-match@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz#3081dadbc3460661b751e7591d7faea5df39dd29" - integrity sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ== - -"@isaacs/brace-expansion@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz#4b3dabab7d8e75a429414a96bd67bf4c1d13e0f3" - integrity sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA== - dependencies: - "@isaacs/balanced-match" "^4.0.1" - "@jest/schemas@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" @@ -2248,11 +2240,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@opentelemetry/api@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" - integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== - "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -2325,11 +2312,6 @@ micromark-util-character "^1.1.0" micromark-util-symbol "^1.0.1" -"@standard-schema/spec@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.0.0.tgz#f193b73dc316c4170f2e82a881da0f550d551b9c" - integrity sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA== - "@svgr/babel-plugin-add-jsx-attribute@8.0.0": version "8.0.0" resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz#4001f5d5dd87fa13303e36ee106e3ff3a7eb8b22" @@ -2853,7 +2835,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -2939,6 +2921,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.45.tgz#2c0fafd78705e7a18b7906b5201a522719dc5190" integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw== +"@types/parse-json@^4.0.0": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" + integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== + "@types/parse5@^5.0.0": version "5.0.3" resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109" @@ -3105,11 +3092,6 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== -"@vercel/oidc@3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@vercel/oidc/-/oidc-3.0.3.tgz#82c2b6dd4d5c3b37dcb1189718cdeb9db402d052" - integrity sha512-yNEQvPcVrK9sIe637+I0jD6leluPxzwJKx/Haw6F4H77CdDsszUn5V3o96LPziXkSNE2B83+Z3mjqGKBK/R6Gg== - "@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1": version "1.14.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6" @@ -3251,15 +3233,7 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -accepts@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-2.0.0.tgz#bbcf4ba5075467f3f2131eab3cffc73c2f5d7895" - integrity sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng== - dependencies: - mime-types "^3.0.0" - negotiator "^1.0.0" - -accepts@~1.3.4: +accepts@~1.3.4, accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== @@ -3284,7 +3258,7 @@ acorn@^8.0.0, acorn@^8.0.4, acorn@^8.11.0, acorn@^8.14.0, acorn@^8.8.2: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== -address@^1.0.1: +address@^1.0.1, address@^1.1.2: version "1.2.2" resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e" integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== @@ -3297,16 +3271,6 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ai@5.0.93, ai@^5.0.30: - version "5.0.93" - resolved "https://registry.yarnpkg.com/ai/-/ai-5.0.93.tgz#040fff47ce6603b36ed9b8b7ca228c2400d94be3" - integrity sha512-9eGcu+1PJgPg4pRNV4L7tLjRR3wdJC9CXQoNMvtqvYNOLZHFCzjHtVIOr2SIkoJJeu2+sOy3hyiSuTmy2MA40g== - dependencies: - "@ai-sdk/gateway" "2.0.9" - "@ai-sdk/provider" "2.0.0" - "@ai-sdk/provider-utils" "3.0.17" - "@opentelemetry/api" "1.9.0" - ajv-formats@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" @@ -3314,7 +3278,7 @@ ajv-formats@^2.1.1: dependencies: ajv "^8.0.0" -ajv-keywords@^3.5.2: +ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== @@ -3326,7 +3290,7 @@ ajv-keywords@^5.1.0: dependencies: fast-deep-equal "^3.1.3" -ajv@^6.12.5: +ajv@^6.12.2, ajv@^6.12.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -3346,32 +3310,52 @@ ajv@^8.0.0, ajv@^8.9.0: json-schema-traverse "^1.0.0" require-from-string "^2.0.2" -algoliasearch-helper@^3.26.0: - version "3.26.1" - resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.26.1.tgz#5b7f0874a2751c3d6de675d5403d8fa2f015023f" - integrity sha512-CAlCxm4fYBXtvc5MamDzP6Svu8rW4z9me4DCBY1rQ2UDJ0u0flWmusQ8M3nOExZsLLRcUwUPoRAPMrhzOG3erw== +algoliasearch-helper@^3.13.3: + version "3.22.5" + resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.22.5.tgz#2fcc26814e10a121a2c2526a1b05c754061c56c0" + integrity sha512-lWvhdnc+aKOKx8jyA3bsdEgHzm/sglC4cYdMG4xSQyRiPLJVJtH/IVYZG3Hp6PkTEhQqhyVYkeP9z2IlcHJsWw== dependencies: "@algolia/events" "^4.0.1" -algoliasearch@^5.28.0, algoliasearch@^5.37.0: - version "5.44.0" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-5.44.0.tgz#25017f7ea7afcd35b35fb5a790a78694e5dddf4b" - integrity sha512-f8IpsbdQjzTjr/4mJ/jv5UplrtyMnnciGax6/B0OnLCs2/GJTK13O4Y7Ff1AvJVAaztanH+m5nzPoUq6EAy+aA== +algoliasearch@^4.18.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.24.0.tgz#b953b3e2309ef8f25da9de311b95b994ac918275" + integrity sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g== dependencies: - "@algolia/abtesting" "1.10.0" - "@algolia/client-abtesting" "5.44.0" - "@algolia/client-analytics" "5.44.0" - "@algolia/client-common" "5.44.0" - "@algolia/client-insights" "5.44.0" - "@algolia/client-personalization" "5.44.0" - "@algolia/client-query-suggestions" "5.44.0" - "@algolia/client-search" "5.44.0" - "@algolia/ingestion" "1.44.0" - "@algolia/monitoring" "1.44.0" - "@algolia/recommend" "5.44.0" - "@algolia/requester-browser-xhr" "5.44.0" - "@algolia/requester-fetch" "5.44.0" - "@algolia/requester-node-http" "5.44.0" + "@algolia/cache-browser-local-storage" "4.24.0" + "@algolia/cache-common" "4.24.0" + "@algolia/cache-in-memory" "4.24.0" + "@algolia/client-account" "4.24.0" + "@algolia/client-analytics" "4.24.0" + "@algolia/client-common" "4.24.0" + "@algolia/client-personalization" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/logger-common" "4.24.0" + "@algolia/logger-console" "4.24.0" + "@algolia/recommend" "4.24.0" + "@algolia/requester-browser-xhr" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/requester-node-http" "4.24.0" + "@algolia/transporter" "4.24.0" + +algoliasearch@^5.12.0: + version "5.15.0" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-5.15.0.tgz#09cef5a2555c4554b37a99f0488ea6ab2347e625" + integrity sha512-Yf3Swz1s63hjvBVZ/9f2P1Uu48GjmjCN+Esxb6MAONMGtZB1fRX8/S1AhUTtsuTlcGovbYLxpHgc7wEzstDZBw== + dependencies: + "@algolia/client-abtesting" "5.15.0" + "@algolia/client-analytics" "5.15.0" + "@algolia/client-common" "5.15.0" + "@algolia/client-insights" "5.15.0" + "@algolia/client-personalization" "5.15.0" + "@algolia/client-query-suggestions" "5.15.0" + "@algolia/client-search" "5.15.0" + "@algolia/ingestion" "1.15.0" + "@algolia/monitoring" "1.15.0" + "@algolia/recommend" "5.15.0" + "@algolia/requester-browser-xhr" "5.15.0" + "@algolia/requester-fetch" "5.15.0" + "@algolia/requester-node-http" "5.15.0" ansi-align@^3.0.1: version "3.0.1" @@ -3449,6 +3433,11 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" @@ -3470,6 +3459,11 @@ astring@^1.8.0: resolved "https://registry.yarnpkg.com/astring/-/astring-1.9.0.tgz#cc73e6062a7eb03e7d19c22d8b0b3451fd9bfeef" integrity sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg== +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + autocomplete.js@^0.37.0: version "0.37.1" resolved "https://registry.yarnpkg.com/autocomplete.js/-/autocomplete.js-0.37.1.tgz#a29a048d827e7d2bf8f7df8b831766e5cc97df01" @@ -3489,18 +3483,6 @@ autoprefixer@^10.4.19: picocolors "^1.0.1" postcss-value-parser "^4.2.0" -autoprefixer@^10.4.21: - version "10.4.22" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.22.tgz#90b27ab55ec0cf0684210d1f056f7d65dac55f16" - integrity sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg== - dependencies: - browserslist "^4.27.0" - caniuse-lite "^1.0.30001754" - fraction.js "^5.3.4" - normalize-range "^0.1.2" - picocolors "^1.1.1" - postcss-value-parser "^4.2.0" - available-typed-arrays@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" @@ -3567,11 +3549,6 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -baseline-browser-mapping@^2.8.25: - version "2.8.28" - resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.8.28.tgz#9ef511f5a7c19d74a94cafcbf951608398e9bdb3" - integrity sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ== - batch@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" @@ -3592,20 +3569,23 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== -body-parser@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.1.tgz#6df606b0eb0a6e3f783dde91dde182c24c82438c" - integrity sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw== +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: - bytes "^3.1.2" - content-type "^1.0.5" - debug "^4.4.3" - http-errors "^2.0.0" - iconv-lite "^0.7.0" - on-finished "^2.4.1" - qs "^6.14.0" - raw-body "^3.0.1" - type-is "^2.0.1" + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.13.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" bonjour-service@^1.2.1: version "1.3.0" @@ -3648,7 +3628,7 @@ boxen@^7.0.0: widest-line "^4.0.1" wrap-ansi "^8.1.0" -brace-expansion@>=1.1.12, brace-expansion@^1.1.7: +brace-expansion@>=1.1.12, brace-expansion@^1.1.7, brace-expansion@^2.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-4.0.1.tgz#3387e13eaa2992025d05ea47308f77e4a8dedd1e" integrity sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA== @@ -3662,7 +3642,7 @@ braces@^3.0.3, braces@~3.0.2: dependencies: fill-range "^7.1.1" -browserslist@^4.0.0, browserslist@^4.23.0, browserslist@^4.23.3, browserslist@^4.24.0, browserslist@^4.24.2: +browserslist@^4.0.0, browserslist@^4.18.1, browserslist@^4.23.0, browserslist@^4.23.1, browserslist@^4.23.3, browserslist@^4.24.0, browserslist@^4.24.2: version "4.24.2" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.2.tgz#f5845bc91069dbd55ee89faf9822e1d885d16580" integrity sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg== @@ -3672,17 +3652,6 @@ browserslist@^4.0.0, browserslist@^4.23.0, browserslist@^4.23.3, browserslist@^4 node-releases "^2.0.18" update-browserslist-db "^1.1.1" -browserslist@^4.26.0, browserslist@^4.27.0: - version "4.28.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.0.tgz#9cefece0a386a17a3cd3d22ebf67b9deca1b5929" - integrity sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ== - dependencies: - baseline-browser-mapping "^2.8.25" - caniuse-lite "^1.0.30001754" - electron-to-chromium "^1.5.249" - node-releases "^2.0.27" - update-browserslist-db "^1.1.4" - buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -3708,7 +3677,7 @@ bytes@3.0.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== -bytes@3.1.2, bytes@^3.1.2, bytes@~3.1.2: +bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== @@ -3739,14 +3708,6 @@ call-bind-apply-helpers@^1.0.0: es-errors "^1.3.0" function-bind "^1.1.2" -call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" - integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.7: version "1.0.8" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" @@ -3757,14 +3718,6 @@ call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.7: get-intrinsic "^1.2.4" set-function-length "^1.2.2" -call-bound@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" - integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== - dependencies: - call-bind-apply-helpers "^1.0.2" - get-intrinsic "^1.3.0" - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -3798,17 +3751,17 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001669, caniuse-lite@^1.0.30001754: - version "1.0.30001757" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz" - integrity sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001669: + version "1.0.30001687" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001687.tgz#d0ac634d043648498eedf7a3932836beba90ebae" + integrity sha512-0S/FDhf4ZiqrTUiQ39dKeUjYRjkv7lOZU1Dgif2rIqrTzX/1wV2hfKu9TOm1IHkdSijfLswxTFzl/cvir+SLSQ== ccount@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== -chalk@^4.0.0, chalk@^4.1.2: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -3890,7 +3843,7 @@ chevrotain@~11.0.3: "@chevrotain/utils" "11.0.3" lodash-es "4.17.21" -chokidar@^3.5.3, chokidar@^3.6.0: +chokidar@^3.4.2, chokidar@^3.5.3, chokidar@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== @@ -3915,7 +3868,7 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== -clean-css@^5.2.2, clean-css@^5.3.3, clean-css@~5.3.2: +clean-css@^5.2.2, clean-css@^5.3.2, clean-css@~5.3.2: version "5.3.3" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.3.tgz#b330653cd3bd6b75009cc25c714cae7b93351ccd" integrity sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg== @@ -4125,12 +4078,14 @@ content-disposition@0.5.2: resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" integrity sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA== -content-disposition@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.1.tgz#a8b7bbeb2904befdfb6787e5c0c086959f605f9b" - integrity sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q== +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" -content-type@^1.0.5: +content-type@~1.0.4, content-type@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== @@ -4140,16 +4095,21 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -cookie-signature@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793" - integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg== +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== -cookie@>=0.7.0, cookie@^0.7.1: +cookie@0.7.1, cookie@>=0.7.0: version "1.0.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-1.0.2.tgz#27360701532116bd3f1f9416929d176afe1e4610" integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA== +copy-text-to-clipboard@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz#0202b2d9bdae30a49a53f898626dcc3b49ad960b" + integrity sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q== + copy-webpack-plugin@^11.0.0: version "11.0.0" resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz#96d4dbdb5f73d02dd72d0528d1958721ab72e04a" @@ -4198,6 +4158,17 @@ cose-base@^2.2.0: dependencies: layout-base "^2.0.0" +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + cosmiconfig@^8.1.3, cosmiconfig@^8.3.5: version "8.3.6" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" @@ -4208,7 +4179,7 @@ cosmiconfig@^8.1.3, cosmiconfig@^8.3.5: parse-json "^5.2.0" path-type "^4.0.0" -cross-spawn@>=6.0.6, cross-spawn@^7.0.3: +cross-spawn@>=6.0.6, cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -4236,16 +4207,16 @@ css-declaration-sorter@^7.2.0: resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz#6dec1c9523bc4a643e088aab8f09e67a54961024" integrity sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow== -css-has-pseudo@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-7.0.3.tgz#a5ee2daf5f70a2032f3cefdf1e36e7f52a243873" - integrity sha512-oG+vKuGyqe/xvEMoxAQrhi7uY16deJR3i7wwhBerVrGQKSqUC5GiOVxTpM9F9B9hw0J+eKeOWLH7E9gZ1Dr5rA== +css-has-pseudo@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-7.0.1.tgz#adbb51821e51f7a7c1d2df4d12827870cc311137" + integrity sha512-EOcoyJt+OsuKfCADgLT7gADZI5jMzIe/AeI6MeAYKiFBDmNmM7kk46DtSfMj5AohUJisqVzopBpnQTlvbyaBWg== dependencies: "@csstools/selector-specificity" "^5.0.0" postcss-selector-parser "^7.0.0" postcss-value-parser "^4.2.0" -css-loader@^6.11.0: +css-loader@^6.8.1: version "6.11.0" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.11.0.tgz#33bae3bf6363d0a7c2cf9031c96c744ff54d85ba" integrity sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g== @@ -4324,10 +4295,10 @@ css-what@^6.0.1, css-what@^6.1.0: resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== -cssdb@^8.4.2: - version "8.4.2" - resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-8.4.2.tgz#1a367ab1904c97af0bb2c7ae179764deae7b078b" - integrity sha512-PzjkRkRUS+IHDJohtxkIczlxPPZqRo0nXplsYXOMBRPjcVRjj1W4DfvRgshUYTVuUigU7ptVYkFJQ7abUB0nyg== +cssdb@^8.2.1: + version "8.2.2" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-8.2.2.tgz#0a5bcbc47a297e6b0296e6082f60363e17b337d4" + integrity sha512-Z3kpWyvN68aKyeMxOUGmffQeHjvrzDxbre2B2ikr/WqQ4ZMkhHu2nOD6uwSeq3TpuOYU7ckvmJRAUIt6orkYUg== cssesc@^3.0.0: version "3.0.0" @@ -4716,7 +4687,7 @@ debounce@^1.2.1: resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== -debug@2.6.9: +debug@2.6.9, debug@^2.6.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -4730,13 +4701,6 @@ debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: dependencies: ms "^2.1.3" -debug@^4.3.5, debug@^4.4.3: - version "4.4.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" - integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== - dependencies: - ms "^2.1.3" - debug@^4.3.6: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" @@ -4770,7 +4734,7 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deepmerge@^4.3.1: +deepmerge@^4.2.2, deepmerge@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== @@ -4821,6 +4785,20 @@ define-properties@^1.1.3, define-properties@^1.2.1: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +del@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a" + integrity sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg== + dependencies: + globby "^11.0.1" + graceful-fs "^4.2.4" + is-glob "^4.0.1" + is-path-cwd "^2.2.0" + is-path-inside "^3.0.2" + p-map "^4.0.0" + rimraf "^3.0.2" + slash "^3.0.0" + delaunator@5: version "5.0.1" resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-5.0.1.tgz#39032b08053923e924d6094fe2cde1a99cc51278" @@ -4828,7 +4806,7 @@ delaunator@5: dependencies: robust-predicates "^3.0.2" -depd@^2.0.0, depd@~2.0.0: +depd@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== @@ -4838,16 +4816,29 @@ depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== -dequal@^2.0.0, dequal@^2.0.3: +dequal@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + detect-node@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== +detect-port-alt@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" + integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q== + dependencies: + address "^1.0.1" + debug "^2.6.0" + detect-port@^1.5.1: version "1.6.1" resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.6.1.tgz#45e4073997c5f292b957cb678fb0bb8ed4250a67" @@ -5022,15 +5013,6 @@ dot-prop@^6.0.1: dependencies: is-obj "^2.0.0" -dunder-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" - integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== - dependencies: - call-bind-apply-helpers "^1.0.1" - es-errors "^1.3.0" - gopd "^1.2.0" - duplexer@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" @@ -5046,11 +5028,6 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.5.249: - version "1.5.254" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.254.tgz#94b84c0a5faff94b334536090a9dec1c74b10130" - integrity sha512-DcUsWpVhv9svsKRxnSCZ86SjD+sp32SGidNB37KpqXJncp1mfUgKbHvBomE89WJDbfVKw1mdv5+ikrvd43r+Bg== - electron-to-chromium@^1.5.41: version "1.5.71" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.71.tgz#d8b5dba1e55b320f2f4e9b1ca80738f53fcfec2b" @@ -5081,7 +5058,12 @@ emoticon@^4.0.1: resolved "https://registry.yarnpkg.com/emoticon/-/emoticon-4.1.0.tgz#d5a156868ee173095627a33de3f1e914c3dde79e" integrity sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ== -encodeurl@^2.0.0: +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +encodeurl@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== @@ -5123,11 +5105,6 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" -es-define-property@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" - integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== - es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" @@ -5138,13 +5115,6 @@ es-module-lexer@^1.2.1: resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== -es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" - integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== - dependencies: - es-errors "^1.3.0" - esast-util-from-estree@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz#8d1cfb51ad534d2f159dc250e604f3478a79f1ad" @@ -5334,7 +5304,7 @@ eta@^2.2.0: resolved "https://registry.yarnpkg.com/eta/-/eta-2.2.0.tgz#eb8b5f8c4e8b6306561a455e62cd7492fe3a9b8a" integrity sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g== -etag@^1.8.1: +etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== @@ -5347,7 +5317,7 @@ eval@^0.1.8: "@types/node" "*" require-like ">= 0.1.1" -eventemitter3@^4.0.0, eventemitter3@^4.0.4: +eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== @@ -5357,64 +5327,47 @@ events@^3.2.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== -eventsource-parser@^3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.6.tgz#292e165e34cacbc936c3c92719ef326d4aeb4e90" - integrity sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg== - -execa@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - exenv@^1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" integrity sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw== -express@>=4.22.0, express@^4.21.2: - version "5.2.1" - resolved "https://registry.yarnpkg.com/express/-/express-5.2.1.tgz#8f21d15b6d327f92b4794ecf8cb08a72f956ac04" - integrity sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw== +express@^4.21.2: + version "4.21.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" + integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== dependencies: - accepts "^2.0.0" - body-parser "^2.2.1" - content-disposition "^1.0.0" - content-type "^1.0.5" - cookie "^0.7.1" - cookie-signature "^1.2.1" - debug "^4.4.0" - depd "^2.0.0" - encodeurl "^2.0.0" - escape-html "^1.0.3" - etag "^1.8.1" - finalhandler "^2.1.0" - fresh "^2.0.0" - http-errors "^2.0.0" - merge-descriptors "^2.0.0" - mime-types "^3.0.0" - on-finished "^2.4.1" - once "^1.4.0" - parseurl "^1.3.3" - proxy-addr "^2.0.7" - qs "^6.14.0" - range-parser "^1.2.1" - router "^2.2.0" - send "^1.1.0" - serve-static "^2.2.0" - statuses "^2.0.1" - type-is "^2.0.1" - vary "^1.1.2" + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.3" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.7.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~2.0.0" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.3.1" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.3" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.12" + proxy-addr "~2.0.7" + qs "6.13.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.19.0" + serve-static "1.16.2" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" exsolve@^1.0.7: version "1.0.7" @@ -5502,6 +5455,11 @@ file-loader@^6.2.0: loader-utils "^2.0.0" schema-utils "^3.0.0" +filesize@^8.0.6: + version "8.0.7" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8" + integrity sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ== + fill-range@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" @@ -5509,17 +5467,18 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" -finalhandler@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-2.1.1.tgz#a2c517a6559852bcdb06d1f8bd7f51b68fad8099" - integrity sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA== +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== dependencies: - debug "^4.4.0" - encodeurl "^2.0.0" - escape-html "^1.0.3" - on-finished "^2.4.1" - parseurl "^1.3.3" - statuses "^2.0.1" + debug "2.6.9" + encodeurl "~2.0.0" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" find-cache-dir@^4.0.0: version "4.0.0" @@ -5529,6 +5488,21 @@ find-cache-dir@^4.0.0: common-path-prefix "^3.0.0" pkg-dir "^7.0.0" +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + find-up@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-6.3.0.tgz#2abab3d3280b2dc7ac10199ef324c4e002c8c790" @@ -5554,6 +5528,33 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" +foreground-child@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + +fork-ts-checker-webpack-plugin@^6.5.0: + version "6.5.3" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz#eda2eff6e22476a2688d10661688c47f611b37f3" + integrity sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ== + dependencies: + "@babel/code-frame" "^7.8.3" + "@types/json-schema" "^7.0.5" + chalk "^4.1.0" + chokidar "^3.4.2" + cosmiconfig "^6.0.0" + deepmerge "^4.2.2" + fs-extra "^9.0.0" + glob "^7.1.6" + memfs "^3.1.2" + minimatch "^3.0.4" + schema-utils "2.7.0" + semver "^7.3.2" + tapable "^1.0.0" + form-data-encoder@^2.1.2: version "2.1.4" resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5" @@ -5574,15 +5575,10 @@ fraction.js@^4.3.7: resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== -fraction.js@^5.3.4: - version "5.3.4" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-5.3.4.tgz#8c0fcc6a9908262df4ed197427bdeef563e0699a" - integrity sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ== - -fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4" - integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A== +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== fs-extra@^10.1.0: version "10.1.0" @@ -5602,6 +5598,26 @@ fs-extra@^11.1.1, fs-extra@^11.2.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-extra@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-monkey@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.6.tgz#8ead082953e88d992cf3ff844faa907b26756da2" + integrity sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + fsevents@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" @@ -5643,36 +5659,12 @@ get-intrinsic@^1.2.4: has-symbols "^1.0.3" hasown "^2.0.0" -get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" - integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== - dependencies: - call-bind-apply-helpers "^1.0.2" - es-define-property "^1.0.1" - es-errors "^1.3.0" - es-object-atoms "^1.1.1" - function-bind "^1.1.2" - get-proto "^1.0.1" - gopd "^1.2.0" - has-symbols "^1.1.0" - hasown "^2.0.2" - math-intrinsics "^1.1.0" - get-own-enumerable-property-symbols@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== -get-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" - integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== - dependencies: - dunder-proto "^1.0.1" - es-object-atoms "^1.0.0" - -get-stream@^6.0.0, get-stream@^6.0.1: +get-stream@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== @@ -5701,14 +5693,29 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@>=10.5.0, glob@^10.3.10: - version "13.0.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-13.0.0.tgz#9d9233a4a274fc28ef7adce5508b7ef6237a1be3" - integrity sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA== +glob@^10.3.10: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== dependencies: - minimatch "^10.1.1" + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" minipass "^7.1.2" - path-scurry "^2.0.0" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + +glob@^7.0.0, glob@^7.1.3, glob@^7.1.6: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" global-dirs@^3.0.0: version "3.0.1" @@ -5717,6 +5724,22 @@ global-dirs@^3.0.0: dependencies: ini "2.0.0" +global-modules@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -5727,7 +5750,7 @@ globals@^15.14.0: resolved "https://registry.yarnpkg.com/globals/-/globals-15.15.0.tgz#7c4761299d41c32b075715a4ce1ede7897ff72a8" integrity sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg== -globby@^11.1.0: +globby@^11.0.1, globby@^11.0.4, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -5750,7 +5773,7 @@ globby@^13.1.1, globby@^13.1.4: merge2 "^1.4.1" slash "^4.0.0" -gopd@^1.0.1, gopd@^1.2.0: +gopd@^1.0.1: version "1.2.0" resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== @@ -5828,7 +5851,7 @@ has-proto@^1.0.1: dependencies: call-bind "^1.0.7" -has-symbols@^1.0.3, has-symbols@^1.1.0: +has-symbols@^1.0.3: version "1.1.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== @@ -6198,16 +6221,16 @@ http-deceiver@^1.2.7: resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== -http-errors@^2.0.0, http-errors@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.1.tgz#36d2f65bc909c8790018dd36fb4d93da6caae06b" - integrity sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ== +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: - depd "~2.0.0" - inherits "~2.0.4" - setprototypeof "~1.2.0" - statuses "~2.0.2" - toidentifier "~1.0.1" + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" http-errors@~1.6.2: version "1.6.3" @@ -6253,16 +6276,18 @@ http2-wrapper@^2.1.10: quick-lru "^5.1.1" resolve-alpn "^1.2.0" -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - hyperdyperid@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/hyperdyperid/-/hyperdyperid-1.2.0.tgz#59668d323ada92228d2a869d3e474d5a33b69e6b" integrity sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A== +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + iconv-lite@0.6: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -6270,13 +6295,6 @@ iconv-lite@0.6: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -iconv-lite@^0.7.0, iconv-lite@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.0.tgz#c50cd80e6746ca8115eb98743afa81aa0e147a3e" - integrity sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" @@ -6292,7 +6310,7 @@ ignore@^5.2.0, ignore@^5.2.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== -image-size@>=1.2.1, image-size@^2.0.2: +image-size@>=1.2.1, image-size@^1.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/image-size/-/image-size-2.0.2.tgz#84a7b43704db5736f364bf0d1b029821299b4bdc" integrity sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w== @@ -6302,7 +6320,12 @@ immediate@^3.2.3: resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== -import-fresh@^3.3.0: +immer@^9.0.7: + version "9.0.21" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176" + integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA== + +import-fresh@^3.1.0, import-fresh@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -6330,22 +6353,30 @@ infima@0.2.0-alpha.45: resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.45.tgz#542aab5a249274d81679631b492973dd2c1e7466" integrity sha512-uyH0zfr1erU1OohLk0fT4Rrb94AOhguWNOcD9uGrSpRvNB+6gZXUoJX5J0NtvzBO10YZ9PgvA4NFgt+fYg8ojw== +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + inherits@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== -inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3, inherits@~2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - ini@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== -ini@^1.3.4, ini@~1.3.0: +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== @@ -6370,6 +6401,11 @@ internmap@^1.0.0: resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" @@ -6541,6 +6577,11 @@ is-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== +is-path-cwd@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + is-path-inside@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -6568,11 +6609,6 @@ is-plain-object@^5.0.0: resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== -is-promise@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3" - integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ== - is-reference@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.3.tgz#9ef7bf9029c70a67b2152da4adf57c23d718910f" @@ -6585,10 +6621,10 @@ is-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" integrity sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA== -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-root@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" + integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== is-typed-array@^1.1.3: version "1.1.13" @@ -6646,7 +6682,7 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== -jackspeak@2.1.1: +jackspeak@2.1.1, jackspeak@^3.1.2: version "2.1.1" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.1.1.tgz#2a42db4cfbb7e55433c28b6f75d8b796af9669cd" integrity sha512-juf9stUEwUaILepraGOWIJTLwg48bUnBmRqd2ln2Os1sW987zeoj/hzhbvRB95oMuS2ZTpjULmdwHNX4rzZIZw== @@ -6708,17 +6744,17 @@ joi@^17.9.2: integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: - version "3.14.2" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.2.tgz#77485ce1dd7f33c061fd1b16ecea23b55fcb04b0" - integrity sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg== + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" esprima "^4.0.0" js-yaml@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" - integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" @@ -6747,11 +6783,6 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" - integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== - json5@^2.1.2, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" @@ -6870,6 +6901,11 @@ loader-utils@^2.0.0: emojis-list "^3.0.0" json5 "^2.1.2" +loader-utils@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.3.1.tgz#735b9a19fd63648ca7adbd31c2327dfe281304e5" + integrity sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg== + local-pkg@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-1.1.2.tgz#c03d208787126445303f8161619dc701afa4abb5" @@ -6879,6 +6915,21 @@ local-pkg@^1.0.0: pkg-types "^2.3.0" quansync "^0.2.11" +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + locate-path@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-7.2.0.tgz#69cb1779bd90b35ab1e771e1f2f89a202c2a8a8a" @@ -6940,10 +6991,10 @@ lowercase-keys@^3.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== -lru-cache@^11.0.0: - version "11.2.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.2.2.tgz#40fd37edffcfae4b2940379c0722dc6eeaa75f24" - integrity sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg== +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== lru-cache@^5.1.1: version "5.1.1" @@ -6989,15 +7040,14 @@ marked@^16.0.0: resolved "https://registry.yarnpkg.com/marked/-/marked-16.2.0.tgz#c407a4f7ed3acc1110812525cfd1b0ed8502792c" integrity sha512-LbbTuye+0dWRz2TS9KJ7wsnD4KAtpj0MVkWc90XvBa6AslXsT0hTBVH5k32pcSyHH1fst9XEFJunXHktVy0zlg== -marked@^16.3.0: - version "16.4.2" - resolved "https://registry.yarnpkg.com/marked/-/marked-16.4.2.tgz#4959a64be6c486f0db7467ead7ce288de54290a3" - integrity sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA== - -math-intrinsics@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" - integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== +mdast-util-definitions@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz#9910abb60ac5d7115d6819b57ae0bcef07a3f7a7" + integrity sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + unist-util-visit "^4.0.0" mdast-util-directive@^3.0.0: version "3.0.0" @@ -7324,10 +7374,24 @@ mdast-util-phrasing@^4.0.0: "@types/mdast" "^4.0.0" unist-util-is "^6.0.0" -mdast-util-to-hast@>=13.2.1, mdast-util-to-hast@^13.0.0: - version "13.2.1" - resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz#d7ff84ca499a57e2c060ae67548ad950e689a053" - integrity sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA== +mdast-util-to-hast@^12.1.0: + version "12.3.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz#045d2825fb04374e59970f5b3f279b5700f6fb49" + integrity sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-definitions "^5.0.0" + micromark-util-sanitize-uri "^1.1.0" + trim-lines "^3.0.0" + unist-util-generated "^2.0.0" + unist-util-position "^4.0.0" + unist-util-visit "^4.0.0" + +mdast-util-to-hast@^13.0.0: + version "13.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz#5ca58e5b921cc0a3ded1bc02eed79a4fe4fe41f4" + integrity sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA== dependencies: "@types/hast" "^3.0.0" "@types/mdast" "^4.0.0" @@ -7392,10 +7456,17 @@ mdn-data@2.0.30: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== -media-typer@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-1.1.0.tgz#6ab74b8f2d3320f2064b2a87a38e7931ff3a5561" - integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw== +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +memfs@^3.1.2: + version "3.6.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6" + integrity sha512-EGowvkkgbMcIChjMTMkESFDbZeSh8xZ7kNSF0hAiAN4Jh6jgHCRS0Ga/+C8y6Au+oqpezRHCfPsmJ2+DwAgiwQ== + dependencies: + fs-monkey "^1.0.4" memfs@^4.6.0: version "4.17.2" @@ -7407,10 +7478,10 @@ memfs@^4.6.0: tree-dump "^1.0.1" tslib "^2.0.0" -merge-descriptors@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz#ea922f660635a2249ee565e0449f951e6b603808" - integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g== +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge-stream@^2.0.0: version "2.0.0" @@ -7448,6 +7519,11 @@ mermaid@>=11.10.0, mermaid@^10.9.0: ts-dedent "^2.2.0" uuid "^11.1.0" +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz#1386628df59946b2d39fb2edfd10f3e8e0a75bb8" @@ -8103,7 +8179,7 @@ micromark-util-resolve-all@^2.0.0: dependencies: micromark-util-types "^2.0.0" -micromark-util-sanitize-uri@^1.0.0: +micromark-util-sanitize-uri@^1.0.0, micromark-util-sanitize-uri@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz#613f738e4400c6eedbc53590c67b197e30d7f90d" integrity sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A== @@ -8225,11 +8301,6 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== -mime-db@^1.54.0: - version "1.54.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" - integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== - mime-db@~1.33.0: version "1.33.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" @@ -8242,24 +8313,17 @@ mime-types@2.1.18: dependencies: mime-db "~1.33.0" -mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.34: +mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" -mime-types@^3.0.0, mime-types@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.2.tgz#39002d4182575d5af036ffa118100f2524b2e2ab" - integrity sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A== - dependencies: - mime-db "^1.54.0" - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== mimic-response@^3.1.0: version "3.1.0" @@ -8271,10 +8335,10 @@ mimic-response@^4.0.0: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== -mini-css-extract-plugin@^2.9.2: - version "2.9.4" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.4.tgz#cafa1a42f8c71357f49cd1566810d74ff1cb0200" - integrity sha512-ZWYT7ln73Hptxqxk2DxPU9MmapXRhxkJD6tkSR04dnQxm8BGu2hzgKLugK5yySD97u/8yy7Ma7E76k9ZdvtjkQ== +mini-css-extract-plugin@^2.9.1: + version "2.9.2" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz#966031b468917a5446f4c24a80854b2947503c5b" + integrity sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w== dependencies: schema-utils "^4.0.0" tapable "^2.2.1" @@ -8284,26 +8348,26 @@ minimalistic-assert@^1.0.0: resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -minimatch@3.1.2, minimatch@^3.0.4: +minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimatch@^10.1.1: - version "10.1.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.1.1.tgz#e6e61b9b0c1dcab116b5a7d1458e8b6ae9e73a55" - integrity sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ== +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: - "@isaacs/brace-expansion" "^5.0.0" + brace-expansion "^2.0.1" minimist@^1.2.0: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -minipass@^7.1.2: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== @@ -8338,7 +8402,7 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@^2.1.3: +ms@2.1.3, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -8360,11 +8424,6 @@ mz@^2.7.0: object-assign "^4.0.1" thenify-all "^1.0.0" -nanoid@^3.3.11: - version "3.3.11" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" - integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== - nanoid@^3.3.7: version "3.3.8" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" @@ -8375,11 +8434,6 @@ negotiator@0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -negotiator@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" - integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== - negotiator@~0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7" @@ -8422,21 +8476,16 @@ node-fetch@2.6.7: dependencies: whatwg-url "^5.0.0" -node-forge@>=1.3.2, node-forge@^1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.2.tgz#d0d2659a26eef778bf84d73e7f55c08144ee7750" - integrity sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw== +node-forge@^1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== node-releases@^2.0.18: version "2.0.18" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== -node-releases@^2.0.27: - version "2.0.27" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e" - integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA== - nopt@1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" @@ -8464,13 +8513,6 @@ not@^0.1.0: resolved "https://registry.yarnpkg.com/not/-/not-0.1.0.tgz#c9691c1746c55dcfbe54cbd8bd4ff041bc2b519d" integrity sha512-5PDmaAsVfnWUgTUbJ3ERwn7u79Z0dYxN9ErxCpVJJqe2RK0PJ3z+iFUxuqjwtlDDegXvtWoxD/3Fzxox7tFGWA== -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - nprogress@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" @@ -8496,10 +8538,10 @@ object-assign@^4.0.1, object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.13.3: - version "1.13.4" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" - integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== +object-inspect@^1.13.1: + version "1.13.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.3.tgz#f14c183de51130243d6d18ae149375ff50ea488a" + integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA== object-is@^1.1.5: version "1.1.6" @@ -8529,7 +8571,7 @@ obuf@^1.0.0, obuf@^1.1.2: resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== -on-finished@^2.4.1: +on-finished@2.4.1, on-finished@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== @@ -8541,20 +8583,13 @@ on-headers@>=1.1.0, on-headers@~1.0.2: resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.1.0.tgz#59da4f91c45f5f989c6e4bcedc5a3b0aed70ff65" integrity sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A== -once@^1.4.0: +once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - open@^10.0.3: version "10.1.2" resolved "https://registry.yarnpkg.com/open/-/open-10.1.2.tgz#d5df40984755c9a9c3c93df8156a12467e882925" @@ -8584,10 +8619,19 @@ p-cancelable@^3.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== +p-limit@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" p-limit@^4.0.0: version "4.0.0" @@ -8596,6 +8640,20 @@ p-limit@^4.0.0: dependencies: yocto-queue "^1.0.0" +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-locate@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-6.0.0.tgz#3da9a49d4934b901089dca3302fa65dc5a05c04f" @@ -8610,14 +8668,6 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-queue@^6.6.2: - version "6.6.2" - resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" - integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== - dependencies: - eventemitter3 "^4.0.4" - p-timeout "^3.2.0" - p-retry@^6.2.0: version "6.2.1" resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-6.2.1.tgz#81828f8dc61c6ef5a800585491572cc9892703af" @@ -8627,12 +8677,15 @@ p-retry@^6.2.0: is-network-error "^1.0.0" retry "^0.13.1" -p-timeout@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" - integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== - dependencies: - p-finally "^1.0.0" +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== package-json@^8.1.0: version "8.1.1" @@ -8678,7 +8731,7 @@ parse-entities@^4.0.0: is-decimal "^2.0.0" is-hexadecimal "^2.0.0" -parse-json@^5.2.0: +parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -8713,7 +8766,7 @@ parse5@^7.0.0: dependencies: entities "^4.5.0" -parseurl@^1.3.3, parseurl@~1.3.2: +parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== @@ -8736,17 +8789,32 @@ path-data-parser@0.1.0, path-data-parser@^0.1.0: resolved "https://registry.yarnpkg.com/path-data-parser/-/path-data-parser-0.1.0.tgz#8f5ba5cc70fc7becb3dcefaea08e2659aba60b8c" integrity sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w== +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + path-exists@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7" integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ== +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + path-is-inside@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== -path-key@^3.0.0, path-key@^3.1.0: +path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -8768,13 +8836,18 @@ path-root@^0.1.1: dependencies: path-root-regex "^0.1.0" -path-scurry@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.1.tgz#4b6572376cfd8b811fca9cd1f5c24b3cbac0fe10" - integrity sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== dependencies: - lru-cache "^11.0.0" - minipass "^7.1.2" + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-to-regexp@0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" + integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== path-to-regexp@3.3.0: version "3.3.0" @@ -8788,11 +8861,6 @@ path-to-regexp@^1.7.0: dependencies: isarray "0.0.1" -path-to-regexp@^8.0.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.3.0.tgz#aa818a6981f99321003a08987d3cec9c3474cd1f" - integrity sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA== - path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -8852,6 +8920,13 @@ pkg-types@^2.3.0: exsolve "^1.0.7" pathe "^2.0.3" +pkg-up@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + points-on-curve@0.2.0, points-on-curve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/points-on-curve/-/points-on-curve-0.2.0.tgz#7dbb98c43791859434284761330fa893cb81b4d1" @@ -8892,15 +8967,15 @@ postcss-clamp@^4.1.0: dependencies: postcss-value-parser "^4.2.0" -postcss-color-functional-notation@^7.0.12: - version "7.0.12" - resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.12.tgz#9a3df2296889e629fde18b873bb1f50a4ecf4b83" - integrity sha512-TLCW9fN5kvO/u38/uesdpbx3e8AkTYhMvDZYa9JpmImWuTE99bDQ7GU7hdOADIZsiI9/zuxfAJxny/khknp1Zw== +postcss-color-functional-notation@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.6.tgz#d74c1e2294b72287eb9af079c04b7ddeff7ec5b3" + integrity sha512-wLXvm8RmLs14Z2nVpB4CWlnvaWPRcOZFltJSlcbYwSJ1EDZKsKDhPKIMecCnuU054KSmlmubkqczmm6qBPCBhA== dependencies: - "@csstools/css-color-parser" "^3.1.0" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" "@csstools/utilities" "^2.0.0" postcss-color-hex-alpha@^10.0.0: @@ -8937,35 +9012,35 @@ postcss-convert-values@^6.1.0: browserslist "^4.23.0" postcss-value-parser "^4.2.0" -postcss-custom-media@^11.0.6: - version "11.0.6" - resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-11.0.6.tgz#6b450e5bfa209efb736830066682e6567bd04967" - integrity sha512-C4lD4b7mUIw+RZhtY7qUbf4eADmb7Ey8BFA2px9jUbwg7pjTZDl4KY4bvlUV+/vXQvzQRfiGEVJyAbtOsCMInw== +postcss-custom-media@^11.0.5: + version "11.0.5" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-11.0.5.tgz#2fcd88a9b1d4da41c67dac6f2def903063a3377d" + integrity sha512-SQHhayVNgDvSAdX9NQ/ygcDQGEY+aSF4b/96z7QUX6mqL5yl/JgG/DywcF6fW9XbnCRE+aVYk+9/nqGuzOPWeQ== dependencies: - "@csstools/cascade-layer-name-parser" "^2.0.5" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/media-query-list-parser" "^4.0.3" + "@csstools/cascade-layer-name-parser" "^2.0.4" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/media-query-list-parser" "^4.0.2" -postcss-custom-properties@^14.0.6: - version "14.0.6" - resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-14.0.6.tgz#1af73a650bf115ba052cf915287c9982825fc90e" - integrity sha512-fTYSp3xuk4BUeVhxCSJdIPhDLpJfNakZKoiTDx7yRGCdlZrSJR7mWKVOBS4sBF+5poPQFMj2YdXx1VHItBGihQ== +postcss-custom-properties@^14.0.4: + version "14.0.4" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-14.0.4.tgz#de9c663285a98833a946d7003a34369d3ce373a9" + integrity sha512-QnW8FCCK6q+4ierwjnmXF9Y9KF8q0JkbgVfvQEMa93x1GT8FvOiUevWCN2YLaOWyByeDX8S6VFbZEeWoAoXs2A== dependencies: - "@csstools/cascade-layer-name-parser" "^2.0.5" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" + "@csstools/cascade-layer-name-parser" "^2.0.4" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" "@csstools/utilities" "^2.0.0" postcss-value-parser "^4.2.0" -postcss-custom-selectors@^8.0.5: - version "8.0.5" - resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-8.0.5.tgz#9448ed37a12271d7ab6cb364b6f76a46a4a323e8" - integrity sha512-9PGmckHQswiB2usSO6XMSswO2yFWVoCAuih1yl9FVcwkscLjRKjwsjM3t+NIWpSU2Jx3eOiK2+t4vVTQaoCHHg== +postcss-custom-selectors@^8.0.4: + version "8.0.4" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-8.0.4.tgz#95ef8268fdbbbd84f34cf84a4517c9d99d419c5a" + integrity sha512-ASOXqNvDCE0dAJ/5qixxPeL1aOVGHGW2JwSy7HyjWNbnWTQCl+fDc968HY1jCmZI0+BaYT5CxsOiUhavpG/7eg== dependencies: - "@csstools/cascade-layer-name-parser" "^2.0.5" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" + "@csstools/cascade-layer-name-parser" "^2.0.4" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" postcss-selector-parser "^7.0.0" postcss-dir-pseudo-class@^9.0.1: @@ -9002,12 +9077,12 @@ postcss-discard-unused@^6.0.5: dependencies: postcss-selector-parser "^6.0.16" -postcss-double-position-gradients@^6.0.4: - version "6.0.4" - resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.4.tgz#b482d08b5ced092b393eb297d07976ab482d4cad" - integrity sha512-m6IKmxo7FxSP5nF2l63QbCC3r+bWpFUWmZXZf096WxG0m7Vl1Q1+ruFOhpdDRmKrRS+S3Jtk+TVk/7z0+BVK6g== +postcss-double-position-gradients@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.0.tgz#eddd424ec754bb543d057d4d2180b1848095d4d2" + integrity sha512-JkIGah3RVbdSEIrcobqj4Gzq0h53GG4uqDPsho88SgY84WnpkTpI0k50MFK/sX7XqVisZ6OqUfFnoUO6m1WWdg== dependencies: - "@csstools/postcss-progressive-custom-properties" "^4.2.1" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" "@csstools/utilities" "^2.0.0" postcss-value-parser "^4.2.0" @@ -9043,18 +9118,18 @@ postcss-image-set-function@^7.0.0: "@csstools/utilities" "^2.0.0" postcss-value-parser "^4.2.0" -postcss-lab-function@^7.0.12: - version "7.0.12" - resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-7.0.12.tgz#eb555ac542607730eb0a87555074e4a5c6eef6e4" - integrity sha512-tUcyRk1ZTPec3OuKFsqtRzW2Go5lehW29XA21lZ65XmzQkz43VY2tyWEC202F7W3mILOjw0voOiuxRGTsN+J9w== +postcss-lab-function@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-7.0.6.tgz#3121800fc7939ed1d9a1e87abeb33c407151252c" + integrity sha512-HPwvsoK7C949vBZ+eMyvH2cQeMr3UREoHvbtra76/UhDuiViZH6pir+z71UaJQohd7VDSVUdR6TkWYKExEc9aQ== dependencies: - "@csstools/css-color-parser" "^3.1.0" - "@csstools/css-parser-algorithms" "^3.0.5" - "@csstools/css-tokenizer" "^3.0.4" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" "@csstools/utilities" "^2.0.0" -postcss-loader@^7.3.4: +postcss-loader@^7.3.3: version "7.3.4" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-7.3.4.tgz#aed9b79ce4ed7e9e89e56199d25ad1ec8f606209" integrity sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A== @@ -9063,10 +9138,10 @@ postcss-loader@^7.3.4: jiti "^1.20.0" semver "^7.5.4" -postcss-logical@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-8.1.0.tgz#4092b16b49e3ecda70c4d8945257da403d167228" - integrity sha512-pL1hXFQ2fEXNKiNiAgtfA005T9FBxky5zkX6s4GZM2D8RkVgRqz3f4g1JUoq925zXv495qk8UNldDwh8uGEDoA== +postcss-logical@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-8.0.0.tgz#0db0b90c2dc53b485a8074a4b7a906297544f58d" + integrity sha512-HpIdsdieClTjXLOyYdUPAX/XQASNIwdKt5hoZW08ZOAiI+tbV0ta1oclkpVkW5ANU+xJvk3KkA0FejkjGLXUkg== dependencies: postcss-value-parser "^4.2.0" @@ -9156,12 +9231,12 @@ postcss-modules-values@^4.0.0: dependencies: icss-utils "^5.0.0" -postcss-nesting@^13.0.2: - version "13.0.2" - resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-13.0.2.tgz#fde0d4df772b76d03b52eccc84372e8d1ca1402e" - integrity sha512-1YCI290TX+VP0U/K/aFxzHzQWHWURL+CtHMSbex1lCdpXD1SoR2sYuxDu5aNI9lPoXpKTCggFZiDJbwylU0LEQ== +postcss-nesting@^13.0.1: + version "13.0.1" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-13.0.1.tgz#c405796d7245a3e4c267a9956cacfe9670b5d43e" + integrity sha512-VbqqHkOBOt4Uu3G8Dm8n6lU5+9cJFxiuty9+4rcoyRPO9zZS1JIs6td49VIoix3qYqELHlJIn46Oih9SAKo+yQ== dependencies: - "@csstools/selector-resolve-nested" "^3.1.0" + "@csstools/selector-resolve-nested" "^3.0.0" "@csstools/selector-specificity" "^5.0.0" postcss-selector-parser "^7.0.0" @@ -9259,71 +9334,67 @@ postcss-place@^10.0.0: dependencies: postcss-value-parser "^4.2.0" -postcss-preset-env@^10.2.1: - version "10.4.0" - resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-10.4.0.tgz#fa6167a307f337b2bcdd1d125604ff97cdeb5142" - integrity sha512-2kqpOthQ6JhxqQq1FSAAZGe9COQv75Aw8WbsOvQVNJ2nSevc9Yx/IKZGuZ7XJ+iOTtVon7LfO7ELRzg8AZ+sdw== +postcss-preset-env@^10.1.0: + version "10.1.1" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-10.1.1.tgz#6ee631272353fb1c4a9711943e9b80a178ffce44" + integrity sha512-wqqsnBFD6VIwcHHRbhjTOcOi4qRVlB26RwSr0ordPj7OubRRxdWebv/aLjKLRR8zkZrbxZyuus03nOIgC5elMQ== dependencies: - "@csstools/postcss-alpha-function" "^1.0.1" - "@csstools/postcss-cascade-layers" "^5.0.2" - "@csstools/postcss-color-function" "^4.0.12" - "@csstools/postcss-color-function-display-p3-linear" "^1.0.1" - "@csstools/postcss-color-mix-function" "^3.0.12" - "@csstools/postcss-color-mix-variadic-function-arguments" "^1.0.2" - "@csstools/postcss-content-alt-text" "^2.0.8" - "@csstools/postcss-contrast-color-function" "^2.0.12" - "@csstools/postcss-exponential-functions" "^2.0.9" + "@csstools/postcss-cascade-layers" "^5.0.1" + "@csstools/postcss-color-function" "^4.0.6" + "@csstools/postcss-color-mix-function" "^3.0.6" + "@csstools/postcss-content-alt-text" "^2.0.4" + "@csstools/postcss-exponential-functions" "^2.0.5" "@csstools/postcss-font-format-keywords" "^4.0.0" - "@csstools/postcss-gamut-mapping" "^2.0.11" - "@csstools/postcss-gradients-interpolation-method" "^5.0.12" - "@csstools/postcss-hwb-function" "^4.0.12" - "@csstools/postcss-ic-unit" "^4.0.4" - "@csstools/postcss-initial" "^2.0.1" - "@csstools/postcss-is-pseudo-class" "^5.0.3" - "@csstools/postcss-light-dark-function" "^2.0.11" + "@csstools/postcss-gamut-mapping" "^2.0.6" + "@csstools/postcss-gradients-interpolation-method" "^5.0.6" + "@csstools/postcss-hwb-function" "^4.0.6" + "@csstools/postcss-ic-unit" "^4.0.0" + "@csstools/postcss-initial" "^2.0.0" + "@csstools/postcss-is-pseudo-class" "^5.0.1" + "@csstools/postcss-light-dark-function" "^2.0.7" "@csstools/postcss-logical-float-and-clear" "^3.0.0" "@csstools/postcss-logical-overflow" "^2.0.0" "@csstools/postcss-logical-overscroll-behavior" "^2.0.0" "@csstools/postcss-logical-resize" "^3.0.0" - "@csstools/postcss-logical-viewport-units" "^3.0.4" - "@csstools/postcss-media-minmax" "^2.0.9" - "@csstools/postcss-media-queries-aspect-ratio-number-values" "^3.0.5" + "@csstools/postcss-logical-viewport-units" "^3.0.3" + "@csstools/postcss-media-minmax" "^2.0.5" + "@csstools/postcss-media-queries-aspect-ratio-number-values" "^3.0.4" "@csstools/postcss-nested-calc" "^4.0.0" "@csstools/postcss-normalize-display-values" "^4.0.0" - "@csstools/postcss-oklab-function" "^4.0.12" - "@csstools/postcss-progressive-custom-properties" "^4.2.1" - "@csstools/postcss-random-function" "^2.0.1" - "@csstools/postcss-relative-color-syntax" "^3.0.12" + "@csstools/postcss-oklab-function" "^4.0.6" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/postcss-random-function" "^1.0.1" + "@csstools/postcss-relative-color-syntax" "^3.0.6" "@csstools/postcss-scope-pseudo-class" "^4.0.1" - "@csstools/postcss-sign-functions" "^1.1.4" - "@csstools/postcss-stepped-value-functions" "^4.0.9" - "@csstools/postcss-text-decoration-shorthand" "^4.0.3" - "@csstools/postcss-trigonometric-functions" "^4.0.9" + "@csstools/postcss-sign-functions" "^1.1.0" + "@csstools/postcss-stepped-value-functions" "^4.0.5" + "@csstools/postcss-text-decoration-shorthand" "^4.0.1" + "@csstools/postcss-trigonometric-functions" "^4.0.5" "@csstools/postcss-unset-value" "^4.0.0" - autoprefixer "^10.4.21" - browserslist "^4.26.0" + autoprefixer "^10.4.19" + browserslist "^4.23.1" css-blank-pseudo "^7.0.1" - css-has-pseudo "^7.0.3" + css-has-pseudo "^7.0.1" css-prefers-color-scheme "^10.0.0" - cssdb "^8.4.2" + cssdb "^8.2.1" postcss-attribute-case-insensitive "^7.0.1" postcss-clamp "^4.1.0" - postcss-color-functional-notation "^7.0.12" + postcss-color-functional-notation "^7.0.6" postcss-color-hex-alpha "^10.0.0" postcss-color-rebeccapurple "^10.0.0" - postcss-custom-media "^11.0.6" - postcss-custom-properties "^14.0.6" - postcss-custom-selectors "^8.0.5" + postcss-custom-media "^11.0.5" + postcss-custom-properties "^14.0.4" + postcss-custom-selectors "^8.0.4" postcss-dir-pseudo-class "^9.0.1" - postcss-double-position-gradients "^6.0.4" + postcss-double-position-gradients "^6.0.0" postcss-focus-visible "^10.0.1" postcss-focus-within "^9.0.1" postcss-font-variant "^5.0.0" postcss-gap-properties "^6.0.0" postcss-image-set-function "^7.0.0" - postcss-lab-function "^7.0.12" - postcss-logical "^8.1.0" - postcss-nesting "^13.0.2" + postcss-lab-function "^7.0.6" + postcss-logical "^8.0.0" + postcss-nesting "^13.0.1" postcss-opacity-percentage "^3.0.0" postcss-overflow-shorthand "^6.0.0" postcss-page-break "^3.0.4" @@ -9421,7 +9492,7 @@ postcss-zindex@^6.0.2: resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-6.0.2.tgz#e498304b83a8b165755f53db40e2ea65a99b56e1" integrity sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg== -postcss@^8.4.21, postcss@^8.4.24, postcss@^8.4.33: +postcss@^8.4.21, postcss@^8.4.24, postcss@^8.4.26, postcss@^8.4.33, postcss@^8.4.38: version "8.4.49" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.49.tgz#4ea479048ab059ab3ae61d082190fabfd994fe19" integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA== @@ -9430,15 +9501,6 @@ postcss@^8.4.21, postcss@^8.4.24, postcss@^8.4.33: picocolors "^1.1.1" source-map-js "^1.2.1" -postcss@^8.5.4: - version "8.5.6" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" - integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== - dependencies: - nanoid "^3.3.11" - picocolors "^1.1.1" - source-map-js "^1.2.1" - pretty-error@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6" @@ -9504,7 +9566,7 @@ proto-list@~1.2.1: resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== -proxy-addr@^2.0.7: +proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== @@ -9524,12 +9586,12 @@ pupa@^3.1.0: dependencies: escape-goat "^4.0.0" -qs@^6.14.0: - version "6.14.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930" - integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w== +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: - side-channel "^1.1.0" + side-channel "^1.0.6" quansync@^0.2.11: version "0.2.11" @@ -9558,20 +9620,20 @@ range-parser@1.2.0: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" integrity sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A== -range-parser@^1.2.1: +range-parser@^1.2.1, range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -raw-body@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.2.tgz#3e3ada5ae5568f9095d84376fd3a49b8fb000a51" - integrity sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA== +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: - bytes "~3.1.2" - http-errors "~2.0.1" - iconv-lite "~0.7.0" - unpipe "~1.0.0" + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" rc@1.2.8: version "1.2.8" @@ -9583,6 +9645,36 @@ rc@1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-dev-utils@^12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.1.tgz#ba92edb4a1f379bd46ccd6bcd4e7bc398df33e73" + integrity sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ== + dependencies: + "@babel/code-frame" "^7.16.0" + address "^1.1.2" + browserslist "^4.18.1" + chalk "^4.1.2" + cross-spawn "^7.0.3" + detect-port-alt "^1.1.6" + escape-string-regexp "^4.0.0" + filesize "^8.0.6" + find-up "^5.0.0" + fork-ts-checker-webpack-plugin "^6.5.0" + global-modules "^2.0.0" + globby "^11.0.4" + gzip-size "^6.0.0" + immer "^9.0.7" + is-root "^2.1.0" + loader-utils "^3.2.0" + open "^8.4.0" + pkg-up "^3.1.0" + prompts "^2.4.2" + react-error-overlay "^6.0.11" + recursive-readdir "^2.2.2" + shell-quote "^1.7.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + react-dom@^18.0.0: version "18.3.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" @@ -9591,15 +9683,29 @@ react-dom@^18.0.0: loose-envify "^1.1.0" scheduler "^0.23.2" -react-fast-compare@^3.2.0: +react-error-overlay@^6.0.11: + version "6.0.11" + resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" + integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== + +react-fast-compare@^3.2.0, react-fast-compare@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49" integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ== -"react-helmet-async@npm:@slorber/react-helmet-async@1.3.0": +react-helmet-async@*: + version "2.0.5" + resolved "https://registry.yarnpkg.com/react-helmet-async/-/react-helmet-async-2.0.5.tgz#cfc70cd7bb32df7883a8ed55502a1513747223ec" + integrity sha512-rYUYHeus+i27MvFE+Jaa4WsyBKGkL6qVgbJvSBoX8mbsWoABJXdEO0bZyi0F6i+4f0NuIb8AvqPMj3iXFHkMwg== + dependencies: + invariant "^2.2.4" + react-fast-compare "^3.2.2" + shallowequal "^1.1.0" + +react-helmet-async@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/@slorber/react-helmet-async/-/react-helmet-async-1.3.0.tgz#11fbc6094605cf60aa04a28c17e0aab894b4ecff" - integrity sha512-e9/OK8VhwUSc67diWI8Rb3I0YgI9/SBQtnhe9aEuK6MhZm7ntZZimXgwXnd8W96YTmSOb9M4d8LwhRZyhWr/1A== + resolved "https://registry.yarnpkg.com/react-helmet-async/-/react-helmet-async-1.3.0.tgz#7bd5bf8c5c69ea9f02f6083f14ce33ef545c222e" + integrity sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg== dependencies: "@babel/runtime" "^7.12.5" invariant "^2.2.4" @@ -9612,10 +9718,10 @@ react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-json-view-lite@^2.3.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/react-json-view-lite/-/react-json-view-lite-2.5.0.tgz#c7ff011c7cc80e9900abc7aa4916c6a5c6d6c1c6" - integrity sha512-tk7o7QG9oYyELWHL8xiMQ8x4WzjCzbWNyig3uexmkLb54r8jO0yH3WCWx8UZS0c49eSA4QUmG5caiRJ8fAn58g== +react-json-view-lite@^1.2.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/react-json-view-lite/-/react-json-view-lite-1.5.0.tgz#377cc302821717ac79a1b6d099e1891df54c8662" + integrity sha512-nWqA1E4jKPklL2jvHWs6s+7Na0qNgw9HCP6xehdQJeg6nPBTFZgGwyko9Q0oj+jQWKTTVRS30u0toM5wiuL3iw== react-lifecycles-compat@^3.0.0: version "3.0.4" @@ -9726,6 +9832,18 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +reading-time@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/reading-time/-/reading-time-1.5.0.tgz#d2a7f1b6057cb2e169beaf87113cc3411b5bc5bb" + integrity sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg== + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== + dependencies: + resolve "^1.1.6" + recma-build-jsx@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz#c02f29e047e103d2fab2054954e1761b8ea253c4" @@ -9766,6 +9884,13 @@ recma-stringify@^1.0.0: unified "^11.0.0" vfile "^6.0.0" +recursive-readdir@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.3.tgz#e726f328c0d69153bcabd5c322d3195252379372" + integrity sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA== + dependencies: + minimatch "^3.0.5" + regenerate-unicode-properties@^10.2.0: version "10.2.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz#626e39df8c372338ea9b8028d1f99dc3fd9c3db0" @@ -9956,10 +10081,20 @@ remark-parse@^11.0.0: micromark-util-types "^2.0.0" unified "^11.0.0" -remark-rehype@>=11.0.0, remark-rehype@^10.0.0, remark-rehype@^11.0.0: - version "11.1.2" - resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-11.1.2.tgz#2addaadda80ca9bd9aa0da763e74d16327683b37" - integrity sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw== +remark-rehype@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-10.1.0.tgz#32dc99d2034c27ecaf2e0150d22a6dcccd9a6279" + integrity sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-to-hast "^12.1.0" + unified "^10.0.0" + +remark-rehype@^11.0.0: + version "11.1.1" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-11.1.1.tgz#f864dd2947889a11997c0a2667cd6b38f685bca7" + integrity sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ== dependencies: "@types/hast" "^3.0.0" "@types/mdast" "^4.0.0" @@ -10029,7 +10164,7 @@ resolve-pathname@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== -resolve@^1.14.2: +resolve@^1.1.6, resolve@^1.14.2: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -10055,6 +10190,13 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + robust-predicates@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.2.tgz#d5b28528c4824d20fc48df1928d41d9efa1ad771" @@ -10070,16 +10212,10 @@ roughjs@^4.6.6: points-on-curve "^0.2.0" points-on-path "^0.2.1" -router@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/router/-/router-2.2.0.tgz#019be620b711c87641167cc79b99090f00b146ef" - integrity sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ== - dependencies: - debug "^4.4.0" - depd "^2.0.0" - is-promise "^4.0.0" - parseurl "^1.3.3" - path-to-regexp "^8.0.0" +rtl-detect@^1.0.4: + version "1.1.2" + resolved "https://registry.yarnpkg.com/rtl-detect/-/rtl-detect-1.1.2.tgz#ca7f0330af5c6bb626c15675c642ba85ad6273c6" + integrity sha512-PGMBq03+TTG/p/cRB7HCLKJ1MgDIi07+QU1faSjiYRfmY5UsAttV9Hs08jDAHVwcOwmVLcSJkpwyfXszVjWfIQ== rtlcss@^4.1.0: version "4.3.0" @@ -10125,7 +10261,7 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -"safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -10142,10 +10278,14 @@ scheduler@^0.23.2: dependencies: loose-envify "^1.1.0" -schema-dts@^1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/schema-dts/-/schema-dts-1.1.5.tgz#9237725d305bac3469f02b292a035107595dc324" - integrity sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg== +schema-utils@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" + integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== + dependencies: + "@types/json-schema" "^7.0.4" + ajv "^6.12.2" + ajv-keywords "^3.4.1" schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0: version "3.3.0" @@ -10209,27 +10349,29 @@ semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.4, semver@^7.6.3: +semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.4, semver@^7.6.3: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== -send@^1.1.0, send@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/send/-/send-1.2.0.tgz#32a7554fb777b831dfa828370f773a3808d37212" - integrity sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: - debug "^4.3.5" - encodeurl "^2.0.0" - escape-html "^1.0.3" - etag "^1.8.1" - fresh "^2.0.0" - http-errors "^2.0.0" - mime-types "^3.0.1" - ms "^2.1.3" - on-finished "^2.4.1" - range-parser "^1.2.1" - statuses "^2.0.1" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" serialize-javascript@^6.0.0, serialize-javascript@^6.0.1: version "6.0.2" @@ -10264,15 +10406,15 @@ serve-index@^1.9.1: mime-types "~2.1.17" parseurl "~1.3.2" -serve-static@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-2.2.0.tgz#9c02564ee259bdd2251b82d659a2e7e1938d66f9" - integrity sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ== +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "^2.0.0" - escape-html "^1.0.3" - parseurl "^1.3.3" - send "^1.2.0" + encodeurl "~2.0.0" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.19.0" set-function-length@^1.2.2: version "1.2.2" @@ -10291,7 +10433,7 @@ setprototypeof@1.1.0: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== -setprototypeof@~1.2.0: +setprototypeof@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== @@ -10320,56 +10462,40 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@^1.8.1: +shell-quote@^1.7.3, shell-quote@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.2.tgz#d2d83e057959d53ec261311e9e9b8f51dcb2934a" integrity sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA== -side-channel-list@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" - integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== +shelljs@^0.8.5: + version "0.8.5" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" + integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== dependencies: - es-errors "^1.3.0" - object-inspect "^1.13.3" + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" -side-channel-map@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" - integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: - call-bound "^1.0.2" + call-bind "^1.0.7" es-errors "^1.3.0" - get-intrinsic "^1.2.5" - object-inspect "^1.13.3" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" -side-channel-weakmap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" - integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - get-intrinsic "^1.2.5" - object-inspect "^1.13.3" - side-channel-map "^1.0.1" - -side-channel@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" - integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== - dependencies: - es-errors "^1.3.0" - object-inspect "^1.13.3" - side-channel-list "^1.0.0" - side-channel-map "^1.0.1" - side-channel-weakmap "^1.0.2" - -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: +signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + sirv@^2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.4.tgz#5dd9a725c578e34e449f332703eb2a74e46a29b0" @@ -10504,16 +10630,16 @@ srcset@^4.0.0: resolved "https://registry.yarnpkg.com/srcset/-/srcset-4.0.0.tgz#336816b665b14cd013ba545b6fe62357f86e65f4" integrity sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw== +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + "statuses@>= 1.4.0 < 2": version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== -statuses@^2.0.1, statuses@~2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382" - integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw== - std-env@^3.7.0: version "3.8.0" resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.8.0.tgz#b56ffc1baf1a29dcc80a3bdf11d7fca7c315e7d5" @@ -10587,11 +10713,6 @@ strip-bom-string@^1.0.0: resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" integrity sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g== -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -10679,14 +10800,6 @@ svgo@^3.0.2, svgo@^3.2.0: csso "^5.0.5" picocolors "^1.0.0" -swr@^2.2.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/swr/-/swr-2.3.6.tgz#5fee0ee8a0762a16871ee371075cb09422b64f50" - integrity sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw== - dependencies: - dequal "^2.0.3" - use-sync-external-store "^1.4.0" - synp@^1.9.10: version "1.9.14" resolved "https://registry.yarnpkg.com/synp/-/synp-1.9.14.tgz#1feb222d273f6092c6c264746277e95655c60717" @@ -10702,6 +10815,11 @@ synp@^1.9.10: semver "^7.6.3" sort-object-keys "^1.1.3" +tapable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" @@ -10728,6 +10846,11 @@ terser@^5.10.0, terser@^5.15.1, terser@^5.26.0: commander "^2.20.0" source-map-support "~0.5.20" +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + thenify-all@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" @@ -10747,11 +10870,6 @@ thingies@^1.20.0: resolved "https://registry.yarnpkg.com/thingies/-/thingies-1.21.0.tgz#e80fbe58fd6fdaaab8fad9b67bd0a5c943c445c1" integrity sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g== -throttleit@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-2.1.0.tgz#a7e4aa0bf4845a5bd10daa39ea0c783f631a07b4" - integrity sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw== - thunky@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" @@ -10772,11 +10890,6 @@ tinyexec@^1.0.1: resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.0.1.tgz#70c31ab7abbb4aea0a24f55d120e5990bfa1e0b1" integrity sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw== -tinypool@^1.0.2: - version "1.1.1" - resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.1.1.tgz#059f2d042bd37567fbc017d3d426bdd2a2612591" - integrity sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg== - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -10792,7 +10905,7 @@ to-vfile@^6.1.0: is-buffer "^2.0.0" vfile "^4.0.0" -toidentifier@~1.0.1: +toidentifier@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== @@ -10857,14 +10970,13 @@ type-fest@^2.13.0, type-fest@^2.5.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== -type-is@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-2.0.1.tgz#64f6cf03f92fce4015c2b224793f6bdd4b068c97" - integrity sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw== +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== dependencies: - content-type "^1.0.5" - media-typer "^1.1.0" - mime-types "^3.0.0" + media-typer "0.3.0" + mime-types "~2.1.24" typedarray-to-buffer@^3.1.5: version "3.1.5" @@ -10963,6 +11075,11 @@ unist-util-find-after@^3.0.0: dependencies: unist-util-is "^4.0.0" +unist-util-generated@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.1.tgz#e37c50af35d3ed185ac6ceacb6ca0afb28a85cae" + integrity sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A== + unist-util-is@^4.0.0, unist-util-is@^4.0.2: version "4.1.0" resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" @@ -11104,7 +11221,7 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== -unpipe@~1.0.0: +unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== @@ -11117,14 +11234,6 @@ update-browserslist-db@^1.1.1: escalade "^3.2.0" picocolors "^1.1.0" -update-browserslist-db@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz#7802aa2ae91477f255b86e0e46dbc787a206ad4a" - integrity sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A== - dependencies: - escalade "^3.2.0" - picocolors "^1.1.1" - update-notifier@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-6.0.2.tgz#a6990253dfe6d5a02bd04fbb6a61543f55026b60" @@ -11166,11 +11275,6 @@ use-editable@^2.3.3: resolved "https://registry.yarnpkg.com/use-editable/-/use-editable-2.3.3.tgz#a292fe9ba4c291cd28d1cc2728c75a5fc8d9a33f" integrity sha512-7wVD2JbfAFJ3DK0vITvXBdpd9JAz5BcKAAolsnLBuBn6UDDwBGuCIAGvR3yA2BNKm578vAMVHFCWaOcA+BhhiA== -use-sync-external-store@^1.4.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz#b174bfa65cb2b526732d9f2ac0a408027876f32d" - integrity sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w== - util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -11197,6 +11301,11 @@ utility-types@^3.10.0: resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.11.0.tgz#607c40edb4f258915e901ea7995607fdf319424c" integrity sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw== +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + uuid@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.1.0.tgz#9549028be1753bb934fc96e2bca09bb4105ae912" @@ -11230,7 +11339,7 @@ value-equal@^1.0.1: resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== -vary@^1.1.2, vary@~1.1.2: +vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== @@ -11402,7 +11511,7 @@ webpack-dev-middleware@^7.4.2: range-parser "^1.2.1" schema-utils "^4.0.0" -webpack-dev-server@>=5.2.1, webpack-dev-server@^5.2.2: +webpack-dev-server@>=5.2.1, webpack-dev-server@^4.15.2: version "5.2.2" resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-5.2.2.tgz#96a143d50c58fef0c79107e61df911728d7ceb39" integrity sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg== @@ -11542,6 +11651,13 @@ which@4.0.0: dependencies: isexe "^3.1.1" +which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -11633,6 +11749,11 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== +yaml@^1.7.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + yarn-audit-fix@^9.3.10: version "9.3.12" resolved "https://registry.yarnpkg.com/yarn-audit-fix/-/yarn-audit-fix-9.3.12.tgz#cc34e87aa080bace32f2f105be6b581a3cb6eb24" @@ -11657,16 +11778,16 @@ yarn-audit-fix@^9.3.10: synp "^1.9.10" tslib "^2.5.3" +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + yocto-queue@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.1.1.tgz#fef65ce3ac9f8a32ceac5a634f74e17e5b232110" integrity sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g== -zod@^4.1.8: - version "4.1.12" - resolved "https://registry.yarnpkg.com/zod/-/zod-4.1.12.tgz#64f1ea53d00eab91853195653b5af9eee68970f0" - integrity sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ== - zwitch@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920"