diff --git a/.cargo/config.toml b/.cargo/config.toml index 7e4e7a0f90..eb89fa1e55 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,8 +1,8 @@ [alias] xtask = "run --package xtask --" -# @fb-only -# @fb-only +# @fb-only: [build] +# @fb-only: target-dir = "../../../buck-out/elp" [profile.release] codegen-units = 1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56b6434474..e9980283f2 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-13-x64, macos-latest-arm, windows-2022-x64] + platform-arch: [ubuntu-22.04-x64, ubuntu-22.04-arm, macos-15-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-13-x64 - platform: macos-13 + - platform-arch: macos-15-x64 + platform: macos-15-intel os: macos target: x86_64-apple-darwin vscode-target: darwin-x64 @@ -75,12 +75,8 @@ jobs: steps: - name: Checkout erlang-language-platform uses: "actions/checkout@v3" - - name: Checkout eqwalizer - uses: "actions/checkout@v3" with: - repository: WhatsApp/eqwalizer - path: eqwalizer - ref: main + submodules: true - name: Set up GraalVM uses: graalvm/setup-graalvm@v1 with: @@ -101,6 +97,8 @@ 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: @@ -139,7 +137,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 --no-default-features --workspace --target ${{ matrix.target }}' + run: 'cargo test --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\"' @@ -204,6 +202,8 @@ 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,3 +289,7 @@ 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/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..1445b3a80b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "eqwalizer"] + path = eqwalizer + url = https://github.com/WhatsApp/eqwalizer diff --git a/.llms/rules/elp_development.md b/.llms/rules/elp_development.md index d6462ed7e3..efd132ac4b 100644 --- a/.llms/rules/elp_development.md +++ b/.llms/rules/elp_development.md @@ -3,13 +3,34 @@ llms-gk: 'devmate_elp_development_md' apply_to_regex: '^(.*\.rs|.*\.md)$' oncalls: ['vscode_erlang'] --- - -# ELP Development Rules for LLMs - +# ELP Development Rules for LLMs (OSS) ## 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. +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 +``` ## Diagnostic Code Management @@ -17,13 +38,13 @@ ELP (Erlang Language Platform) is a language server and development tools suite 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 @@ -37,7 +58,8 @@ 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 @@ -51,16 +73,19 @@ 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 @@ -69,7 +94,8 @@ Every diagnostic must have a corresponding `DiagnosticDescriptor` that defines w - 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 @@ -78,12 +104,6 @@ Every diagnostic must have a corresponding `DiagnosticDescriptor` that defines w - 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 @@ -118,12 +138,96 @@ Every diagnostic must have a corresponding `DiagnosticDescriptor` that defines w - Group related tests in the same module - Use descriptive test names that explain the scenario +### 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`. + +#### 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 +3. **Annotations**: Mark expected diagnostics or ranges using `%% ^^^` syntax +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: + +- **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 + +```rust +let fixture = r#" +//- /src/main.erl +-module(main). + +foo( -> ok. %% +%% ^ error: W0004: Missing ')'~ +"#; +``` + ### Test Data - Create minimal test cases that focus on specific functionality - Use realistic Erlang code examples in tests - Test both positive and negative cases +### 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: + +| Crate Name | Directory Name | +| -------------------- | ----------------------- | +| `elp` | `crates/elp` | +| `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_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` | + +Example: To run tests for the `elp_ide` crate: + +```bash +cargo test -p elp_ide +``` + +Or to run tests in a specific directory: + +```bash +cargo test --manifest-path crates/ide/Cargo.toml +``` + ### Existing tests - Do not change existing tests without asking @@ -211,14 +315,8 @@ Every diagnostic must have a corresponding `DiagnosticDescriptor` that defines w - 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 `./meta/cargo.sh clippy --tests` before submitting a diff +- Always run tests before finishing +- Always run `cargo clippy --tests` before submitting PRs +- Use `cargo fmt` for code formatting diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 51f0340659..7572a84e98 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,7 +4,7 @@ { "label": "ELP: build (debug)", "type": "shell", - // @fb-only + // @fb-only: "command": "./meta/cargo.sh build", "command": "cargo build", // @oss-only "group": { "kind": "build", @@ -19,7 +19,7 @@ { "label": "ELP: build (release)", "type": "shell", - // @fb-only + // @fb-only: "command": "./meta/cargo.sh build --release", "command": "cargo build --release", // @oss-only "group": { "kind": "build", @@ -34,7 +34,7 @@ { "label": "ELP: build (release-thin)", "type": "shell", - // @fb-only + // @fb-only: "command": "./meta/cargo.sh build --profile release-thin --bins", "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 + // @fb-only: "command": "./meta/clippy.sh --workspace --tests", "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 + // @fb-only: "command": "./meta/clippy.sh --workspace --tests --fix", "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 + // @fb-only: "command": "./meta/cargo.sh test --workspace", "command": "cargo test --workspace", // @oss-only "group": { "kind": "build", diff --git a/Cargo.lock b/Cargo.lock index 03f23763eb..2da9907eca 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,7 +572,6 @@ dependencies = [ "elp_ide_ssr", "elp_project_model", "elp_syntax", - "elp_text_edit", "elp_types_db", "env_logger", "expect-test", @@ -604,7 +603,6 @@ dependencies = [ "cov-mark", "elp_ide_db", "elp_syntax", - "elp_text_edit", "expect-test", "fxhash", "hir", @@ -637,6 +635,7 @@ name = "elp_ide_db" version = "1.1.0" dependencies = [ "anyhow", + "cov-mark", "eetf", "either", "elp_base_db", @@ -644,12 +643,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", @@ -664,6 +663,7 @@ dependencies = [ "strum", "strum_macros", "tempfile", + "text-size", "toml", "tracing", ] @@ -734,10 +734,8 @@ 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", @@ -757,14 +755,6 @@ 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 5814517745..825530fe4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,13 +30,9 @@ 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 deleted file mode 100644 index 6b2733b5b9..0000000000 --- a/bench_runner/example_bench/benches/main.rs +++ /dev/null @@ -1,60 +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. - */ - -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 deleted file mode 100644 index f895c08c52..0000000000 --- a/bench_runner/runner/main.rs +++ /dev/null @@ -1,16 +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. - */ - -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 e94e180032..cd1328d14d 100644 --- a/crates/base_db/src/fixture.rs +++ b/crates/base_db/src/fixture.rs @@ -87,6 +87,7 @@ 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) } } @@ -101,6 +102,7 @@ pub struct ChangeFixture { pub diagnostics_enabled: DiagnosticsEnabled, pub tags: FxHashMap)>>, pub annotations: FxHashMap>, + pub expect_parse_errors: bool, } struct Builder { @@ -172,6 +174,7 @@ impl ChangeFixture { let FixtureWithProjectMeta { fixture, mut diagnostics_enabled, + expect_parse_errors, } = fixture_with_meta.clone(); let builder = Builder::new(diagnostics_enabled.clone()); @@ -295,7 +298,7 @@ impl ChangeFixture { ProjectManifest::discover(&AbsPathBuf::assert(json_config_file.into())).unwrap(); let loaded_project = Project::load( &manifest, - elp_config.eqwalizer, + &elp_config, &BuckQueryConfig::BuildGeneratedCode, &|_| {}, ) @@ -344,6 +347,7 @@ impl ChangeFixture { diagnostics_enabled, tags, annotations, + expect_parse_errors, }, change, project, @@ -405,6 +409,64 @@ 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 6b3757ff43..0cd8df74c9 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 +// @fb-only: mod meta_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 + // @fb-only: meta_only::ignored_sources_regexes() ]; regexes.into_iter().flatten().collect::>() }; diff --git a/crates/elp/Cargo.toml b/crates/elp/Cargo.toml index 66552ada1d..2a1b6e8b65 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 c113311661..374dcdba2f 100644 --- a/crates/elp/src/arc_types.rs +++ b/crates/elp/src/arc_types.rs @@ -8,8 +8,8 @@ * above-listed licenses. */ -// @fb-only -// @fb-only +// @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 use std::path::Path; use serde::Serialize; diff --git a/crates/elp/src/bin/args.rs b/crates/elp/src/bin/args.rs index 961d3216f7..c9790e9314 100644 --- a/crates/elp/src/bin/args.rs +++ b/crates/elp/src/bin/args.rs @@ -11,14 +11,20 @@ use std::cmp::Ordering; use std::env; use std::fs; +use std::io::IsTerminal; use std::path::PathBuf; +use anyhow::Result; +use anyhow::bail; use bpaf::Bpaf; use bpaf::Parser; use bpaf::construct; use bpaf::long; use elp_ide::elp_ide_db::DiagnosticCode; use elp_project_model::buck::BuckQueryConfig; +use hir::fold::MacroStrategy; +use hir::fold::ParenStrategy; +use hir::fold::Strategy; use itertools::Itertools; use serde::Deserialize; @@ -66,6 +72,17 @@ 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)] @@ -138,8 +155,6 @@ 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 @@ -156,8 +171,6 @@ 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/... @@ -176,8 +189,6 @@ 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 @@ -200,8 +211,6 @@ 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, } @@ -269,8 +278,6 @@ 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, @@ -327,11 +334,102 @@ 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, } +#[derive(Clone, Debug, Bpaf)] +pub struct Ssr { + /// Path to directory with project, or to a JSON file (defaults to `.`) + #[bpaf(argument("PROJECT"), fallback(PathBuf::from(".")))] + pub project: PathBuf, + /// Parse a single module from the project, not the entire project. + #[bpaf(argument("MODULE"))] + pub module: Option, + /// Parse a single application from the project, not the entire project. + #[bpaf(long("app"), long("application"), argument("APP"))] + pub app: Option, + /// Parse a single file from the project, not the entire project. This can be an include file or escript, etc. + #[bpaf(argument("FILE"))] + pub file: Option, + + /// Run with rebar + pub rebar: bool, + /// Rebar3 profile to pickup (default is test) + #[bpaf(long("as"), argument("PROFILE"), fallback("test".to_string()))] + pub profile: String, + + /// Also generate diagnostics for generated files + pub include_generated: bool, + /// Also generate diagnostics for test files + pub include_tests: bool, + + /// Show diagnostics in JSON format + #[bpaf( + argument("FORMAT"), + complete(format_completer), + fallback(None), + guard(format_guard, "Please use json") + )] + pub format: Option, + + /// Macro expansion strategy: expand | no-expand | visible-expand (default expand) + #[bpaf( + long("macros"), + argument("STRATEGY"), + complete(macros_completer), + fallback(None), + guard(macros_guard, "Please supply a valid macro expansion value") + )] + pub macro_strategy: Option, + + /// Explicitly match parentheses. If omitted, they are ignored. + #[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, + + /// SSR specs to use + #[bpaf( + positional("SSR_SPECS"), + guard(at_least_1, "there should be at least one spec") + )] + pub ssr_specs: Vec, +} + #[derive(Clone, Debug, Bpaf)] pub struct Explain { /// Error code to explain @@ -356,6 +454,8 @@ pub struct ProjectInfo { pub to: Option, /// Include the buck uquery results in the output pub buck_query: bool, + /// Dump a list of targets and their types + pub target_types: bool, } #[derive(Clone, Debug, Bpaf)] @@ -374,8 +474,6 @@ 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)] @@ -395,6 +493,7 @@ pub enum Command { GenerateCompletions(GenerateCompletions), RunServer(RunServer), Lint(Lint), + Ssr(Ssr), Version(Version), Shell(Shell), Explain(Explain), @@ -418,18 +517,47 @@ pub struct Args { /// When using buck, do not invoke a build step for generated files. pub no_buck_generated: bool, + /// 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, } impl Args { pub fn query_config(&self) -> BuckQueryConfig { - if self.no_buck_generated { + if self.buck_quick_start { + BuckQueryConfig::BuckTargetsOnly + } else if self.no_buck_generated { BuckQueryConfig::NoBuildGeneratedCode } else { 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 { @@ -473,7 +601,8 @@ pub fn command() -> impl Parser { .map(Command::EqwalizeStats) .to_options() .command("eqwalize-stats") - .help("Return statistics about code quality for eqWAlizer"); + .help("Return statistics about code quality for eqWAlizer") + .hide(); let dialyze_all = dialyze_all() .map(Command::DialyzeAll) @@ -500,6 +629,18 @@ 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() + .command("ssr") + .help("Run SSR (Structural Search and Replace) pattern matching on project files."); + let run_server = run_server() .map(Command::RunServer) .to_options() @@ -543,23 +684,26 @@ pub fn command() -> impl Parser { .help("Dump a JSON config stanza suitable for use in VS Code project.json"); construct!([ + // Note: The order here is what is used for `elp --help` output + version, + run_server, + shell, eqwalize, eqwalize_all, eqwalize_app, eqwalize_target, + eqwalize_stats, dialyze_all, lint, - run_server, - generate_completions, + ssr, + search, parse_all, parse_elp, - build_info, - version, - shell, - eqwalize_stats, explain, + build_info, project_info, glean, + generate_completions, config_stanza, ]) .fallback(Help()) @@ -642,6 +786,48 @@ 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), + ("no-expand".to_string(), None), + ("visible-expand".to_string(), None), + ] +} + +fn macros_guard(format: &Option) -> bool { + match format { + None => true, + Some(_) => parse_macro_strategy(format).is_ok(), + } +} + +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() @@ -722,6 +908,44 @@ 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 { + match macro_strategy.as_deref() { + Some("no-expand") => Ok(MacroStrategy::DoNotExpand), + Some("expand") => Ok(MacroStrategy::Expand), + Some("visible-expand") => Ok(MacroStrategy::ExpandButIncludeMacroCall), + None => Ok(MacroStrategy::Expand), + Some(s) => bail!( + "Invalid macro strategy '{}'. Valid options are: expand, no-expand, visible-expand", + s + ), + } +} + +impl Ssr { + pub fn is_format_normal(&self) -> bool { + self.format.is_none() + } + + pub fn is_format_json(&self) -> bool { + self.format == Some("json".to_string()) + } + + pub fn parse_strategy(&self) -> Result { + let macros = parse_macro_strategy(&self.macro_strategy)?; + let parens = if self.paren_strategy { + ParenStrategy::VisibleParens + } else { + ParenStrategy::InvisibleParens + }; + Ok(Strategy { macros, parens }) + } } impl ParseAllElp { diff --git a/crates/elp/src/bin/build_info_cli.rs b/crates/elp/src/bin/build_info_cli.rs index d091fc8e90..2308acb2a7 100644 --- a/crates/elp/src/bin/build_info_cli.rs +++ b/crates/elp/src/bin/build_info_cli.rs @@ -15,15 +15,18 @@ use std::io::Write; use anyhow::Result; use elp_ide::elp_ide_db::elp_base_db::AbsPath; use elp_ide::elp_ide_db::elp_base_db::AbsPathBuf; +use elp_project_model::AppType; use elp_project_model::ElpConfig; -use elp_project_model::EqwalizerConfig; use elp_project_model::IncludeParentDirs; use elp_project_model::Project; +use elp_project_model::ProjectAppData; use elp_project_model::ProjectBuildData; use elp_project_model::ProjectManifest; use elp_project_model::buck::BuckQueryConfig; -use elp_project_model::buck::query_buck_targets_bxl; +use elp_project_model::buck::BuckTarget; +use elp_project_model::buck::query_buck_targets; use elp_project_model::json::JsonConfig; +use fxhash::FxHashMap; use crate::args::BuildInfo; use crate::args::ProjectInfo; @@ -31,8 +34,8 @@ use crate::args::ProjectInfo; pub(crate) fn save_build_info(args: BuildInfo, query_config: &BuckQueryConfig) -> Result<()> { let root = fs::canonicalize(&args.project)?; let root = AbsPathBuf::assert_utf8(root); - let (_elp_config, manifest) = ProjectManifest::discover(&root)?; - let project = Project::load(&manifest, EqwalizerConfig::default(), query_config, &|_| {})?; + let (elp_config, manifest) = ProjectManifest::discover(&root)?; + let project = Project::load(&manifest, &elp_config, query_config, &|_| {})?; let mut writer = File::create(&args.to)?; let json_str = serde_json::to_string_pretty::(&project.as_json(root))?; writer.write_all(json_str.as_bytes())?; @@ -66,25 +69,68 @@ pub(crate) fn save_project_info(args: ProjectInfo, query_config: &BuckQueryConfi if args.buck_query && let ProjectBuildData::Buck(buck) = &project.project_build_data { - let buck_targets_query = query_buck_targets_bxl(&buck.buck_conf, query_config); - writer.write_all(b"================buck targets query raw================\n")?; - writer.write_all(format!("{:#?}\n", &buck_targets_query).as_bytes())?; - }; - writer.write_all(b"================manifest================\n")?; - writer.write_all(format!("{:#?}\n", &manifest).as_bytes())?; - writer.write_all(b"================project_build_data================\n")?; - writer.write_all(format!("{:#?}\n", &project.project_build_data).as_bytes())?; - writer.write_all(b"================project_app_data================\n")?; - writer.write_all(format!("{:#?}\n", &project.project_apps).as_bytes())?; + let buck_targets_query = query_buck_targets(&buck.buck_conf, query_config); + if let Ok(targets) = &buck_targets_query { + writer.write_all(format!("{:#?}\n", sort_buck_targets(targets)).as_bytes())?; + } else { + writer.write_all(format!("{:#?}\n", &buck_targets_query).as_bytes())?; + } + } else if args.target_types { + writer.write_all(b"================target types================\n")?; + for line in buck_targets_and_types(&project.project_apps) { + writer.write_all(format!("{}\n", line).as_bytes())?; + } + } else { + writer.write_all(b"================manifest================\n")?; + writer.write_all(format!("{:#?}\n", &manifest).as_bytes())?; + writer.write_all(b"================project_build_data================\n")?; + writer.write_all(format!("{:#?}\n", &project.project_build_data).as_bytes())?; + writer.write_all(b"================project_app_data================\n")?; + writer.write_all(format!("{:#?}\n", &project.project_apps).as_bytes())?; + } Ok(()) } +fn sort_buck_targets(hash_map: &FxHashMap) -> Vec<(String, &BuckTarget)> { + let mut vec = hash_map + .iter() + .map(|(n, t)| (format!("target_name:{}", n), t)) + .collect::>(); + vec.sort_by(|a, b| a.0.cmp(&b.0)); + vec +} + +fn buck_targets_and_types(apps: &[ProjectAppData]) -> Vec { + let tn = |tn| -> String { + if let Some(tn) = tn { + tn + } else { + "".to_string() + } + }; + let mut vec = apps + .iter() + .filter(|app| app.app_type != AppType::Otp) + .filter(|app| app.is_buck_generated != Some(true)) + .map(|app| { + format!( + "{:?} {:<30} {}", + app.app_type, + app.name, + tn(app.buck_target_name.clone()) + ) + }) + .collect::>(); + vec.sort(); + vec +} + fn load_project( root: &AbsPath, query_config: &BuckQueryConfig, ) -> Result<(ProjectManifest, Project)> { let (elp_config, manifest) = ProjectManifest::discover(root)?; - let project = Project::load(&manifest, elp_config.eqwalizer, query_config, &|_| {})?; + let project = Project::load(&manifest, &elp_config, query_config, &|_| {})?; Ok((manifest, project)) } @@ -94,6 +140,6 @@ fn load_fallback( ) -> Result<(ProjectManifest, Project)> { let manifest = ProjectManifest::discover_no_manifest(root, IncludeParentDirs::Yes); let elp_config = ElpConfig::default(); - let project = Project::load(&manifest, elp_config.eqwalizer, query_config, &|_| {})?; + let project = Project::load(&manifest, &elp_config, query_config, &|_| {})?; Ok((manifest, project)) } diff --git a/crates/elp/src/bin/elp_parse_cli.rs b/crates/elp/src/bin/elp_parse_cli.rs index c826c0a927..770ab60456 100644 --- a/crates/elp/src/bin/elp_parse_cli.rs +++ b/crates/elp/src/bin/elp_parse_cli.rs @@ -14,6 +14,7 @@ use std::io::Write; use std::path::Path; use std::path::PathBuf; use std::str; +use std::time::SystemTime; use anyhow::Result; use anyhow::bail; @@ -23,7 +24,6 @@ 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; @@ -40,6 +40,7 @@ use elp_ide::elp_ide_db::elp_base_db::IncludeOtp; use elp_ide::elp_ide_db::elp_base_db::ModuleName; use elp_ide::elp_ide_db::elp_base_db::Vfs; use elp_ide::elp_ide_db::elp_base_db::VfsPath; +use elp_log::telemetry; use elp_project_model::AppType; use elp_project_model::DiscoverConfig; use elp_project_model::buck::BuckQueryConfig; @@ -56,6 +57,35 @@ 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, @@ -70,6 +100,7 @@ pub fn parse_all( ) -> Result<()> { log::info!("Loading project at: {:?}", args.project); + let start_time = SystemTime::now(); // Track memory usage at the start let memory_start = MemoryUsage::now(); @@ -129,8 +160,7 @@ 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, &loaded.vfs, &cfg, &args.to, file_id, &name)? - .map_or(vec![], |x| vec![x]) + do_parse_one(&analysis, &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:?}"), }; @@ -141,13 +171,24 @@ 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")?; @@ -166,6 +207,7 @@ 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())?; } @@ -192,12 +234,14 @@ pub fn parse_all( cli, )?; } else { - print_diagnostic(&diag, &line_index, &url, &mut err_in_diag, cli)?; + print_diagnostic(&diag, &line_index, &mut err_in_diag, cli)?; } } } } + telemetry::report_elapsed_time("parse-elp done", start_time); + if args.is_format_normal() && args.report_system_stats { print_memory_usage(loaded.analysis_host, loaded.vfs, cli)?; writeln!(cli, "{}", memory_used)?; @@ -235,11 +279,10 @@ 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, url, diag); + let diag = convert::ide_to_lsp_diagnostic(line_index, diag, |_file_id| None); let severity = match diag.severity { None => DiagnosticSeverity::ERROR, Some(sev) => { @@ -282,7 +325,6 @@ 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) @@ -293,7 +335,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, vfs, config, to, file_id, module_name.as_str()).unwrap() + do_parse_one(db, config, to, file_id, module_name.as_str()).unwrap() } else { None } @@ -314,7 +356,6 @@ 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) @@ -323,7 +364,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, vfs, config, to, file_id, module_name.as_str()).unwrap() + do_parse_one(&db, config, to, file_id, module_name.as_str()).unwrap() } else { None } @@ -333,13 +374,11 @@ 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)?; @@ -357,11 +396,13 @@ 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, &url, diagnostic); + let diagnostic = + convert::ide_to_lsp_diagnostic(&line_index, diagnostic, |_file_id| None); writeln!(output, "{diagnostic:?}")?; } for diagnostic in erlang_service.iter() { - let diagnostic = convert::ide_to_lsp_diagnostic(&line_index, &url, diagnostic); + let diagnostic = + convert::ide_to_lsp_diagnostic(&line_index, diagnostic, |_file_id| None); writeln!(output, "{diagnostic:?}")?; } } diff --git a/crates/elp/src/bin/eqwalizer_cli.rs b/crates/elp/src/bin/eqwalizer_cli.rs index e9159372be..141b2157d0 100644 --- a/crates/elp/src/bin/eqwalizer_cli.rs +++ b/crates/elp/src/bin/eqwalizer_cli.rs @@ -10,6 +10,7 @@ use std::path::Path; use std::sync::Arc; +use std::time::SystemTime; use anyhow::Context; use anyhow::Result; @@ -38,6 +39,7 @@ use elp_ide::elp_ide_db::elp_base_db::FileId; use elp_ide::elp_ide_db::elp_base_db::IncludeOtp; use elp_ide::elp_ide_db::elp_base_db::ModuleName; use elp_ide::elp_ide_db::elp_base_db::VfsPath; +use elp_log::telemetry; use elp_project_model::AppName; use elp_project_model::DiscoverConfig; use elp_project_model::ProjectBuildData; @@ -76,6 +78,7 @@ pub fn eqwalize_module( cli: &mut dyn Cli, query_config: &BuckQueryConfig, ) -> Result<()> { + let start_time = SystemTime::now(); let config = DiscoverConfig::new(args.rebar, &args.profile); let mut loaded = load::load_project_at( cli, @@ -86,7 +89,10 @@ pub fn eqwalize_module( query_config, )?; build::compile_deps(&loaded, cli)?; - do_eqwalize_module(args, &mut loaded, cli) + telemetry::report_elapsed_time("eqwalize operational", start_time); + let r = do_eqwalize_module(args, &mut loaded, cli); + telemetry::report_elapsed_time("eqwalize done", start_time); + r } pub fn do_eqwalize_module( @@ -143,6 +149,7 @@ pub fn eqwalize_all( cli: &mut dyn Cli, query_config: &BuckQueryConfig, ) -> Result<()> { + let start_time = SystemTime::now(); // Hack to avoid hint appearing in tests cli.spinner(SHELL_HINT).finish(); let config = DiscoverConfig::new(args.rebar, &args.profile); @@ -155,7 +162,10 @@ pub fn eqwalize_all( query_config, )?; build::compile_deps(&loaded, cli)?; - do_eqwalize_all(args, &mut loaded, cli) + telemetry::report_elapsed_time("eqwalize-all operational", start_time); + let r = do_eqwalize_all(args, &mut loaded, cli); + telemetry::report_elapsed_time("eqwalize-all done", start_time); + r } pub fn do_eqwalize_all( @@ -176,10 +186,7 @@ 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, args.include_tests) - .unwrap() - && !otp_file_to_ignore(analysis, file_id) + if analysis.should_eqwalize(file_id).unwrap() && !otp_file_to_ignore(analysis, file_id) { if args.stats { add_stat(name.to_string()); @@ -226,6 +233,7 @@ pub fn eqwalize_app( cli: &mut dyn Cli, query_config: &BuckQueryConfig, ) -> Result<()> { + let start_time = SystemTime::now(); let config = DiscoverConfig::new(args.rebar, &args.profile); let mut loaded = load::load_project_at( cli, @@ -236,7 +244,10 @@ pub fn eqwalize_app( query_config, )?; build::compile_deps(&loaded, cli)?; - do_eqwalize_app(args, &mut loaded, cli) + telemetry::report_elapsed_time("eqwalize-app operational", start_time); + let r = do_eqwalize_app(args, &mut loaded, cli); + telemetry::report_elapsed_time("eqwalize-app done", start_time); + r } pub fn do_eqwalize_app( @@ -255,9 +266,7 @@ 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, args.include_tests) - .unwrap() + && analysis.should_eqwalize(file_id).unwrap() && !otp_file_to_ignore(analysis, file_id) { Some(file_id) @@ -283,6 +292,7 @@ pub fn eqwalize_target( cli: &mut dyn Cli, query_config: &BuckQueryConfig, ) -> Result<()> { + let start_time = SystemTime::now(); let config = DiscoverConfig::buck(); let mut loaded = load::load_project_at( cli, @@ -294,6 +304,7 @@ pub fn eqwalize_target( )?; set_eqwalizer_config(&mut loaded); + telemetry::report_elapsed_time("eqwalize-target operational", start_time); let buck = match &loaded.project.project_build_data { ProjectBuildData::Buck(buck) => buck, @@ -323,9 +334,7 @@ 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, args.include_tests) - .unwrap() + if analysis.should_eqwalize(file_id).unwrap() && !otp_file_to_ignore(analysis, file_id) { file_ids.push(file_id); @@ -353,13 +362,15 @@ elp eqwalize-target erl/chatd #same as //erl/chatd/... but enables shell complet let mut reporter = reporting::PrettyReporter::new(analysis, &loaded, cli); let bail_on_error = args.bail_on_error; - eqwalize(EqwalizerInternalArgs { + let r = eqwalize(EqwalizerInternalArgs { analysis, loaded: &loaded, file_ids, reporter: &mut reporter, bail_on_error, - }) + }); + telemetry::report_elapsed_time("eqwalize-target done", start_time); + r } pub fn eqwalize_stats( @@ -390,9 +401,7 @@ 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, args.include_tests) - .expect("cancelled") + if analysis.should_eqwalize(file_id).expect("cancelled") && !otp_file_to_ignore(analysis, file_id) { analysis @@ -464,8 +473,6 @@ 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| { @@ -584,17 +591,6 @@ 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 0c1946b329..5b39a4aa06 100644 --- a/crates/elp/src/bin/erlang_service_cli.rs +++ b/crates/elp/src/bin/erlang_service_cli.rs @@ -11,6 +11,7 @@ use std::fs; use std::path::Path; use std::str; +use std::time::SystemTime; use anyhow::Context; use anyhow::Error; @@ -26,6 +27,7 @@ use elp_ide::Analysis; use elp_ide::elp_ide_db::elp_base_db::FileId; use elp_ide::elp_ide_db::elp_base_db::IncludeOtp; use elp_ide::erlang_service::DiagnosticLocation; +use elp_log::telemetry; use elp_log::timeit; use elp_project_model::AppType; use elp_project_model::DiscoverConfig; @@ -40,6 +42,7 @@ use crate::reporting::add_stat; use crate::reporting::dump_stats; pub fn parse_all(args: &ParseAll, cli: &mut dyn Cli, query_config: &BuckQueryConfig) -> Result<()> { + let start_time = SystemTime::now(); let config = DiscoverConfig::new(!args.buck, &args.profile); let loaded = load::load_project_at( cli, @@ -52,10 +55,15 @@ pub fn parse_all(args: &ParseAll, cli: &mut dyn Cli, query_config: &BuckQueryCon build::compile_deps(&loaded, cli)?; fs::create_dir_all(&args.to)?; + telemetry::report_elapsed_time("parse-all operational", start_time); + let parse_diagnostics = do_parse_all(cli, &loaded, &args.to, &args.module, args.buck)?; if args.stats { dump_stats(cli, args.list_modules); } + + telemetry::report_elapsed_time("parse-all done", start_time); + if !parse_diagnostics.is_empty() { writeln!( cli, @@ -142,14 +150,15 @@ 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 { - directive_location, + file_attribute_location: directive_location, + error_path: _, error_location: _, }) => ( Some(directive_location), @@ -161,7 +170,7 @@ pub fn do_parse_one( relative_path: relative_path.to_owned(), line_num, msg: err.msg.to_owned(), - range, + range: range.copied(), } }) .collect(); diff --git a/crates/elp/src/bin/glean.rs b/crates/elp/src/bin/glean.rs index dad833e0c1..cb420261d2 100644 --- a/crates/elp/src/bin/glean.rs +++ b/crates/elp/src/bin/glean.rs @@ -11,7 +11,6 @@ use core::option::Option::None; use std::io::Write; use std::mem; -use std::path::Path; use anyhow::Result; use elp::build::load; @@ -85,7 +84,7 @@ const REC_ARITY: u32 = 99; const HEADER_ARITY: u32 = 100; const FACTS_FILE: &str = "facts.json"; -// @fb-only +// @fb-only: mod meta_only; #[derive(Serialize, Debug, Eq, Hash, PartialEq, Clone)] struct GleanFileId(u32); @@ -93,7 +92,6 @@ struct GleanFileId(u32); #[derive(Clone, Debug, Default)] struct IndexConfig { pub multi: bool, - pub prefix: Option, } impl From for FileId { @@ -769,10 +767,7 @@ 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, - prefix: args.prefix.clone(), - }; + let config = IndexConfig { multi: args.multi }; let (facts, module_index) = indexer.index(config)?; write_results(facts, module_index, cli, args) } @@ -861,14 +856,7 @@ 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, - config.prefix.as_ref(), - ) { + match Self::index_file(db, file_id, path, project_id, &module_index) { Some((file, line, decl, xref, facts, module_fact)) => { let mut result = FxHashMap::default(); result.insert( @@ -884,14 +872,7 @@ 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, - config.prefix.as_ref(), - ) + Self::index_file(db, file_id, &path, project_id, &module_index) }) }) .flatten() @@ -948,7 +929,6 @@ impl GleanIndexer { path: &VfsPath, project_id: ProjectId, module_index: &FxHashMap, - prefix: Option<&String>, ) -> Option<( FileFact, FileLinesFact, @@ -957,7 +937,7 @@ impl GleanIndexer { Option<(Vec, XRefFact)>, Option, )> { - let file_fact = Self::file_fact(db, file_id, path, project_id, prefix)?; + let file_fact = Self::file_fact(db, file_id, path, project_id)?; 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)?; @@ -1014,7 +994,7 @@ impl GleanIndexer { .filter(|text| !text.is_empty()) }); - // @fb-only + // @fb-only: let exdoc_link = elp_ide::meta_only::exdoc_links::module_exdoc_link(&module, &sema); let exdoc_link: Option = None; // @oss-only ModuleFact::new( @@ -1173,16 +1153,12 @@ 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 = match prefix { - Some(prefix) => Path::new(&prefix).join(file_path).to_str()?.into(), - None => file_path.as_str().to_string(), - }; + let file_path = file_path.as_str().to_string(); Some(FileFact::new(file_id, file_path)) } @@ -1556,7 +1532,7 @@ impl GleanIndexer { }) => { let def = macro_def.as_ref()?; let mut resolved = Self::resolve_macro_v2(sema, def, source_file, ctx)?; - // @fb-only + // @fb-only: meta_only::resolve_macro_expansion(sema, *expansion, ctx, &mut resolved); Some(resolved) } hir::AnyExpr::Pat(Pat::MacroCall { macro_def, .. }) @@ -1584,7 +1560,7 @@ impl GleanIndexer { vars: FxHashMap<&Location, &String>, ) -> Vec { let mut result = vec![]; - if !db.is_eqwalizer_enabled(file_id, false) { + if !db.is_eqwalizer_enabled(file_id) { return result; } let module_diagnostics = db.eqwalizer_diagnostics_by_project(project_id, vec![file_id]); @@ -1899,9 +1875,9 @@ impl GleanIndexer { let source_file = sema.parse(file_id); let range = Self::find_range(sema, ctx, &source_file, &expr_source)?; - // @fb-only - // @fb-only - // @fb-only + // @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()); let wam_url = None; // @oss-only Some(XRef { @@ -2063,7 +2039,6 @@ 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()); @@ -2090,25 +2065,6 @@ 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#" @@ -2379,10 +2335,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 @@ -2437,10 +2393,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 aeb6fe4871..241a3d4481 100644 --- a/crates/elp/src/bin/lint_cli.rs +++ b/crates/elp/src/bin/lint_cli.rs @@ -13,12 +13,14 @@ 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; @@ -51,16 +53,16 @@ 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; @@ -75,6 +77,7 @@ pub fn run_lint_command( cli: &mut dyn Cli, query_config: &BuckQueryConfig, ) -> Result<()> { + let start_time = SystemTime::now(); let memory_start = MemoryUsage::now(); if let Some(to) = &args.to { @@ -86,9 +89,12 @@ pub fn run_lint_command( // We load the project after loading config, in case it bails with // errors. No point wasting time if the config is wrong. let mut loaded = load_project(args, cli, query_config)?; + telemetry::report_elapsed_time("lint operational", start_time); let result = do_codemod(cli, &mut loaded, &diagnostics_config, args); + telemetry::report_elapsed_time("lint done", start_time); + let memory_end = MemoryUsage::now(); let memory_used = memory_end - memory_start; @@ -109,7 +115,7 @@ fn get_and_report_diagnostics_config(args: &Lint, cli: &mut dyn Cli) -> Result Result> { + loaded: &LoadResult, + module: &Option, +) -> Result<(Vec<(String, FileId, DiagnosticCollection)>, bool, bool)> { 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())); - 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()) + // 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)) } -fn do_parse_one( +fn do_diagnostics_one( db: &Analysis, config: &DiagnosticsConfig, file_id: FileId, @@ -233,6 +293,8 @@ 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 @@ -273,7 +335,18 @@ pub fn do_codemod( res = match (file_id, name) { (None, _) => { - do_parse_all(cli, &analysis, &loaded.project_id, diagnostics_config, args)? + 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 } (Some(file_id), Some(name)) => { if let Some(app) = &args.app @@ -282,87 +355,124 @@ pub fn do_codemod( { panic!("Module {} does not belong to app {}", name.as_str(), app) } - do_parse_one(&analysis, diagnostics_config, file_id, &name, args)? - .map_or(vec![], |x| vec![x]) + 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 } (Some(file_id), _) => { panic!("Could not get name from file_id for {file_id:?}") } }; - filter_diagnostics( - &analysis, - &args.module, - Some(&diagnostics_config.enabled), - &res, - &FxHashSet::default(), - )? + res }; - 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() - )?; + let mut err_in_diag = streamed_err_in_diag; + // At this point, the analysis variable from above is dropped - 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, - )?; - } - } - } + // 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 args.apply_fix && diagnostics_config.enabled.all_enabled() { + } + + // Handle apply_fix case separately since it needs to filter diagnostics anyway + if args.apply_fix { + if diagnostics_config.enabled.all_enabled() { bail!( "We cannot apply fixes if all diagnostics enabled. Perhaps provide --diagnostic-filter" ); } - if args.apply_fix && !diagnostics_config.enabled.all_enabled() { + + 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 + } + } + } + let mut changed_files = FxHashSet::default(); let mut lints = Lints::new( &mut loaded.analysis_host, @@ -370,7 +480,7 @@ pub fn do_codemod( &mut loaded.vfs, args, &mut changed_files, - initial_diags, + filtered_diags, ); // We handle the fix application result here, so // the overall status of whether error-severity @@ -382,20 +492,232 @@ pub fn do_codemod( writeln!(cli, "Apply fix failed: {err:#}").ok(); } }; + + if err_in_diag { + bail!("Errors found") + } } - if err_in_diag { + } 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 { 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)? } else { LintConfig::default() }; + let cfg = DiagnosticsConfig::default() .configure_diagnostics( &cfg_from_file, @@ -414,12 +736,82 @@ 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)?; - writeln!(cli, " {}", diag.print(&line_index, use_cli_severity))?; + 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 + )?; + } + } + } + Ok(()) } @@ -604,13 +996,10 @@ impl<'a> Lints<'a> { if self.args.check_eqwalize_all { writeln!(cli, "Running eqwalize-all to check for knock-on problems.")?; } - let diags = do_parse_one( - &self.analysis_host.analysis(), - self.cfg, - file_id, - &name, - self.args, - )?; + let diags = { + let analysis = self.analysis_host.analysis(); + do_diagnostics_one(&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 @@ -621,14 +1010,15 @@ impl<'a> Lints<'a> { bail!("Applying change introduces an error diagnostic"); } else { self.changed_files.insert((file_id, name.clone())); - let changes = changes - .iter() - .filter_map(|d| { - form_from_diff(&self.analysis_host.analysis(), file_id, d) - }) - .collect::>(); + let changed_forms = { + let analysis = self.analysis_host.analysis(); + changes + .iter() + .filter_map(|d| form_from_diff(&analysis, file_id, d)) + .collect::>() + }; - for form_id in &changes { + for form_id in &changed_forms { self.changed_forms.insert(InFile::new(file_id, *form_id)); } @@ -641,24 +1031,24 @@ impl<'a> Lints<'a> { .flatten() .collect::>(); - let new_diagnostics = filter_diagnostics( - &self.analysis_host.analysis(), - &None, - None, - &new_diags, - &self.changed_forms, - )?; + let new_diagnostics = { + let analysis = self.analysis_host.analysis(); + filter_diagnostics(&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, - &self.analysis_host.analysis(), + &analysis, + self.vfs, *file_id, + None, self.args.use_cli_severity, cli, )?; @@ -730,10 +1120,13 @@ 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, - &self.analysis_host.analysis(), + &analysis, + self.vfs, file_id, + None, self.args.use_cli_severity, cli, )?; @@ -800,7 +1193,9 @@ impl<'a> Lints<'a> { print_diagnostic( &diagnostic, &self.analysis_host.analysis(), + self.vfs, file_id, + None, self.args.use_cli_severity, cli, )?; @@ -935,13 +1330,6 @@ 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; @@ -993,7 +1381,7 @@ mod tests { expect![[r#" enabled_lints = ["P1700"] disabled_lints = [] - + [erlang_service] warnings_as_errors = true [[ad_hoc_lints.lints]] @@ -1081,11 +1469,11 @@ mod tests { head_mismatcX(0) -> 0. "#, expect![[r#" - module specified: lints - Diagnostics reported in 1 modules: - lints: 1 - 4:2-4:15::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch' - "#]], + 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 + "#]], expect![""], ); } @@ -1102,9 +1490,8 @@ mod tests { "#, expect![[r#" module specified: lints - Diagnostics reported in 1 modules: - lints: 1 - 2:2-2:5::[Warning] [L1230] function foo/0 is unused + Diagnostics reported: + app_a/src/lints.erl:3:3-3:6::[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 e40d3b5b05..56535e4492 100644 --- a/crates/elp/src/bin/main.rs +++ b/crates/elp/src/bin/main.rs @@ -40,8 +40,10 @@ mod erlang_service_cli; mod explain_cli; mod glean; mod lint_cli; +// @fb-only: mod meta_only; mod reporting; mod shell; +mod ssr_cli; // Use jemalloc as the global allocator #[cfg(not(any(target_env = "msvc", target_os = "openbsd")))] @@ -63,9 +65,14 @@ 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 res = try_main(&mut cli, args); + 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 code = handle_res(res, cli.err()); process::exit(code); } @@ -96,14 +103,28 @@ fn setup_static(args: &Args) { } } +fn setup_cli_telemetry(args: &Args) { + match &args.command { + args::Command::RunServer(_) => { + // Do nothing, we have server telemetry + } + _ => { + // Initialize CLI telemetry, if used + // @fb-only: meta_only::initialize_telemetry(); + } + } +} + fn try_main(cli: &mut dyn Cli, args: Args) -> Result<()> { let logger = setup_logging(&args.log_file, args.no_log_buffering)?; + setup_cli_telemetry(&args); INIT.call_once(|| { setup_static(&args); 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)?, @@ -121,6 +142,9 @@ 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::GenerateCompletions(args) => { let instructions = args::gen_completions(&args.shell); writeln!(cli, "#Please run this:\n{instructions}")? @@ -264,7 +288,7 @@ mod tests { let (_stdout, stderr, code) = elp(args_vec![ "parse-all", "--project", - "../../test_projects/standard", + "../../test/test_projects/standard", "--to", tmp.path(), ]); @@ -282,7 +306,7 @@ mod tests { fn parse_all_complete(project: &str) -> Result { // Just check the command returns. - let project_path = format!("../../test_projects/{project}"); + let project_path = format!("../../test/test_projects/{project}"); let tmp = Builder::new().prefix("elp_parse_all_").tempdir().unwrap(); let (_stdout, _stderr, code) = elp(args_vec![ "parse-all", @@ -419,16 +443,34 @@ mod tests { }) .unwrap(); - let otp_version = OTP_VERSION.as_ref().expect("MISSING OTP VERSION"); let exp_path = expect_file!(format!( - "../resources/test/{}/{}/{}-OTP-{}.pretty", + "../resources/test/{}/{}/{}.pretty", project, app, module.as_str(), - otp_version, )); let (stdout, _) = cli.to_strings(); - assert_normalised_file(exp_path, &stdout, project_path.into(), false); + + 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(); + 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, + ); + } + } else { + assert_normalised_file(exp_path, &stdout, project_path.into(), false); + } } } EqwalizerDiagnostics::NoAst { module } => { @@ -563,10 +605,7 @@ mod tests { fn eqwalize_target_diagnostics_match_snapshot_pretty() { if cfg!(feature = "buck") { simple_snapshot( - args_vec![ - "eqwalize-target", - "//whatsapp/elp/test_projects/standard:app_a", - ], + args_vec!["eqwalize-target", "//standard:app_a",], "standard", expect_file!("../resources/test/standard/eqwalize_target_diagnostics.pretty"), true, @@ -630,6 +669,24 @@ 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) { @@ -913,7 +970,9 @@ 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())); + buck_config.buck_root = Some(AbsPathBuf::assert_utf8( + current_dir().unwrap().join(path_str.clone()), + )); 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]/"); @@ -925,38 +984,13 @@ 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": [ "" ], @@ -964,61 +998,88 @@ mod tests { "macros": { "COMMON_TEST": "true", "TEST": "true" - } + }, + "name": "app_a_SUITE", + "src_dirs": [] }, { - "name": "common", - "dir": "/[prelude]//erlang/common_test/common", + "dir": "/[prelude]//erlang/common_test/test_exec/src", + "extra_src_dirs": [], + "include_dirs": [], + "macros": {}, + "name": "test_exec", "src_dirs": [ - "src" - ], + "" + ] + }, + { + "dir": "/[prelude]//erlang/common_test/common", "extra_src_dirs": [], "include_dirs": [ "include" ], - "macros": {} + "macros": {}, + "name": "common", + "src_dirs": [ + "src" + ] }, { - "name": "cth_hooks", "dir": "/[prelude]//erlang/common_test/cth_hooks/src", - "src_dirs": [ - "" - ], "extra_src_dirs": [], "include_dirs": [ "" ], - "macros": {} + "macros": {}, + "name": "cth_hooks", + "src_dirs": [ + "" + ] }, { - "name": "buck2_shell_utils", "dir": "/[prelude]//erlang/shell/src", - "src_dirs": [ - "" - ], "extra_src_dirs": [], "include_dirs": [], - "macros": {} + "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" + ] }, { - "name": "test_binary", "dir": "/[prelude]//erlang/common_test/test_binary/src", - "src_dirs": [ - "" - ], "extra_src_dirs": [], "include_dirs": [], - "macros": {} + "macros": {}, + "name": "test_binary", + "src_dirs": [ + "" + ] }, { - "name": "test_cli_lib", "dir": "/[prelude]//erlang/common_test/test_cli_lib/src", - "src_dirs": [ - "" - ], "extra_src_dirs": [], "include_dirs": [], - "macros": {} + "macros": {}, + "name": "test_cli_lib", + "src_dirs": [ + "" + ] } ], "deps": [] @@ -1033,6 +1094,12 @@ 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() { @@ -1046,7 +1113,7 @@ mod tests { "--to", tmp_file.clone(), "--project", - path_str + path_str.clone() ]; let (stdout, stderr, code) = elp(args); assert_eq!( @@ -1061,7 +1128,9 @@ 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())); + buck_config.buck_root = Some(AbsPathBuf::assert_utf8( + current_dir().unwrap().join(path_str.clone()), + )); 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]/"); @@ -1297,6 +1366,7 @@ mod tests { check_lint_fix( args_vec![ "lint", + "--no-stream", "--diagnostic-filter", "W0010", "--experimental", @@ -1324,6 +1394,7 @@ mod tests { check_lint_fix( args_vec![ "lint", + "--no-stream", "--diagnostic-filter", "W0010", "--experimental", @@ -1349,7 +1420,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( + check_lint_fix_stderr_sorted( args_vec![ "lint", "--diagnostic-filter", @@ -1383,7 +1454,7 @@ mod tests { "lint", "--experimental", "--config-file", - "../../test_projects/linter/does_not_exist.toml" + "../../test/test_projects/linter/does_not_exist.toml" ], "linter", expect_file!("../resources/test/linter/parse_elp_lint_custom_config_invalid_output.stdout"), @@ -1395,7 +1466,7 @@ mod tests { &[], false, Some(expect![[r#" - unable to read "../../test_projects/linter/does_not_exist.toml": No such file or directory (os error 2) + unable to read "../../test/test_projects/linter/does_not_exist.toml": No such file or directory (os error 2) "#]]), ) .expect("bad test"); @@ -1406,12 +1477,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( + check_lint_fix_stderr_sorted( args_vec![ "lint", "--experimental", "--config-file", - "../../test_projects/linter/elp_lint_test1.toml" + "../../test/test_projects/linter/elp_lint_test1.toml" ], "linter", expect_file!("../resources/test/linter/parse_elp_lint_custom_config_output.stdout"), @@ -1422,6 +1493,7 @@ mod tests { Path::new("../resources/test/lint/lint_recursive"), &[], false, + None, ) .expect("bad test"); } @@ -1436,7 +1508,7 @@ mod tests { "lint", "--experimental", "--config-file", - "../../test_projects/linter/elp_lint_adhoc.toml", + "../../test/test_projects/linter/elp_lint_adhoc.toml", "--module", "app_b", "--apply-fix", @@ -1460,14 +1532,14 @@ mod tests { #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn lint_diagnostic_ignore(buck: bool) { - simple_snapshot( + simple_snapshot_sorted( args_vec![ "lint", "--experimental", "--diagnostic-ignore", "W0011", "--config-file", - "../../test_projects/linter/elp_lint_test_ignore.toml" + "../../test/test_projects/linter/elp_lint_test_ignore.toml" ], "linter", expect_file!("../resources/test/linter/parse_elp_lint_ignore.stdout"), @@ -1511,7 +1583,7 @@ mod tests { &[], false, Some(expect![[r#" - failed to read "../../test_projects/linter_bad_config/.elp_lint.toml":expected a right bracket, found an identifier at line 6 column 4 + failed to read "../../test/test_projects/linter_bad_config/.elp_lint.toml":expected a right bracket, found an identifier at line 6 column 4 "#]]), ) .expect("bad test"); @@ -1520,8 +1592,8 @@ mod tests { #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn lint_no_diagnostics_filter_all_enabled(buck: bool) { - simple_snapshot_expect_error( - args_vec!["lint",], + simple_snapshot_expect_error_sorted( + args_vec!["lint"], "linter", expect_file!("../resources/test/linter/parse_elp_no_lint_specified_output.stdout"), buck, @@ -1529,10 +1601,24 @@ 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( + simple_snapshot_expect_error_sorted( args_vec!["lint", "--format", "json"], "linter", expect_file!("../resources/test/linter/parse_elp_no_lint_specified_json_output.stdout"), @@ -1559,11 +1645,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( + check_lint_fix_stderr_sorted( args_vec![ "lint", "--config-file", - "../../test_projects/linter/elp_lint_test2.toml" + "../../test/test_projects/linter/elp_lint_test2.toml" ], "linter", expect_file!("../resources/test/linter/parse_elp_lint_explicit_enable_output.stdout"), @@ -1586,7 +1672,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( + check_lint_fix_stderr_sorted( args_vec![ "lint", "--diagnostic-filter", @@ -1611,38 +1697,6 @@ 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) { @@ -1830,7 +1884,7 @@ mod tests { #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn lint_edoc(buck: bool) { - simple_snapshot( + simple_snapshot_sorted( args_vec![ "lint", "--include-edoc-diagnostics", @@ -1864,7 +1918,7 @@ mod tests { #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn lint_ct_include_tests(buck: bool) { - simple_snapshot_expect_error( + simple_snapshot_expect_error_sorted( args_vec![ "lint", "--include-ct-diagnostics", @@ -1882,8 +1936,8 @@ mod tests { #[test] fn lint_resolves_generated_includes() { if cfg!(feature = "buck") { - simple_snapshot_expect_error( - args_vec!["lint"], + simple_snapshot_expect_error_sorted( + args_vec!["lint", "--module", "top_includer",], "buck_tests_2", expect_file!("../resources/test/buck_tests_2/resolves_generated_includes.stdout"), true, @@ -1898,7 +1952,8 @@ mod tests { simple_snapshot_expect_stderror( args_vec!["lint",], "buck_bad_config", - expect_file!("../resources/test/buck_bad_config/bxl_error_message.stdout"), + // @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 true, None, true, @@ -1908,11 +1963,12 @@ mod tests { #[test] fn lint_warnings_as_errors() { - simple_snapshot_expect_error( + simple_snapshot_expect_error_sorted( args_vec![ "lint", + "--no-stream" "--config-file", - "../../test_projects/linter/elp_lint_warnings_as_errors.toml" + "../../test/test_projects/linter/elp_lint_warnings_as_errors.toml" ], "linter", expect_file!("../resources/test/linter/warnings_as_errors.stdout"), @@ -1927,7 +1983,7 @@ mod tests { args_vec![ "lint", "--config-file", - "../../test_projects/linter/elp_lint_custom_function_matches.toml", + "../../test/test_projects/linter/elp_lint_custom_function_matches.toml", "--module", "custom_function_matches" ], @@ -1938,6 +1994,287 @@ mod tests { ) } + #[test] + fn lint_unavailable_type() { + 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", + ], + "linter", + expect_file!("../resources/test/linter/ssr_ad_hoc.stdout"), + true, + None, + ) + } + + #[test] + fn lint_ssr_from_bad_config() { + simple_snapshot_expect_stderror( + args_vec![ + "lint", + "--config-file", + "../../test/test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml", + ], + "linter", + expect_file!("../resources/test/linter/ssr_ad_hoc_parse_fail.stdout"), + true, + None, + false, + ) + } + + #[test] + fn lint_ssr_as_cli_arg() { + simple_snapshot( + args_vec!["ssr", "ssr: {_@A, _@B}.",], + "linter", + expect_file!("../resources/test/linter/ssr_ad_hoc_cli.stdout"), + true, + None, + ) + } + + #[test] + fn lint_ssr_as_cli_arg_without_prefix() { + simple_snapshot( + args_vec!["ssr", "{_@A, _@B}",], + "linter", + expect_file!("../resources/test/linter/ssr_ad_hoc_cli.stdout"), + true, + None, + ) + } + + #[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( + args_vec!["ssr", "3" "{4}",], + "linter", + expect_file!("../resources/test/linter/ssr_ad_hoc_cli_multiple.stdout"), + true, + None, + ) + } + + #[test] + fn lint_ssr_as_cli_arg_malformed() { + simple_snapshot_expect_stderror( + args_vec!["ssr", "ssr: {_@A, = _@B}.",], + "linter", + expect_file!("../resources/test/linter/ssr_ad_hoc_cli_parse_error.stdout"), + true, + None, + false, + ) + } + + #[test] + fn lint_ssr_as_cli_parens_visible() { + simple_snapshot( + args_vec!["ssr", "--parens", "(_@A)",], + "linter", + expect_file!("../resources/test/linter/ssr_ad_hoc_cli_parens_visible.stdout"), + true, + None, + ) + } + + #[test] + fn lint_ssr_as_cli_parens_invisible() { + // Invisible parens are the default + simple_snapshot( + args_vec!["ssr", "(((3)))",], + "linter", + expect_file!("../resources/test/linter/ssr_ad_hoc_cli_parens_invisible.stdout"), + true, + None, + ) + } + + #[test] + fn lint_ssr_as_cli_macros_expand() { + simple_snapshot( + args_vec!["ssr", "--macros", "expand", "?BAR(_@AA)", "{4}"], + "linter", + expect_file!("../resources/test/linter/ssr_ad_hoc_cli_macros_expand.stdout"), + true, + None, + ) + } + + #[test] + fn lint_ssr_as_cli_macros_expand_is_default() { + simple_snapshot( + args_vec!["ssr", "?BAR(_@AA)", "{4}"], + "linter", + expect_file!("../resources/test/linter/ssr_ad_hoc_cli_macros_expand.stdout"), + true, + None, + ) + } + + #[test] + fn lint_ssr_as_cli_macros_visible_expand() { + simple_snapshot( + args_vec!["ssr", "--macros", "visible-expand", "?BAR(_@AA)", "{4}"], + "linter", + expect_file!("../resources/test/linter/ssr_ad_hoc_cli_macros_visible_expand.stdout"), + true, + None, + ) + } + + #[test] + fn lint_ssr_as_cli_macros_no_expand() { + simple_snapshot( + args_vec!["ssr", "--macros", "no-expand", "?BAR(_@AA)", "{4}"], + "linter", + expect_file!("../resources/test/linter/ssr_ad_hoc_cli_macros_no_expand.stdout"), + true, + None, + ) + } + + #[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) { @@ -2069,6 +2406,117 @@ 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] @@ -2159,6 +2607,26 @@ mod tests { expected.assert_eq(&stdout); } + #[test] + fn ssr_help() { + let args = args::args() + .run_inner(Args::from(&["ssr", "--help"])) + .unwrap_err(); + let expected = expect_file!["../resources/test/ssr_help.stdout"]; + let stdout = args.unwrap_stdout(); + 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() @@ -2377,6 +2845,61 @@ 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, @@ -2510,6 +3033,55 @@ 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, @@ -2564,7 +3136,14 @@ mod tests { } fn project_path(project: &str) -> String { - format!("../../test_projects/{project}") + 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() } struct BackupFiles { diff --git a/crates/elp/src/bin/shell.rs b/crates/elp/src/bin/shell.rs index 490c852893..13ff79ed36 100644 --- a/crates/elp/src/bin/shell.rs +++ b/crates/elp/src/bin/shell.rs @@ -15,6 +15,7 @@ use std::path::Path; use std::path::PathBuf; use std::process::Command; use std::sync::Arc; +use std::time::SystemTime; use anyhow::Result; use elp::build::load; @@ -29,6 +30,7 @@ use elp_ide::elp_ide_db::elp_base_db::SourceDatabaseExt; use elp_ide::elp_ide_db::elp_base_db::SourceRoot; use elp_ide::elp_ide_db::elp_base_db::SourceRootId; use elp_ide::elp_ide_db::elp_base_db::VfsPath; +use elp_log::telemetry; use elp_project_model::DiscoverConfig; use elp_project_model::buck::BuckQueryConfig; use paths::Utf8PathBuf; @@ -155,10 +157,9 @@ 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" && opt != "--include-tests") + .find(|&opt| opt != "--include-generated") { return Err(ShellError::UnexpectedOption( "eqwalize-app".into(), @@ -175,7 +176,6 @@ impl ShellCommand { rebar, app: app.into(), include_generated, - include_tests, bail_on_error: false, }))); } @@ -183,10 +183,9 @@ 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" && opt != "--include-tests") + .find(|&opt| opt != "--include-generated") { return Err(ShellError::UnexpectedOption( "eqwalize-all".into(), @@ -202,7 +201,6 @@ impl ShellCommand { rebar, format: None, include_generated, - include_tests, bail_on_error: false, stats: false, list_modules: false, @@ -224,10 +222,8 @@ 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 "; @@ -331,6 +327,7 @@ fn update_changes( } pub fn run_shell(shell: &Shell, cli: &mut dyn Cli, query_config: &BuckQueryConfig) -> Result<()> { + let start_time = SystemTime::now(); let mut cmd = Command::new("watchman"); let _ = cmd.arg("--version").output().map_err(|_| { anyhow::Error::msg("`watchman` command not found. install it from https://facebook.github.io/watchman/ to use `elp shell`.") @@ -349,6 +346,7 @@ pub fn run_shell(shell: &Shell, cli: &mut dyn Cli, query_config: &BuckQueryConfi Mode::Shell, query_config, )?; + telemetry::report_elapsed_time("shell operational", start_time); let mut rl = rustyline::DefaultEditor::new()?; let mut last_read = watchman.get_clock()?; write!(cli, "{WELCOME}")?; @@ -403,5 +401,6 @@ pub fn run_shell(shell: &Shell, cli: &mut dyn Cli, query_config: &BuckQueryConfi } } } + telemetry::report_elapsed_time("shell done", start_time); Ok(()) } diff --git a/crates/elp/src/bin/ssr_cli.rs b/crates/elp/src/bin/ssr_cli.rs new file mode 100644 index 0000000000..36f26d4554 --- /dev/null +++ b/crates/elp/src/bin/ssr_cli.rs @@ -0,0 +1,717 @@ +/* + * 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::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; +use elp::convert; +use elp::memory_usage::MemoryUsage; +use elp::otp_file_to_ignore; +use elp_eqwalizer::Mode; +use elp_ide::Analysis; +use elp_ide::AnalysisHost; +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; +use elp_ide::elp_ide_db::elp_base_db::ModuleName; +use elp_ide::elp_ide_db::elp_base_db::ProjectId; +use elp_ide::elp_ide_db::elp_base_db::VfsPath; +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 hir::Semantic; +use paths::Utf8PathBuf; +use rayon::prelude::ParallelBridge; +use rayon::prelude::ParallelIterator; + +use crate::args::Ssr; +use crate::reporting; +use crate::reporting::print_memory_usage; + +fn normalize_ssr_pattern(pattern: &str) -> String { + if pattern.starts_with("ssr:") { + pattern.to_string() + } else { + format!("ssr: {}.", pattern) + } +} + +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(); + + // Validate all SSR patterns early + let analysis_host = AnalysisHost::default(); + let analysis = analysis_host.analysis(); + for pattern in &args.ssr_specs { + let normalized_pattern = normalize_ssr_pattern(pattern); + match analysis.validate_ssr_pattern(&normalized_pattern) { + Ok(Ok(())) => {} + Ok(Err(e)) => bail!("invalid SSR pattern '{}': {}", pattern, e), + Err(_cancelled) => bail!("SSR pattern validation was cancelled"), + } + } + + // Parse the strategy from CLI arguments + let strategy = args.parse_strategy()?; + + // Create the lint config with all SSR patterns + 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); + } + + // Build the diagnostics config + let diagnostics_config = DiagnosticsConfig::default() + .configure_diagnostics( + &lint_config, + &Some("ad-hoc: ssr-match".to_string()), + &None, + FallBackToAll::Yes, + )? + .set_include_generated(args.include_generated) + .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(()); + } + + // 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); + + telemetry::report_elapsed_time("ssr done", start_time); + + let memory_end = MemoryUsage::now(); + let memory_used = memory_end - memory_start; + + // Print memory usage at the end if requested and format is normal + if args.is_format_normal() && args.report_system_stats { + print_memory_usage(loaded.analysis_host, loaded.vfs, cli)?; + writeln!(cli, "{}", memory_used)?; + } + r +} + +pub fn run_ssr( + cli: &mut dyn Cli, + loaded: &mut LoadResult, + diagnostics_config: &DiagnosticsConfig, + args: &Ssr, + use_color: bool, +) -> Result<()> { + let analysis = loaded.analysis(); + let (file_id, name) = match &args.module { + Some(module) => match analysis.module_file_id(loaded.project_id, module)? { + Some(file_id) => { + if args.is_format_normal() { + writeln!(cli, "module specified: {module}")?; + } + (Some(file_id), analysis.module_name(file_id)?) + } + None => panic!("Module not found: {module}"), + }, + None => match &args.file { + Some(file_name) => { + if args.is_format_normal() { + writeln!(cli, "file specified: {file_name}")?; + } + let path_buf = Utf8PathBuf::from_path_buf(fs::canonicalize(file_name).unwrap()) + .expect("UTF8 conversion failed"); + let path = AbsPath::assert(&path_buf); + let path = path.as_os_str().to_str().unwrap(); + ( + loaded + .vfs + .file_id(&VfsPath::new_real_path(path.to_string())) + .map(|(id, _)| id), + path_buf.as_path().file_name().map(ModuleName::new), + ) + } + None => (None, None), + }, + }; + + 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, + )?; + } + (Some(file_id), Some(name)) => { + if let Some(app) = &args.app + && let Ok(Some(file_app)) = analysis.file_app_name(file_id) + && file_app != AppName(app.to_string()) + { + 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)?; + } + } + (Some(file_id), _) => { + panic!("Could not get name from file_id for {file_id:?}") + } + }; + + if match_count == 0 { + 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, + )?; + } + writeln!(cli)?; + } + } + } + Ok(()) +} + +fn load_project( + args: &Ssr, + cli: &mut dyn Cli, + query_config: &BuckQueryConfig, +) -> Result { + log::info!("Loading project at: {:?}", args.project); + let config = DiscoverConfig::new(args.rebar, &args.profile); + load::load_project_at( + cli, + &args.project, + config, + IncludeOtp::Yes, + Mode::Server, + query_config, + ) +} +fn do_parse_one( + db: &Analysis, + config: &DiagnosticsConfig, + file_id: FileId, + 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); + } + + // Run only the SSR lint configured in lints_from_config + let diagnostics = db.with_db(|database| { + let sema = Semantic::new(database); + let mut diags = Vec::new(); + config + .lints_from_config + .get_diagnostics(&mut diags, &sema, file_id); + diags + })?; + + if !diagnostics.is_empty() { + let res = (name.to_string(), file_id, diagnostics); + Ok(Some(res)) + } else { + Ok(None) + } +} + +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)?; + } + Ok(()) +} + +fn print_diagnostic_json( + diagnostic: &diagnostics::Diagnostic, + analysis: &Analysis, + file_id: FileId, + path: &Path, + use_cli_severity: bool, + cli: &mut dyn Cli, +) -> Result<(), anyhow::Error> { + let line_index = analysis.line_index(file_id)?; + let converted_diagnostic = + convert::ide_to_arc_diagnostic(&line_index, path, diagnostic, use_cli_severity); + writeln!( + cli, + "{}", + serde_json::to_string(&converted_diagnostic).unwrap_or_else(|err| panic!( + "print_diagnostics_json failed for '{converted_diagnostic:?}': {err}" + )) + )?; + 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/build/load.rs b/crates/elp/src/build/load.rs index cb9cb6570f..67457e049f 100644 --- a/crates/elp/src/build/load.rs +++ b/crates/elp/src/build/load.rs @@ -80,12 +80,7 @@ pub fn load_project_at( log::info!("Discovered project: {manifest:?}"); let pb = cli.spinner("Loading build info"); - let project = Project::load( - &manifest, - elp_config.eqwalizer.clone(), - query_config, - &|_progress| {}, - )?; + let project = Project::load(&manifest, &elp_config, query_config, &|_progress| {})?; pb.finish(); load_project(cli, project, include_otp, eqwalizer_mode) diff --git a/crates/elp/src/cli.rs b/crates/elp/src/cli.rs index b3070768d6..0678aaebc1 100644 --- a/crates/elp/src/cli.rs +++ b/crates/elp/src/cli.rs @@ -30,18 +30,13 @@ pub trait Cli: Write + WriteColor { fn err(&mut self) -> &mut dyn Write; } -pub struct Real(StandardStream, Stderr); +pub struct StandardCli(StandardStream, Stderr); -impl Default for Real { - fn default() -> Self { - Self( - StandardStream::stdout(ColorChoice::Always), - std::io::stderr(), - ) +impl StandardCli { + fn new(color_choice: ColorChoice) -> Self { + Self(StandardStream::stdout(color_choice), std::io::stderr()) } -} -impl Real { fn progress_with_style( &self, len: u64, @@ -59,7 +54,7 @@ impl Real { } } -impl Cli for Real { +impl Cli for StandardCli { fn progress(&self, len: u64, prefix: &'static str) -> ProgressBar { self.progress_with_style(len, prefix, " {prefix:25!} {bar} {pos}/{len} {wide_msg}") } @@ -84,6 +79,63 @@ impl Cli for Real { } } +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) @@ -108,6 +160,48 @@ 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 432382a0c0..681a022261 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 +// @fb-only: use crate::meta_only; // Defines the server-side configuration of ELP. We generate *parts* // of VS Code's `package.json` config from this. @@ -42,6 +42,8 @@ use crate::from_json; // `new_name | `old_name` so that we keep parsing the old name. config_data! { struct ConfigData { + /// Whether to use the expermintal `buck2 targets` quick start process. + buck_quickStart: bool = json! { false }, /// Whether to show experimental ELP diagnostics that might /// have more false positives than usual. diagnostics_enableExperimental: bool = json! { false }, @@ -178,7 +180,7 @@ impl Config { return; } self.data = ConfigData::from_json(json); - // @fb-only + // @fb-only: meta_only::harmonise_gks(self); } pub fn update_gks(&mut self, json: serde_json::Value) { @@ -379,8 +381,20 @@ impl Config { try_or!(self.caps.window.as_ref()?.work_done_progress?, false) } + pub fn set_buck_quick_start(&mut self, value: bool) { + self.data.buck_quickStart = value; + } + + pub fn buck_quick_start(&self) -> bool { + self.data.buck_quickStart + } + pub fn buck_query(&self) -> BuckQueryConfig { - BuckQueryConfig::BuildGeneratedCode + if self.buck_quick_start() { + BuckQueryConfig::BuckTargetsOnly + } else { + BuckQueryConfig::BuildGeneratedCode + } } pub fn set_eqwalizer_all(&mut self, value: bool) { @@ -604,10 +618,15 @@ mod tests { let s = remove_ws(&schema); - expect![[r#""elp.diagnostics.disabled":{"default":[],"items":{"type":"string"},"markdownDescription":"ListofELPdiagnosticstodisable.","type":"array","uniqueItems":true},"elp.diagnostics.enableExperimental":{"default":false,"markdownDescription":"WhethertoshowexperimentalELPdiagnosticsthatmight\nhavemorefalsepositivesthanusual.","type":"boolean"},"elp.diagnostics.enableOtp":{"default":false,"markdownDescription":"WhethertoreportdiagnosticsforOTPfiles.","type":"boolean"},"elp.diagnostics.onSave.enable":{"default":false,"markdownDescription":"Updatenativediagnosticsonlywhenthefileissaved.","type":"boolean"},"elp.edoc.enable":{"default":false,"markdownDescription":"WhethertoreportEDocdiagnostics.","type":"boolean"},"elp.eqwalizer.all":{"default":false,"markdownDescription":"WhethertoreportEqwalizerdiagnosticsforthewholeprojectandnotonlyforopenedfiles.","type":"boolean"},"elp.eqwalizer.chunkSize":{"default":100,"markdownDescription":"Chunksizetouseforproject-wideeqwalization.","minimum":0,"type":"integer"},"elp.eqwalizer.maxTasks":{"default":32,"markdownDescription":"Maximumnumberoftaskstoruninparallelforproject-wideeqwalization.","minimum":0,"type":"integer"},"elp.highlightDynamic.enable":{"default":false,"markdownDescription":"Ifenabled,highlightvariableswithtype`dynamic()`whenEqwalizerresultsareavailable.","type":"boolean"},"elp.hoverActions.docLinks.enable":{"default":false,"markdownDescription":"WhethertoshowHoverActionsoftype`docs`.Onlyapplieswhen\n`#elp.hoverActions.enable#`isset.","type":"boolean"},"elp.hoverActions.enable":{"default":false,"markdownDescription":"WhethertoshowHoverActions.","type":"boolean"},"elp.inlayHints.parameterHints.enable":{"default":true,"markdownDescription":"Whethertoshowfunctionparameternameinlayhintsatthecall\nsite.","type":"boolean"},"elp.lens.buck2.mode":{"default":null,"markdownDescription":"Thebuck2modetouseforrunningtestsviathecodelenses.","type":["null","string"]},"elp.lens.debug.enable":{"default":false,"markdownDescription":"Whethertoshowthe`Debug`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.enable":{"default":false,"markdownDescription":"WhethertoshowCodeLensesinErlangfiles.","type":"boolean"},"elp.lens.links.enable":{"default":false,"markdownDescription":"Whethertoshowthe`Link`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.logview.links":{"default":false,"markdownDescription":"WhethertoenableLogViewlenslinks.","type":"boolean"},"elp.lens.run.coverage.enable":{"default":true,"markdownDescription":"Displaycodecoverageinformationwhenrunningtestsviathe\nCodeLenses.Onlyapplieswhen`#elp.lens.enabled`and\n`#elp.lens.run.enable#`areset.","type":"boolean"},"elp.lens.run.enable":{"default":false,"markdownDescription":"Whethertoshowthe`Run`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.run.interactive.enable":{"default":false,"markdownDescription":"Whethertoshowthe`RunInteractive`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.scuba.links":{"default":false,"markdownDescription":"WhethertoenableScubalenslinks.","type":"boolean"},"elp.lens.wam.links":{"default":false,"markdownDescription":"WhethertoenableWAMlenslinks.","type":"boolean"},"elp.log":{"default":"error","markdownDescription":"ConfigureLSP-basedloggingusingenv_loggersyntax.","type":"string"},"elp.signatureHelp.enable":{"default":true,"markdownDescription":"WhethertoshowSignatureHelp.","type":"boolean"},"elp.typesOnHover.enable":{"default":false,"markdownDescription":"Displaytypeswhenhoveringoverexpressions.","type":"boolean"},"#]] + expect![[r#""elp.buck.quickStart":{"default":false,"markdownDescription":"Whethertousetheexpermintal`buck2targets`quickstartprocess.","type":"boolean"},"elp.diagnostics.disabled":{"default":[],"items":{"type":"string"},"markdownDescription":"ListofELPdiagnosticstodisable.","type":"array","uniqueItems":true},"elp.diagnostics.enableExperimental":{"default":false,"markdownDescription":"WhethertoshowexperimentalELPdiagnosticsthatmight\nhavemorefalsepositivesthanusual.","type":"boolean"},"elp.diagnostics.enableOtp":{"default":false,"markdownDescription":"WhethertoreportdiagnosticsforOTPfiles.","type":"boolean"},"elp.diagnostics.onSave.enable":{"default":false,"markdownDescription":"Updatenativediagnosticsonlywhenthefileissaved.","type":"boolean"},"elp.edoc.enable":{"default":false,"markdownDescription":"WhethertoreportEDocdiagnostics.","type":"boolean"},"elp.eqwalizer.all":{"default":false,"markdownDescription":"WhethertoreportEqwalizerdiagnosticsforthewholeprojectandnotonlyforopenedfiles.","type":"boolean"},"elp.eqwalizer.chunkSize":{"default":100,"markdownDescription":"Chunksizetouseforproject-wideeqwalization.","minimum":0,"type":"integer"},"elp.eqwalizer.maxTasks":{"default":32,"markdownDescription":"Maximumnumberoftaskstoruninparallelforproject-wideeqwalization.","minimum":0,"type":"integer"},"elp.highlightDynamic.enable":{"default":false,"markdownDescription":"Ifenabled,highlightvariableswithtype`dynamic()`whenEqwalizerresultsareavailable.","type":"boolean"},"elp.hoverActions.docLinks.enable":{"default":false,"markdownDescription":"WhethertoshowHoverActionsoftype`docs`.Onlyapplieswhen\n`#elp.hoverActions.enable#`isset.","type":"boolean"},"elp.hoverActions.enable":{"default":false,"markdownDescription":"WhethertoshowHoverActions.","type":"boolean"},"elp.inlayHints.parameterHints.enable":{"default":true,"markdownDescription":"Whethertoshowfunctionparameternameinlayhintsatthecall\nsite.","type":"boolean"},"elp.lens.buck2.mode":{"default":null,"markdownDescription":"Thebuck2modetouseforrunningtestsviathecodelenses.","type":["null","string"]},"elp.lens.debug.enable":{"default":false,"markdownDescription":"Whethertoshowthe`Debug`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.enable":{"default":false,"markdownDescription":"WhethertoshowCodeLensesinErlangfiles.","type":"boolean"},"elp.lens.links.enable":{"default":false,"markdownDescription":"Whethertoshowthe`Link`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.logview.links":{"default":false,"markdownDescription":"WhethertoenableLogViewlenslinks.","type":"boolean"},"elp.lens.run.coverage.enable":{"default":true,"markdownDescription":"Displaycodecoverageinformationwhenrunningtestsviathe\nCodeLenses.Onlyapplieswhen`#elp.lens.enabled`and\n`#elp.lens.run.enable#`areset.","type":"boolean"},"elp.lens.run.enable":{"default":false,"markdownDescription":"Whethertoshowthe`Run`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.run.interactive.enable":{"default":false,"markdownDescription":"Whethertoshowthe`RunInteractive`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.scuba.links":{"default":false,"markdownDescription":"WhethertoenableScubalenslinks.","type":"boolean"},"elp.lens.wam.links":{"default":false,"markdownDescription":"WhethertoenableWAMlenslinks.","type":"boolean"},"elp.log":{"default":"error","markdownDescription":"ConfigureLSP-basedloggingusingenv_loggersyntax.","type":"string"},"elp.signatureHelp.enable":{"default":true,"markdownDescription":"WhethertoshowSignatureHelp.","type":"boolean"},"elp.typesOnHover.enable":{"default":false,"markdownDescription":"Displaytypeswhenhoveringoverexpressions.","type":"boolean"},"#]] .assert_eq(s.as_str()); expect![[r#" + "elp.buck.quickStart": { + "default": false, + "markdownDescription": "Whether to use the expermintal `buck2 targets` quick start process.", + "type": "boolean" + }, "elp.diagnostics.disabled": { "default": [], "items": { diff --git a/crates/elp/src/convert.rs b/crates/elp/src/convert.rs index 323a56bdf3..c8db07a5d0 100644 --- a/crates/elp/src/convert.rs +++ b/crates/elp/src/convert.rs @@ -26,6 +26,7 @@ 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; @@ -67,11 +68,14 @@ 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, -) -> lsp_types::Diagnostic { + get_file_info: F, +) -> lsp_types::Diagnostic +where + F: Fn(FileId) -> Option<(LineIndex, Url)>, +{ let code_description = match &d.code_doc_uri { Some(uri) => match lsp_types::Url::parse(uri) { Ok(href) => Some(lsp_types::CodeDescription { href }), @@ -90,7 +94,7 @@ pub fn ide_to_lsp_diagnostic( code_description, source, message: d.message.clone(), - related_information: from_related(line_index, url, &d.related_info), + related_information: from_related(get_file_info, &d.related_info), tags: d.tag.as_ref().map(lsp_diagnostic_tags), data: None, } @@ -158,22 +162,26 @@ pub fn eqwalizer_to_arc_diagnostic( ) } -fn from_related( - line_index: &LineIndex, - url: &Url, +fn from_related( + get_file_info: F, r: &Option>, -) -> Option> { +) -> Option> +where + F: Fn(elp_ide::elp_ide_db::elp_base_db::FileId) -> Option<(LineIndex, Url)>, +{ r.as_ref().map(|ri| { ri.iter() - .map(|i| { + .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)?; let location = Location { - range: range(line_index, i.range), - uri: url.clone(), + range: range(&line_index, i.range), + uri, }; - DiagnosticRelatedInformation { + Some(DiagnosticRelatedInformation { location, message: i.message.clone(), - } + }) }) .collect() }) diff --git a/crates/elp/src/lib.rs b/crates/elp/src/lib.rs index 2ed7fece37..f462141e39 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 +// @fb-only: mod meta_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 + // @fb-only: .chain(meta_only::FILES_TO_IGNORE.iter()) .map(SmolStr::new) .collect(); } @@ -162,6 +162,7 @@ mod tests { use elp_ide::diagnostics::ErlangServiceConfig; use elp_ide::diagnostics::Lint; use elp_ide::diagnostics::LintsFromConfig; + use elp_ide::diagnostics::MatchSsr; use elp_ide::diagnostics::ReplaceCall; use elp_ide::diagnostics::ReplaceCallAction; use elp_ide::diagnostics::Replacement; @@ -188,6 +189,12 @@ mod tests { perm: vec![1, 2], }), }), + Lint::LintMatchSsr(MatchSsr { + ssr_pattern: "ssr: _@A = 10.".to_string(), + message: None, + strategy: None, + severity: None, + }), ], }, linters: FxHashMap::default(), @@ -223,6 +230,10 @@ mod tests { type = "ArgsPermutation" perm = [1, 2] + [[ad_hoc_lints.lints]] + type = "LintMatchSsr" + ssr_pattern = "ssr: _@A = 10." + [linters] "#]] .assert_eq(&toml::to_string::(&lint_config).unwrap()); diff --git a/crates/elp/src/project_loader.rs b/crates/elp/src/project_loader.rs index f092e26242..103353e5db 100644 --- a/crates/elp/src/project_loader.rs +++ b/crates/elp/src/project_loader.rs @@ -18,6 +18,7 @@ use elp_log::telemetry; use elp_project_model::ElpConfig; use elp_project_model::IncludeParentDirs; use elp_project_model::ProjectManifest; +use elp_project_model::buck::BuckQueryConfig; use elp_project_model::otp::Otp; use fxhash::FxHashMap; use fxhash::FxHashSet; @@ -121,12 +122,33 @@ impl ProjectLoader { } } +/// If using buck quick start, it happens in two stages, first to +/// get the basic project config, then to invoke the generation of +/// any artifacts that will become part of the project. +#[derive(Debug, PartialEq, Eq)] +pub enum BuckGenerated { + /// Initial value + NoLoadDone, + /// After first load (buck targets) + NoGenerated, + /// After second load (elp.bxl) + Generated, +} + pub struct ReloadManager { + /// Files that have changed since the last reload. changed_files: FxHashSet, + /// This field is updated when a `changed_files` file is added. + /// It allows us to wait until the last file has been added + /// when a branch switch is done to avoid doing a reload for each. + /// We wait until RELOAD_QUIESCENT_WAIT_TIME has elapsed before doing + /// the reload. last_change: SystemTime, /// ReloadManager clients should ensure this is set when a reload /// task is active, reset when done. reload_in_progress: bool, + buck_generated: BuckGenerated, + buck_quick_start: bool, } /// How long to wait after the last changed file was added before @@ -134,24 +156,76 @@ pub struct ReloadManager { const RELOAD_QUIESCENT_WAIT_TIME: Duration = Duration::from_millis(500); impl ReloadManager { - pub fn new() -> ReloadManager { + pub fn new(buck_quick_start: bool) -> ReloadManager { ReloadManager { changed_files: FxHashSet::default(), last_change: SystemTime::now(), reload_in_progress: false, + buck_generated: BuckGenerated::NoLoadDone, + buck_quick_start, } } /// Used to check if any files are queued, and if so cancel an /// existing reload - pub fn has_changed_files(&self) -> bool { - !self.changed_files.is_empty() + pub fn ok_to_switch_workspace(&self) -> bool { + if self.buck_quick_start { + // `BuckGenerated::NoLoadDone` or `BuckGenerated::NoGenerated`. + + if self.buck_generated == BuckGenerated::NoLoadDone { + // We are doing a 2-stage load, and have just completed the `buck targets` step. + // So time to activate the Project, this is the whole point of the two stage process + true + } else { + self.changed_files.is_empty() + } + } else { + // Do not switch if there are files which will trigger a reload. + // This lets us start that process sooner without wasted effort + // switching when it is going to change anyway. + self.changed_files.is_empty() + } } - pub fn set_reload_active(&mut self) { + pub fn set_reload_active(&mut self) -> BuckQueryConfig { self.reload_in_progress = true; + self.get_query_config() } - pub fn set_reload_done(&mut self) { + + pub fn get_query_config(&self) -> BuckQueryConfig { + if self.buck_quick_start { + match self.buck_generated { + BuckGenerated::NoLoadDone => BuckQueryConfig::BuckTargetsOnly, + BuckGenerated::NoGenerated => BuckQueryConfig::BuildGeneratedCode, + BuckGenerated::Generated => BuckQueryConfig::BuildGeneratedCode, + } + } else { + BuckQueryConfig::BuildGeneratedCode + } + } + + /// This is called when the `Task::FetchProject` is done in `server.rs`, + /// but only after `switch_workspace_ok` has returned true. + pub fn set_reload_done(&mut self, a_file_per_project: FxHashSet) { + if self.buck_quick_start { + match &self.buck_generated { + BuckGenerated::NoLoadDone => { + if self.changed_files.is_empty() && !a_file_per_project.is_empty() { + // We have done the initial "buck targets" query on at least one Project, + // move on to doing `elp.bxl` + self.buck_generated = BuckGenerated::NoGenerated; + self.changed_files = a_file_per_project; + } else { + // We already have changed files from another source, so + // need to repeat this step. Do not change state. + } + } + BuckGenerated::NoGenerated => { + self.buck_generated = BuckGenerated::Generated; + } + BuckGenerated::Generated => {} + }; + } self.reload_in_progress = false; } @@ -181,4 +255,8 @@ impl ReloadManager { self.last_change = SystemTime::now(); } } + + pub fn set_buck_quickstart(&mut self, buck_quick_start: bool) { + self.buck_quick_start = buck_quick_start; + } } 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 new file mode 100644 index 0000000000..f5225605a5 --- /dev/null +++ b/crates/elp/src/resources/test/buck_bad_config/bxl_error_message_oss.stdout @@ -0,0 +1 @@ +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 7c9890aa86..d4954b84ee 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,18 +1,7 @@ + [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 -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. - 49:18-49:31::[WeakWarning] [W0051] Binary string can be written using sigil syntax. - 51:18-51:28::[WeakWarning] [W0051] Binary string can be written using sigil syntax. - 51:38-51:51::[WeakWarning] [W0051] Binary string can be written using sigil syntax. - 55:30-55:40::[WeakWarning] [W0051] Binary string can be written using sigil syntax. +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 diff --git a/crates/elp/src/resources/test/config_stanza.stdout b/crates/elp/src/resources/test/config_stanza.stdout index bdd5c8b487..02e3da475a 100644 --- a/crates/elp/src/resources/test/config_stanza.stdout +++ b/crates/elp/src/resources/test/config_stanza.stdout @@ -1,4 +1,9 @@ { + "elp.buck.quickStart": { + "default": false, + "markdownDescription": "Whether to use the expermintal `buck2 targets` quick start process.", + "type": "boolean" + }, "elp.diagnostics.disabled": { "default": [], "items": { diff --git a/crates/elp/src/resources/test/diagnostics/lint_no_stream.stdout b/crates/elp/src/resources/test/diagnostics/lint_no_stream.stdout new file mode 100644 index 0000000000..eef1c92c6d --- /dev/null +++ b/crates/elp/src/resources/test/diagnostics/lint_no_stream.stdout @@ -0,0 +1,138 @@ +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 c8cdedb3ea..523b8d4bc7 100644 --- a/crates/elp/src/resources/test/diagnostics/lint_report_suppressed.stdout +++ b/crates/elp/src/resources/test/diagnostics/lint_report_suppressed.stdout @@ -1,4 +1,3 @@ module specified: suppressed -Diagnostics reported in 1 modules: - suppressed: 1 - 7:4-7:8::[Warning] [W0007] match is redundant +Diagnostics reported: +app_a/src/suppressed.erl:8:5-8:9::[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 a1db95ccbf..4b0a155055 100644 --- a/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics1.stdout +++ b/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics1.stdout @@ -1,9 +1,10 @@ module specified: diagnostics Diagnostics reported in 1 modules: - diagnostics: 6 + diagnostics: 7 2:9-2:26::[Hint] [W0037] Unspecific include. - 3:0-3:0::[Error] [L0000] Issue in included file + 3:0-3:35::[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 new file mode 100644 index 0000000000..3af8bfb086 --- /dev/null +++ b/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_error.stdout @@ -0,0 +1,5 @@ +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 0c3e5ae9a3..ede82c7c5f 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,3 +4,4 @@ {"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 b3a5f365b7..f040cee98e 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,11 +1,12 @@ module specified: lints -Diagnostics reported in 1 modules: - lints: 1 - 4:0-4:13::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch' +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 --------------------------------------------- Applying fix in module 'lints' for - 4:0-4:13::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch' + 5:1-5:14::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch' + 4:1-4:14: Mismatched clause name @@ -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 6bcfecb8a6..a88f567370 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,12 +1,11 @@ module specified: lint_recursive -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 +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 --------------------------------------------- Applying fix in module 'lint_recursive' for - 18:4-18:11::[Warning] [W0007] match is redundant + 19:5-19:12::[Warning] [W0007] match is redundant @@ -16,7 +16,7 @@ test_foo2(Config) -> @@ -21,12 +20,12 @@ Applying fix in module 'lint_recursive' for New filtered diagnostics lint_recursive: 2 - 13:4-13:11::[Warning] [W0007] match is redundant - 18:4-18:10::[Warning] [W0006] this statement has no effect + 14:5-14:12::[Warning] [W0007] match is redundant + 19:5-19:11::[Warning] [W0006] this statement has no effect --------------------------------------------- Applying fix in module 'lint_recursive' for - 13:4-13:11::[Warning] [W0007] match is redundant + 14:5-14:12::[Warning] [W0007] match is redundant @@ -11,7 +11,7 @@ %% something/0. test_foo(Config) -> @@ -41,12 +40,12 @@ Applying fix in module 'lint_recursive' for New filtered diagnostics lint_recursive: 2 - 18:4-18:10::[Warning] [W0006] this statement has no effect - 13:4-13:10::[Warning] [W0006] this statement has no effect + 19:5-19:11::[Warning] [W0006] this statement has no effect + 14:5-14:11::[Warning] [W0006] this statement has no effect --------------------------------------------- Applying fix in module 'lint_recursive' for - 18:4-18:10::[Warning] [W0006] this statement has no effect + 19:5-19:11::[Warning] [W0006] this statement has no effect @@ -16,7 +16,6 @@ test_foo2(Config) -> @@ -60,12 +59,12 @@ Applying fix in module 'lint_recursive' for New filtered diagnostics lint_recursive: 2 - 16:10-16:16::[Warning] [W0010] this variable is unused - 13:4-13:10::[Warning] [W0006] this statement has no effect + 17:11-17:17::[Warning] [W0010] this variable is unused + 14:5-14:11::[Warning] [W0006] this statement has no effect --------------------------------------------- Applying fix in module 'lint_recursive' for - 16:10-16:16::[Warning] [W0010] this variable is unused + 17:11-17:17::[Warning] [W0010] this variable is unused @@ -14,7 +14,7 @@ Config, clean_mocks(). @@ -80,11 +79,11 @@ Applying fix in module 'lint_recursive' for New filtered diagnostics lint_recursive: 1 - 13:4-13:10::[Warning] [W0006] this statement has no effect + 14:5-14:11::[Warning] [W0006] this statement has no effect --------------------------------------------- Applying fix in module 'lint_recursive' for - 13:4-13:10::[Warning] [W0006] this statement has no effect + 14:5-14:11::[Warning] [W0006] this statement has no effect @@ -11,7 +11,6 @@ %% something/0. test_foo(Config) -> @@ -98,11 +97,11 @@ Applying fix in module 'lint_recursive' for New filtered diagnostics lint_recursive: 1 - 11:9-11:15::[Warning] [W0010] this variable is unused + 12:10-12:16::[Warning] [W0010] this variable is unused --------------------------------------------- Applying fix in module 'lint_recursive' for - 11:9-11:15::[Warning] [W0010] this variable is unused + 12:10-12:16::[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 5e286c673f..c34c9037db 100644 --- a/crates/elp/src/resources/test/diagnostics/parse_otp27_docstrings.jsonl +++ b/crates/elp/src/resources/test/diagnostics/parse_otp27_docstrings.jsonl @@ -1,4 +1,6 @@ module specified: otp27_docstrings Diagnostics reported in 1 modules: - otp27_docstrings: 1 + 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 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 new file mode 100644 index 0000000000..1cef26124c --- /dev/null +++ b/crates/elp/src/resources/test/diagnostics/ssr_exclude_generated.stdout @@ -0,0 +1,2 @@ +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 new file mode 100644 index 0000000000..2b88b6e10c --- /dev/null +++ b/crates/elp/src/resources/test/diagnostics/ssr_include_generated.stdout @@ -0,0 +1,5 @@ +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 43f66a0a3a..67497c4000 100644 --- a/crates/elp/src/resources/test/eqwalize_all_help.stdout +++ b/crates/elp/src/resources/test/eqwalize_all_help.stdout @@ -1,11 +1,10 @@ -Usage: [--project PROJECT] [--as PROFILE] [[--format FORMAT]] [--rebar] [--include-tests] [--bail-on-error] [--stats] [--list-modules] +Usage: [--project PROJECT] [--as PROFILE] [[--format FORMAT]] [--rebar] [--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 eaf1d3126a..bb128f249a 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] [--include-tests] [--rebar] [--bail-on-error] +Usage: [--project PROJECT] [--as PROFILE] [--rebar] [--bail-on-error] Available positional items: app name @@ -6,7 +6,6 @@ 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 eec74e4938..e9a01166dd 100644 --- a/crates/elp/src/resources/test/eqwalize_target_help.stdout +++ b/crates/elp/src/resources/test/eqwalize_target_help.stdout @@ -1,10 +1,9 @@ -Usage: [--project PROJECT] [--include-tests] [--bail-on-error] +Usage: [--project PROJECT] [--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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/any_fun_type-OTP-26.pretty deleted file mode 100644 index c2a5c42406..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/any_fun_type-OTP-26.pretty +++ /dev/null @@ -1,116 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/any_fun_type.erl:46:21 - │ -46 │ to_f_any_neg2(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: 'f0' | fun((atom()) -> pid()) | 'f1' -Context expected type: fun() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: fun((atom()) -> pid()) - However the following candidate: 'f0' - Differs from the expected type: fun() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/any_fun_type.erl:49:23 - │ -49 │ f_any_to_f0_neg(F) -> F. - │ ^ F. -Expression has type: fun() -Context expected type: 'f0' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/any_fun_type.erl:61:31 - │ -61 │ when is_function(F, 1) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun((term()) -> term()) -Context expected type: f2() - │ - -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 - │ -64 │ a_to_a(a) -> a. - │ ^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/any_fun_type.erl:92:24 - │ -92 │ f5_to_f4_cov_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: f5('a' | 'b') -Context expected type: f4('a') - │ - -Because in the expression's type: - fun((term()) -> - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -98 │ apply_f4_neg(F) -> F(a). - │ ^^^^ F('a'). -Expression has type: number() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/any_fun_type.erl:113:22 - │ -113 │ fun3_to_f4_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun((term()) -> 'a' | 'b') -Context expected type: f4('a') - │ - -Because in the expression's type: - fun((term()) -> - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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/any_fun_type-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/any_fun_type-OTP-27.pretty deleted file mode 100644 index c2a5c42406..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/any_fun_type-OTP-27.pretty +++ /dev/null @@ -1,116 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/any_fun_type.erl:46:21 - │ -46 │ to_f_any_neg2(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: 'f0' | fun((atom()) -> pid()) | 'f1' -Context expected type: fun() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: fun((atom()) -> pid()) - However the following candidate: 'f0' - Differs from the expected type: fun() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/any_fun_type.erl:49:23 - │ -49 │ f_any_to_f0_neg(F) -> F. - │ ^ F. -Expression has type: fun() -Context expected type: 'f0' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/any_fun_type.erl:61:31 - │ -61 │ when is_function(F, 1) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun((term()) -> term()) -Context expected type: f2() - │ - -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 - │ -64 │ a_to_a(a) -> a. - │ ^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/any_fun_type.erl:92:24 - │ -92 │ f5_to_f4_cov_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: f5('a' | 'b') -Context expected type: f4('a') - │ - -Because in the expression's type: - fun((term()) -> - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -98 │ apply_f4_neg(F) -> F(a). - │ ^^^^ F('a'). -Expression has type: number() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/any_fun_type.erl:113:22 - │ -113 │ fun3_to_f4_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun((term()) -> 'a' | 'b') -Context expected type: f4('a') - │ - -Because in the expression's type: - fun((term()) -> - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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/any_fun_type-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/any_fun_type.pretty similarity index 77% rename from crates/elp/src/resources/test/eqwalizer_tests/check/any_fun_type-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/any_fun_type.pretty index c2a5c42406..69251d1a75 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/any_fun_type-OTP-28.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/any_fun_type.pretty @@ -37,12 +37,6 @@ 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 │ @@ -67,16 +61,6 @@ 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 │ @@ -103,14 +87,4 @@ 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/apply_none-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/apply_none-OTP-27.pretty deleted file mode 100644 index 60ad8dc0ca..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/apply_none-OTP-27.pretty +++ /dev/null @@ -1,24 +0,0 @@ -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/apply_none.erl:26:1 - │ -26 │ ╭ apply_none1(F) -27 │ │ when is_function(F, 1), -28 │ │ is_function(F, 2) -> -29 │ │ F(a). - │ ╰────────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/apply_none.erl:32:1 - │ -32 │ apply_none2(F) -> F(ok). - │ ^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/apply_none.erl:35:1 - │ -35 │ ╭ apply_none3(F) -> -36 │ │ Res = F(ok), -37 │ │ Res. - │ ╰───────^ Clause is not covered by spec - -3 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/apply_none-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/apply_none-OTP-28.pretty deleted file mode 100644 index 60ad8dc0ca..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/apply_none-OTP-28.pretty +++ /dev/null @@ -1,24 +0,0 @@ -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/apply_none.erl:26:1 - │ -26 │ ╭ apply_none1(F) -27 │ │ when is_function(F, 1), -28 │ │ is_function(F, 2) -> -29 │ │ F(a). - │ ╰────────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/apply_none.erl:32:1 - │ -32 │ apply_none2(F) -> F(ok). - │ ^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/apply_none.erl:35:1 - │ -35 │ ╭ apply_none3(F) -> -36 │ │ Res = F(ok), -37 │ │ Res. - │ ╰───────^ Clause is not covered by spec - -3 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/apply_none-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/apply_none.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/apply_none-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/apply_none.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/approx-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/approx-OTP-26.pretty deleted file mode 100644 index 0fe7555553..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/approx-OTP-26.pretty +++ /dev/null @@ -1,105 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/approx.erl:36:5 - │ -36 │ {X, X}. - │ ^^^^^^ {X, X}. -Expression has type: {dynamic(), dynamic()} -Context expected type: 'ok' - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/approx.erl:39:1 - │ -39 │ generics_with_unions:type_var_from_nowhere(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Unknown id: generics_with_unions:type_var_from_nowhere/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/approx.erl:41:1 - │ -41 │ ╭ -spec test_trans_invalid1_neg( -42 │ │ trans_invalid() -43 │ │ ) -> nok. - │ ╰────────^ test_trans_invalid1_neg/1 references type with invalid definition: trans_invalid/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/approx.erl:47:1 - │ -47 │ ╭ -spec test_trans_invalid2_neg( -48 │ │ trans_invalid() -49 │ │ ) -> nok. - │ ╰────────^ test_trans_invalid2_neg/1 references type with invalid definition: trans_invalid/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/approx.erl:53:1 - │ -53 │ ╭ -spec test_trans_invalid3_neg( -54 │ │ trans_invalid() -55 │ │ ) -> nok. - │ ╰────────^ test_trans_invalid3_neg/1 references type with invalid definition: trans_invalid/0 - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/approx.erl:62:30 - │ -62 │ test_opaque_as_fun_neg(X) -> X(ok). - │ ^ X. -Expected fun type with arity 1 -Got: misc:o() | fun((term()) -> none()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/approx.erl:69:3 - │ -69 │ Dyn2. - │ ^^^^ - │ │ - │ Dyn2. -Expression has type: string() | dynamic() -Context expected type: 'anything' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dynamic() - 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 - │ -74 │ ╭ dyn_union_1(N, D) -> -75 │ │ Res = case D of -76 │ │ 1 -> N; -77 │ │ 2 -> D -78 │ │ end, -79 │ │ eqwalizer:reveal_type(Res), -80 │ │ Res. - │ ╰─────^ Clause is not covered by spec - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/approx.erl:79:25 - │ -79 │ eqwalizer:reveal_type(Res), - │ ^^^ dynamic(number()) - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/approx.erl:85:1 - │ -85 │ ╭ dyn_union_2(N, D) -> -86 │ │ Res = case D of -87 │ │ 2 -> D; -88 │ │ 1 -> N -89 │ │ end, -90 │ │ eqwalizer:reveal_type(Res), -91 │ │ Res. - │ ╰─────^ Clause is not covered by spec - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/approx.erl:90:25 - │ -90 │ eqwalizer:reveal_type(Res), - │ ^^^ dynamic(number()) - -11 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/approx-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/approx-OTP-28.pretty deleted file mode 100644 index 0fe7555553..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/approx-OTP-28.pretty +++ /dev/null @@ -1,105 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/approx.erl:36:5 - │ -36 │ {X, X}. - │ ^^^^^^ {X, X}. -Expression has type: {dynamic(), dynamic()} -Context expected type: 'ok' - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/approx.erl:39:1 - │ -39 │ generics_with_unions:type_var_from_nowhere(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Unknown id: generics_with_unions:type_var_from_nowhere/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/approx.erl:41:1 - │ -41 │ ╭ -spec test_trans_invalid1_neg( -42 │ │ trans_invalid() -43 │ │ ) -> nok. - │ ╰────────^ test_trans_invalid1_neg/1 references type with invalid definition: trans_invalid/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/approx.erl:47:1 - │ -47 │ ╭ -spec test_trans_invalid2_neg( -48 │ │ trans_invalid() -49 │ │ ) -> nok. - │ ╰────────^ test_trans_invalid2_neg/1 references type with invalid definition: trans_invalid/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/approx.erl:53:1 - │ -53 │ ╭ -spec test_trans_invalid3_neg( -54 │ │ trans_invalid() -55 │ │ ) -> nok. - │ ╰────────^ test_trans_invalid3_neg/1 references type with invalid definition: trans_invalid/0 - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/approx.erl:62:30 - │ -62 │ test_opaque_as_fun_neg(X) -> X(ok). - │ ^ X. -Expected fun type with arity 1 -Got: misc:o() | fun((term()) -> none()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/approx.erl:69:3 - │ -69 │ Dyn2. - │ ^^^^ - │ │ - │ Dyn2. -Expression has type: string() | dynamic() -Context expected type: 'anything' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dynamic() - 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 - │ -74 │ ╭ dyn_union_1(N, D) -> -75 │ │ Res = case D of -76 │ │ 1 -> N; -77 │ │ 2 -> D -78 │ │ end, -79 │ │ eqwalizer:reveal_type(Res), -80 │ │ Res. - │ ╰─────^ Clause is not covered by spec - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/approx.erl:79:25 - │ -79 │ eqwalizer:reveal_type(Res), - │ ^^^ dynamic(number()) - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/approx.erl:85:1 - │ -85 │ ╭ dyn_union_2(N, D) -> -86 │ │ Res = case D of -87 │ │ 2 -> D; -88 │ │ 1 -> N -89 │ │ end, -90 │ │ eqwalizer:reveal_type(Res), -91 │ │ Res. - │ ╰─────^ Clause is not covered by spec - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/approx.erl:90:25 - │ -90 │ eqwalizer:reveal_type(Res), - │ ^^^ dynamic(number()) - -11 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/approx-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/approx.pretty similarity index 94% rename from crates/elp/src/resources/test/eqwalizer_tests/check/approx-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/approx.pretty index 0fe7555553..15655d9cac 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/approx-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/approx.pretty @@ -60,12 +60,6 @@ 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/as_pat-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/as_pat-OTP-27.pretty deleted file mode 100644 index da41873f62..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/as_pat-OTP-27.pretty +++ /dev/null @@ -1,17 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/as_pat.erl:51:38 - │ -51 │ unboxL_neg(BN = #box_n{}) -> unbox_a(BN). - │ ^^ BN. -Expression has type: #box_n{} -Context expected type: #box_a{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/as_pat.erl:61:38 - │ -61 │ unboxR_neg(#box_n{} = BN) -> unbox_b(BN). - │ ^^ BN. -Expression has type: #box_n{} -Context expected type: #box_b{} - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/as_pat-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/as_pat-OTP-28.pretty deleted file mode 100644 index da41873f62..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/as_pat-OTP-28.pretty +++ /dev/null @@ -1,17 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/as_pat.erl:51:38 - │ -51 │ unboxL_neg(BN = #box_n{}) -> unbox_a(BN). - │ ^^ BN. -Expression has type: #box_n{} -Context expected type: #box_a{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/as_pat.erl:61:38 - │ -61 │ unboxR_neg(#box_n{} = BN) -> unbox_b(BN). - │ ^^ BN. -Expression has type: #box_n{} -Context expected type: #box_b{} - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/as_pat-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/as_pat.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/as_pat-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/as_pat.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports-OTP-27.pretty deleted file mode 100644 index f1d2ca6927..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports-OTP-27.pretty +++ /dev/null @@ -1,16 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/auto_imports.erl:22:20 - │ -22 │ erlang:error(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/auto_imports-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports-OTP-28.pretty deleted file mode 100644 index f1d2ca6927..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports-OTP-28.pretty +++ /dev/null @@ -1,16 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/auto_imports.erl:22:20 - │ -22 │ erlang:error(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/auto_imports-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports.pretty similarity index 52% rename from crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports.pretty index f1d2ca6927..2c9ecb3a1f 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports-OTP-26.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/auto_imports.pretty @@ -2,15 +2,8 @@ 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/behave-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/behave-OTP-27.pretty deleted file mode 100644 index df46470af5..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/behave-OTP-27.pretty +++ /dev/null @@ -1,13 +0,0 @@ -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/behave.erl:8:20 - │ -8 │ -callback foo() -> behave1:test(). - │ ^^^^^^^^^^^^^^ Unknown id: behave1:test/0 - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ check/src/behave.erl:10:1 - │ -10 │ -type invalid() :: _T. - │ ^^^^^^^^^^^^^^^^^^^^^ _T: Type variable is unbound. - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/behave-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/behave-OTP-28.pretty deleted file mode 100644 index df46470af5..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/behave-OTP-28.pretty +++ /dev/null @@ -1,13 +0,0 @@ -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/behave.erl:8:20 - │ -8 │ -callback foo() -> behave1:test(). - │ ^^^^^^^^^^^^^^ Unknown id: behave1:test/0 - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ check/src/behave.erl:10:1 - │ -10 │ -type invalid() :: _T. - │ ^^^^^^^^^^^^^^^^^^^^^ _T: Type variable is unbound. - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/behave-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/behave.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/behave-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/behave.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/binaries-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/binaries-OTP-27.pretty deleted file mode 100644 index 123c9c69cc..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/binaries-OTP-27.pretty +++ /dev/null @@ -1,65 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:24:17 - │ -24 │ test04_neg() -> <<>>. - │ ^^^^ <<..>>. -Expression has type: binary() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:32:20 - │ -32 │ test05_neg(A) -> <>. - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:35:23 - │ -35 │ test06_neg(A, S) -> <>. - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:38:18 - │ -38 │ test07_neg(A) -> [A]. - │ ^^^ [A]. -Expression has type: [atom()] -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:55:7 - │ -55 │ <<"binary"/binary>>. - │ ^^^^^^^^ string_lit. -Expression has type: string() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:74:9 - │ -74 │ <> = Bits, - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:80:9 - │ -80 │ <> = Bits, - │ ^^^^^^^^ erlang:self(). -Expression has type: pid() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:89:7 - │ -89 │ <<[]>>. - │ ^^ []. -Expression has type: [] -Context expected type: number() - -8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/binaries-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/binaries-OTP-28.pretty deleted file mode 100644 index 123c9c69cc..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/binaries-OTP-28.pretty +++ /dev/null @@ -1,65 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:24:17 - │ -24 │ test04_neg() -> <<>>. - │ ^^^^ <<..>>. -Expression has type: binary() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:32:20 - │ -32 │ test05_neg(A) -> <>. - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:35:23 - │ -35 │ test06_neg(A, S) -> <>. - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:38:18 - │ -38 │ test07_neg(A) -> [A]. - │ ^^^ [A]. -Expression has type: [atom()] -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:55:7 - │ -55 │ <<"binary"/binary>>. - │ ^^^^^^^^ string_lit. -Expression has type: string() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:74:9 - │ -74 │ <> = Bits, - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:80:9 - │ -80 │ <> = Bits, - │ ^^^^^^^^ erlang:self(). -Expression has type: pid() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/binaries.erl:89:7 - │ -89 │ <<[]>>. - │ ^^ []. -Expression has type: [] -Context expected type: number() - -8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/binaries-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/binaries.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/binaries-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/binaries.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/booleans-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/booleans-OTP-27.pretty deleted file mode 100644 index 4407c43d42..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/booleans-OTP-27.pretty +++ /dev/null @@ -1,31 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/booleans.erl:47:3 - │ -47 │ 1 andalso b(). - │ ^ 1. -Expression has type: number() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/booleans.erl:59:3 - │ -59 │ dyn() andalso only_true(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ _ andalso _. -Expression has type: 'false' | 'true' -Context expected type: 'true' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'true' - 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/booleans-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/booleans-OTP-28.pretty deleted file mode 100644 index 4407c43d42..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/booleans-OTP-28.pretty +++ /dev/null @@ -1,31 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/booleans.erl:47:3 - │ -47 │ 1 andalso b(). - │ ^ 1. -Expression has type: number() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/booleans.erl:59:3 - │ -59 │ dyn() andalso only_true(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ _ andalso _. -Expression has type: 'false' | 'true' -Context expected type: 'true' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'true' - 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/booleans-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/booleans.pretty similarity index 80% rename from crates/elp/src/resources/test/eqwalizer_tests/check/booleans-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/booleans.pretty index 4407c43d42..7227163b41 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/booleans-OTP-26.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/booleans.pretty @@ -22,10 +22,4 @@ 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/callbacks1_pos-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks1_pos.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/callbacks1_pos-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/callbacks1_pos.pretty 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 deleted file mode 100644 index 63be36e638..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-26.pretty +++ /dev/null @@ -1,14 +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: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 deleted file mode 100644 index 63be36e638..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-27.pretty +++ /dev/null @@ -1,14 +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: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 deleted file mode 100644 index a24c7a6a48..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-28.pretty +++ /dev/null @@ -1,14 +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: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 new file mode 100644 index 0000000000..6cb2012096 --- /dev/null +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg.pretty @@ -0,0 +1,27 @@ +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/callbacks4_neg-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks4_neg-OTP-27.pretty deleted file mode 100644 index b25bd83371..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks4_neg-OTP-27.pretty +++ /dev/null @@ -1,7 +0,0 @@ -error: behaviour_does_not_exist (See https://fb.me/eqwalizer_errors#behaviour_does_not_exist) - ┌─ check/src/callbacks4_neg.erl:9:1 - │ -9 │ -behaviour(nonexistent). - │ ^^^^^^^^^^^^^^^^^^^^^^^ Behaviour does not exist: nonexistent - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks4_neg-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks4_neg-OTP-28.pretty deleted file mode 100644 index b25bd83371..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks4_neg-OTP-28.pretty +++ /dev/null @@ -1,7 +0,0 @@ -error: behaviour_does_not_exist (See https://fb.me/eqwalizer_errors#behaviour_does_not_exist) - ┌─ check/src/callbacks4_neg.erl:9:1 - │ -9 │ -behaviour(nonexistent). - │ ^^^^^^^^^^^^^^^^^^^^^^^ Behaviour does not exist: nonexistent - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks4_neg-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks4_neg.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/callbacks4_neg-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/callbacks4_neg.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks5_neg-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks5_neg-OTP-27.pretty deleted file mode 100644 index 82ba8217dd..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks5_neg-OTP-27.pretty +++ /dev/null @@ -1,7 +0,0 @@ -error: incorrect_param_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_param_type_in_cb_implementation) - ┌─ check/src/callbacks5_neg.erl:13:1 - │ -13 │ -behavior(gen_server). - │ ^^^^^^^^^^^^^^^^^^^^^ Parameter 1 in implementation of gen_server:format_status/2 has no overlap with expected parameter type. Expected: 'normal' | 'terminate', Got: 'bad'. - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks5_neg-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks5_neg-OTP-28.pretty deleted file mode 100644 index 82ba8217dd..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks5_neg-OTP-28.pretty +++ /dev/null @@ -1,7 +0,0 @@ -error: incorrect_param_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_param_type_in_cb_implementation) - ┌─ check/src/callbacks5_neg.erl:13:1 - │ -13 │ -behavior(gen_server). - │ ^^^^^^^^^^^^^^^^^^^^^ Parameter 1 in implementation of gen_server:format_status/2 has no overlap with expected parameter type. Expected: 'normal' | 'terminate', Got: 'bad'. - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks5_neg-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks5_neg.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/callbacks5_neg-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/callbacks5_neg.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks6_neg-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks6_neg-OTP-27.pretty deleted file mode 100644 index a3c0bd398b..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks6_neg-OTP-27.pretty +++ /dev/null @@ -1,13 +0,0 @@ -error: missing_cb_implementation (See https://fb.me/eqwalizer_errors#missing_cb_implementation) - ┌─ check/src/callbacks6_neg.erl:8:1 - │ -8 │ -behavior(behave). - │ ^^^^^^^^^^^^^^^^^ Missing implementation for behave callback use_invalid/0 - -error: missing_cb_implementation (See https://fb.me/eqwalizer_errors#missing_cb_implementation) - ┌─ check/src/callbacks6_neg.erl:8:1 - │ -8 │ -behavior(behave). - │ ^^^^^^^^^^^^^^^^^ Missing implementation for behave callback use_invalid2/0 - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks6_neg-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks6_neg-OTP-28.pretty deleted file mode 100644 index a3c0bd398b..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks6_neg-OTP-28.pretty +++ /dev/null @@ -1,13 +0,0 @@ -error: missing_cb_implementation (See https://fb.me/eqwalizer_errors#missing_cb_implementation) - ┌─ check/src/callbacks6_neg.erl:8:1 - │ -8 │ -behavior(behave). - │ ^^^^^^^^^^^^^^^^^ Missing implementation for behave callback use_invalid/0 - -error: missing_cb_implementation (See https://fb.me/eqwalizer_errors#missing_cb_implementation) - ┌─ check/src/callbacks6_neg.erl:8:1 - │ -8 │ -behavior(behave). - │ ^^^^^^^^^^^^^^^^^ Missing implementation for behave callback use_invalid2/0 - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks6_neg-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks6_neg.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/callbacks6_neg-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/callbacks6_neg.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks1_pos-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks7_overload_pos.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/callbacks1_pos-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/callbacks7_overload_pos.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates-OTP-26.pretty deleted file mode 100644 index 30ef1a7f38..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates-OTP-26.pretty +++ /dev/null @@ -1,140 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:13:24 - │ -13 │ {true, true} -> aa(X, Y); - │ ^ X. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:13:27 - │ -13 │ {true, true} -> aa(X, Y); - │ ^ Y. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:14:20 - │ -14 │ {true, _} -> a(X); - │ ^ X. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:15:20 - │ -15 │ {_, true} -> a(Y); - │ ^ Y. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:16:10 - │ -16 │ _ -> not-ok - │ ^^^^^^ not _. -Expression has type: boolean() -Context expected type: 'ok' | 'not_ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:16:13 - │ -16 │ _ -> not-ok - │ ^^^ - _. -Expression has type: number() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:16:14 - │ -16 │ _ -> not-ok - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:124:14 - │ -124 │ false -> {p, X} - │ ^^^^^^ - │ │ - │ {'p', X}. -Expression has type: {'p', none() | pid() | reference()} -Context expected type: {'a', atom()} | {'p', pid()} - │ - -Because in the expression's type: - { 'p', - Here the type is a union type with some valid candidates: pid() - However the following candidate: reference() - Differs from the expected type: pid() - } - ------------------------------- Detailed message ------------------------------ - - {'p', none() | pid() | reference()} is not compatible with {'a', atom()} | {'p', pid()} - because - at tuple index 2: - {'p', none() | pid() | reference()} is not compatible with {'p', pid()} - because - none() | 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 - │ -144 │ _ -> X - │ ^ - │ │ - │ X. -Expression has type: 'undefined' | none() | 'restarting' -Context expected type: {'p', pid()} | 'undefined' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'undefined' - However the following candidate: 'restarting' - Differs from the expected type: {'p', pid()} | 'undefined' - ------------------------------- Detailed message ------------------------------ - - 'undefined' | none() | '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 - │ -174 │ lists:nth(1, L). - │ ^ - │ │ - │ L. -Expression has type: #{dynamic() => dynamic()} | none() -Context expected type: [T] - │ - -Because in the expression's type: - Here the type is: #{dynamic() => dynamic()} - Context expects type: [T] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:174:16 - │ -174 │ lists:nth(1, L). - │ ^ - │ │ - │ L. -Expression has type: #{dynamic() => dynamic()} | none() -Context expected type: [dynamic()] - │ - -Because in the expression's type: - Here the type is: #{dynamic() => dynamic()} - Context expects type: [dynamic()] - -11 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates-OTP-27.pretty deleted file mode 100644 index 30ef1a7f38..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates-OTP-27.pretty +++ /dev/null @@ -1,140 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:13:24 - │ -13 │ {true, true} -> aa(X, Y); - │ ^ X. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:13:27 - │ -13 │ {true, true} -> aa(X, Y); - │ ^ Y. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:14:20 - │ -14 │ {true, _} -> a(X); - │ ^ X. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:15:20 - │ -15 │ {_, true} -> a(Y); - │ ^ Y. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:16:10 - │ -16 │ _ -> not-ok - │ ^^^^^^ not _. -Expression has type: boolean() -Context expected type: 'ok' | 'not_ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:16:13 - │ -16 │ _ -> not-ok - │ ^^^ - _. -Expression has type: number() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:16:14 - │ -16 │ _ -> not-ok - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:124:14 - │ -124 │ false -> {p, X} - │ ^^^^^^ - │ │ - │ {'p', X}. -Expression has type: {'p', none() | pid() | reference()} -Context expected type: {'a', atom()} | {'p', pid()} - │ - -Because in the expression's type: - { 'p', - Here the type is a union type with some valid candidates: pid() - However the following candidate: reference() - Differs from the expected type: pid() - } - ------------------------------- Detailed message ------------------------------ - - {'p', none() | pid() | reference()} is not compatible with {'a', atom()} | {'p', pid()} - because - at tuple index 2: - {'p', none() | pid() | reference()} is not compatible with {'p', pid()} - because - none() | 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 - │ -144 │ _ -> X - │ ^ - │ │ - │ X. -Expression has type: 'undefined' | none() | 'restarting' -Context expected type: {'p', pid()} | 'undefined' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'undefined' - However the following candidate: 'restarting' - Differs from the expected type: {'p', pid()} | 'undefined' - ------------------------------- Detailed message ------------------------------ - - 'undefined' | none() | '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 - │ -174 │ lists:nth(1, L). - │ ^ - │ │ - │ L. -Expression has type: #{dynamic() => dynamic()} | none() -Context expected type: [T] - │ - -Because in the expression's type: - Here the type is: #{dynamic() => dynamic()} - Context expects type: [T] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/case_predicates.erl:174:16 - │ -174 │ lists:nth(1, L). - │ ^ - │ │ - │ L. -Expression has type: #{dynamic() => dynamic()} | none() -Context expected type: [dynamic()] - │ - -Because in the expression's type: - Here the type is: #{dynamic() => dynamic()} - Context expects type: [dynamic()] - -11 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates.pretty similarity index 70% rename from crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates.pretty index 30ef1a7f38..a3bc7c96f9 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates-OTP-28.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/case_predicates.pretty @@ -61,7 +61,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^^^^^^ │ │ │ {'p', X}. -Expression has type: {'p', none() | pid() | reference()} +Expression has type: {'p', pid() | reference()} Context expected type: {'a', atom()} | {'p', pid()} │ @@ -72,17 +72,6 @@ Because in the expression's type: Differs from the expected type: pid() } ------------------------------- Detailed message ------------------------------ - - {'p', none() | pid() | reference()} is not compatible with {'a', atom()} | {'p', pid()} - because - at tuple index 2: - {'p', none() | pid() | reference()} is not compatible with {'p', pid()} - because - none() | 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 │ @@ -90,7 +79,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^ │ │ │ X. -Expression has type: 'undefined' | none() | 'restarting' +Expression has type: 'undefined' | 'restarting' Context expected type: {'p', pid()} | 'undefined' │ @@ -99,42 +88,20 @@ Because in the expression's type: However the following candidate: 'restarting' Differs from the expected type: {'p', pid()} | 'undefined' ------------------------------- Detailed message ------------------------------ - - 'undefined' | none() | '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 │ 174 │ lists:nth(1, L). - │ ^ - │ │ - │ L. -Expression has type: #{dynamic() => dynamic()} | none() + │ ^ L. +Expression has type: #{dynamic() => dynamic()} Context expected type: [T] - │ - -Because in the expression's type: - Here the type is: #{dynamic() => dynamic()} - Context expects type: [T] error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/case_predicates.erl:174:16 │ 174 │ lists:nth(1, L). - │ ^ - │ │ - │ L. -Expression has type: #{dynamic() => dynamic()} | none() + │ ^ L. +Expression has type: #{dynamic() => dynamic()} Context expected type: [dynamic()] - │ - -Because in the expression's type: - Here the type is: #{dynamic() => dynamic()} - Context expects type: [dynamic()] 11 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/check_SUITE-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/check_SUITE-OTP-27.pretty deleted file mode 100644 index 9e9f88bb38..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/check_SUITE-OTP-27.pretty +++ /dev/null @@ -1,9 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/test/check_SUITE.erl:13:11 - │ -13 │ fail() -> wrong_ret. - │ ^^^^^^^^^ 'wrong_ret'. -Expression has type: 'wrong_ret' -Context expected type: pid() - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/check_SUITE-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/check_SUITE-OTP-28.pretty deleted file mode 100644 index 9e9f88bb38..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/check_SUITE-OTP-28.pretty +++ /dev/null @@ -1,9 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/test/check_SUITE.erl:13:11 - │ -13 │ fail() -> wrong_ret. - │ ^^^^^^^^^ 'wrong_ret'. -Expression has type: 'wrong_ret' -Context expected type: pid() - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/check_SUITE-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/check_SUITE.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/check_SUITE-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/check_SUITE.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks1_pos-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/compiler_macro.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/callbacks1_pos-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/compiler_macro.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps-OTP-26.pretty deleted file mode 100644 index 3143803509..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps-OTP-26.pretty +++ /dev/null @@ -1,300 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/complex_maps.erl:11:21 - │ -11 │ downcast_neg1(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', c => 'd'} -Context expected type: #{a => 'b'} - │ - -Because in the expression's type: - Here the type is: #{c => ...} - 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 - │ -17 │ downcast_neg2(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', c => 'd'} -Context expected type: #{a => 'b', atom() => number()} - │ - -Because in the expression's type: - #{ c => - Here the type is: 'd' - 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 - │ -20 │ upcast_neg1(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', atom() => atom()} -Context expected type: #{a => 'b', c => 'd'} - │ - -Because in the expression's type: - Here the type is: #{atom() => atom()} - 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 - │ -23 │ upcast_neg2(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', atom() => number()} -Context expected type: #{a => 'b', c => 'd', atom() => number()} - │ - -Because in the expression's type: - #{ atom() => - Here the type is: number() - Context expects type: 'd' - , ... } - 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 - │ -38 │ downcast_neg3(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', atom() => atom()} -Context expected type: #{a => 'b'} - │ - -Because in the expression's type: - Here the type is: #{atom() => atom()} - 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 - │ -44 │ downcast_dyn_neg_1(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', dynamic(atom()) => atom()} -Context expected type: #{a => 'b'} - │ - -Because in the expression's type: - Here the type is: #{dynamic(atom()) => atom()} - 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 - │ -47 │ downcast_dyn_neg_2(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', atom() => dynamic(atom())} -Context expected type: #{a => 'b'} - │ - -Because in the expression's type: - Here the type is: #{atom() => dynamic(atom())} - 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 - │ -56 │ tuple_key_get_neg(#{{ok, {a, b}} := V}) -> V. - │ ^ V. -Expression has type: 'v' -Context expected type: 'err' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/complex_maps.erl:62:30 - │ -62 │ tuple_key_maps_get_neg(M) -> maps:get({ok, {a, b}}, M). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ maps:get({'ok', {'a', 'b'}}, M). -Expression has type: 'v' -Context expected type: 'err' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/complex_maps.erl:71:32 - │ -71 │ get_default_neg1(#{a := V}) -> V. - │ ^ V. -Expression has type: 'b' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/complex_maps.erl:74:34 - │ -74 │ get_default_neg2(#{def := V}) -> V. - │ ^ V. -Expression has type: number() -Context expected type: 'b' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/complex_maps.erl:77:41 - │ -77 │ match_required_1_neg(#{b := _V} = M) -> M. - │ ^ M. -Expression has type: #{a := number(), b := dynamic(), atom() => dynamic()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/complex_maps.erl:80:28 - │ -80 │ compat_default_1_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{atom() => binary()} -Context expected type: #{a => binary(), 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 #{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 - │ -83 │ compat_default_2_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a := 'b', atom() => binary()} -Context expected type: #{a => 'b', {c, d} => atom() | binary(), term() => atom()} - │ - -Because in the expression's type: - #{ atom() => - Here the type is: binary() - 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 - │ -86 │ compat_default_3_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a := 'b', atom() => binary()} -Context expected type: #{a => 'b', {c, d} => atom() | binary(), atom() => atom()} - │ - -Because in the expression's type: - #{ atom() => - Here the type is: binary() - 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 - │ -89 │ dyn_domain_coerce_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{dynamic() => atom()} -Context expected type: #{dynamic() => binary()} - │ - -Because in the expression's type: - #{ dynamic() => - Here the type is: atom() - 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/complex_maps-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps-OTP-28.pretty deleted file mode 100644 index 3143803509..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps-OTP-28.pretty +++ /dev/null @@ -1,300 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/complex_maps.erl:11:21 - │ -11 │ downcast_neg1(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', c => 'd'} -Context expected type: #{a => 'b'} - │ - -Because in the expression's type: - Here the type is: #{c => ...} - 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 - │ -17 │ downcast_neg2(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', c => 'd'} -Context expected type: #{a => 'b', atom() => number()} - │ - -Because in the expression's type: - #{ c => - Here the type is: 'd' - 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 - │ -20 │ upcast_neg1(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', atom() => atom()} -Context expected type: #{a => 'b', c => 'd'} - │ - -Because in the expression's type: - Here the type is: #{atom() => atom()} - 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 - │ -23 │ upcast_neg2(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', atom() => number()} -Context expected type: #{a => 'b', c => 'd', atom() => number()} - │ - -Because in the expression's type: - #{ atom() => - Here the type is: number() - Context expects type: 'd' - , ... } - 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 - │ -38 │ downcast_neg3(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', atom() => atom()} -Context expected type: #{a => 'b'} - │ - -Because in the expression's type: - Here the type is: #{atom() => atom()} - 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 - │ -44 │ downcast_dyn_neg_1(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', dynamic(atom()) => atom()} -Context expected type: #{a => 'b'} - │ - -Because in the expression's type: - Here the type is: #{dynamic(atom()) => atom()} - 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 - │ -47 │ downcast_dyn_neg_2(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'b', atom() => dynamic(atom())} -Context expected type: #{a => 'b'} - │ - -Because in the expression's type: - Here the type is: #{atom() => dynamic(atom())} - 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 - │ -56 │ tuple_key_get_neg(#{{ok, {a, b}} := V}) -> V. - │ ^ V. -Expression has type: 'v' -Context expected type: 'err' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/complex_maps.erl:62:30 - │ -62 │ tuple_key_maps_get_neg(M) -> maps:get({ok, {a, b}}, M). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ maps:get({'ok', {'a', 'b'}}, M). -Expression has type: 'v' -Context expected type: 'err' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/complex_maps.erl:71:32 - │ -71 │ get_default_neg1(#{a := V}) -> V. - │ ^ V. -Expression has type: 'b' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/complex_maps.erl:74:34 - │ -74 │ get_default_neg2(#{def := V}) -> V. - │ ^ V. -Expression has type: number() -Context expected type: 'b' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/complex_maps.erl:77:41 - │ -77 │ match_required_1_neg(#{b := _V} = M) -> M. - │ ^ M. -Expression has type: #{a := number(), b := dynamic(), atom() => dynamic()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/complex_maps.erl:80:28 - │ -80 │ compat_default_1_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{atom() => binary()} -Context expected type: #{a => binary(), 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 #{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 - │ -83 │ compat_default_2_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a := 'b', atom() => binary()} -Context expected type: #{a => 'b', {c, d} => atom() | binary(), term() => atom()} - │ - -Because in the expression's type: - #{ atom() => - Here the type is: binary() - 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 - │ -86 │ compat_default_3_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{a := 'b', atom() => binary()} -Context expected type: #{a => 'b', {c, d} => atom() | binary(), atom() => atom()} - │ - -Because in the expression's type: - #{ atom() => - Here the type is: binary() - 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 - │ -89 │ dyn_domain_coerce_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #{dynamic() => atom()} -Context expected type: #{dynamic() => binary()} - │ - -Because in the expression's type: - #{ dynamic() => - Here the type is: atom() - 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/complex_maps-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps.pretty similarity index 70% rename from crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps.pretty index 3143803509..aae5348c54 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/complex_maps.pretty @@ -14,10 +14,6 @@ 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 │ @@ -35,15 +31,6 @@ 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 │ @@ -60,13 +47,6 @@ 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 │ @@ -85,13 +65,6 @@ 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 │ @@ -108,13 +81,6 @@ 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 │ @@ -131,13 +97,6 @@ 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 │ @@ -154,13 +113,6 @@ 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 │ @@ -218,13 +170,6 @@ 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 │ @@ -242,13 +187,6 @@ 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 │ @@ -266,13 +204,6 @@ 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 │ @@ -290,11 +221,4 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions-OTP-26.pretty deleted file mode 100644 index 396ce7fc52..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions-OTP-26.pretty +++ /dev/null @@ -1,382 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:28:5 - │ -28 │ [N || {_, N} <- L]. - │ ^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -40 │ [X || X <- L]. - │ ^ L. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:48:5 - │ -48 │ << Y || <> <= B >>. - │ ^^^^^^^^^^^^^^^^^^^^^ << || >>. -Expression has type: binary() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:48:8 - │ -48 │ << Y || <> <= B >>. - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:56:18 - │ -56 │ << Y || Y <- B >>. - │ ^ B. -Expression has type: binary() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:60:8 - │ -60 │ << Y || <> <= LB >>. - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:60:22 - │ -60 │ << Y || <> <= LB >>. - │ ^^ LB. -Expression has type: [binary()] -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:68:5 - │ -68 │ [ Y || <> <= LB ]. - │ ^^^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: [number()] -Context expected type: [binary()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -72 │ << Y || <> <= LB >>. - │ ^^^^^^^^^^^^^^^^^^^^^^ << || >>. -Expression has type: binary() -Context expected type: [binary()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:72:8 - │ -72 │ << Y || <> <= LB >>. - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:76:8 - │ -76 │ << Y || <> <= LB >>. - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:90:22 - │ -90 │ Res = [X || X <- L], - │ ^ L. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:100:22 - │ -100 │ Res = [X || X <- L, X], - │ ^ L. -Expression has type: boolean() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:116:14 - │ -116 │ Res = << Y || <> <= LB >>, - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:116:28 - │ -116 │ Res = << Y || <> <= LB >>, - │ ^^ LB. -Expression has type: [binary()] -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:121:24 - │ -121 │ Res = << Y || Y <- B >>, - │ ^ B. -Expression has type: binary() -Context expected type: [term()] - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/comprehensions.erl:147:1 - │ -147 │ test26(X) -> [Y || Y <- X]. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/comprehensions.erl:150:1 - │ -150 │ ╭ test27(X) -> -151 │ │ Res = [Y || Y <- X], -152 │ │ Res. - │ ╰───────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/comprehensions.erl:155:1 - │ -155 │ ╭ test28(X) -> -156 │ │ << Y || -157 │ │ <> <= X >>. - │ ╰─────────────────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:156:5 - │ -156 │ ╭ << Y || -157 │ │ <> <= X >>. - │ ╰─────────────────────^ << || >>. -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:156:8 - │ -156 │ << Y || - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/comprehensions.erl:160:1 - │ -160 │ ╭ test29(X) -> -161 │ │ Res = << Y || -162 │ │ <> <= X >>, -163 │ │ Res. - │ ╰───────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:161:14 - │ -161 │ Res = << Y || - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:163:5 - │ -163 │ Res. - │ ^^^ Res. -Expression has type: binary() -Context expected type: number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/comprehensions.erl:166:1 - │ -166 │ ╭ test30(X) -> -167 │ │ << Y || -168 │ │ <> <= X >>. - │ ╰─────────────────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:167:8 - │ -167 │ << Y || - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/comprehensions.erl:171:1 - │ -171 │ ╭ test31(X) -> -172 │ │ Res = << Y || -173 │ │ <> <= X >>, -174 │ │ Res. - │ ╰───────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:172:14 - │ -172 │ Res = << Y || - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:184:5 - │ -184 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: [atom()] -Context expected type: [binary()] - │ - -Because in the expression's type: - [ - Here the type is: atom() - 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 - │ -226 │ [X || X <- L, X]. - │ ^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: ['true'] -Context expected type: ['false'] - │ - -Because in the expression's type: - [ - Here the type is: 'true' - 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 - │ -231 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: ['true'] -Context expected type: ['false'] - │ - -Because in the expression's type: - [ - Here the type is: 'true' - 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 - │ -239 │ [Y || <> <= B, is_integer(Y) ]. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -267 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: [binary() | 'undefined'] -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: 'undefined' - 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 - │ -386 │ F() || F <- Fs, - │ ^ F. -Expected fun type with arity 0 -Got: fun(() -> atom()) | fun((number()) -> atom()) - -34 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions-OTP-28.pretty deleted file mode 100644 index 396ce7fc52..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions-OTP-28.pretty +++ /dev/null @@ -1,382 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:28:5 - │ -28 │ [N || {_, N} <- L]. - │ ^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -40 │ [X || X <- L]. - │ ^ L. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:48:5 - │ -48 │ << Y || <> <= B >>. - │ ^^^^^^^^^^^^^^^^^^^^^ << || >>. -Expression has type: binary() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:48:8 - │ -48 │ << Y || <> <= B >>. - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:56:18 - │ -56 │ << Y || Y <- B >>. - │ ^ B. -Expression has type: binary() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:60:8 - │ -60 │ << Y || <> <= LB >>. - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:60:22 - │ -60 │ << Y || <> <= LB >>. - │ ^^ LB. -Expression has type: [binary()] -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:68:5 - │ -68 │ [ Y || <> <= LB ]. - │ ^^^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: [number()] -Context expected type: [binary()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -72 │ << Y || <> <= LB >>. - │ ^^^^^^^^^^^^^^^^^^^^^^ << || >>. -Expression has type: binary() -Context expected type: [binary()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:72:8 - │ -72 │ << Y || <> <= LB >>. - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:76:8 - │ -76 │ << Y || <> <= LB >>. - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:90:22 - │ -90 │ Res = [X || X <- L], - │ ^ L. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:100:22 - │ -100 │ Res = [X || X <- L, X], - │ ^ L. -Expression has type: boolean() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:116:14 - │ -116 │ Res = << Y || <> <= LB >>, - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:116:28 - │ -116 │ Res = << Y || <> <= LB >>, - │ ^^ LB. -Expression has type: [binary()] -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:121:24 - │ -121 │ Res = << Y || Y <- B >>, - │ ^ B. -Expression has type: binary() -Context expected type: [term()] - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/comprehensions.erl:147:1 - │ -147 │ test26(X) -> [Y || Y <- X]. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/comprehensions.erl:150:1 - │ -150 │ ╭ test27(X) -> -151 │ │ Res = [Y || Y <- X], -152 │ │ Res. - │ ╰───────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/comprehensions.erl:155:1 - │ -155 │ ╭ test28(X) -> -156 │ │ << Y || -157 │ │ <> <= X >>. - │ ╰─────────────────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:156:5 - │ -156 │ ╭ << Y || -157 │ │ <> <= X >>. - │ ╰─────────────────────^ << || >>. -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:156:8 - │ -156 │ << Y || - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/comprehensions.erl:160:1 - │ -160 │ ╭ test29(X) -> -161 │ │ Res = << Y || -162 │ │ <> <= X >>, -163 │ │ Res. - │ ╰───────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:161:14 - │ -161 │ Res = << Y || - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:163:5 - │ -163 │ Res. - │ ^^^ Res. -Expression has type: binary() -Context expected type: number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/comprehensions.erl:166:1 - │ -166 │ ╭ test30(X) -> -167 │ │ << Y || -168 │ │ <> <= X >>. - │ ╰─────────────────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:167:8 - │ -167 │ << Y || - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/comprehensions.erl:171:1 - │ -171 │ ╭ test31(X) -> -172 │ │ Res = << Y || -173 │ │ <> <= X >>, -174 │ │ Res. - │ ╰───────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:172:14 - │ -172 │ Res = << Y || - │ ^ Y. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/comprehensions.erl:184:5 - │ -184 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: [atom()] -Context expected type: [binary()] - │ - -Because in the expression's type: - [ - Here the type is: atom() - 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 - │ -226 │ [X || X <- L, X]. - │ ^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: ['true'] -Context expected type: ['false'] - │ - -Because in the expression's type: - [ - Here the type is: 'true' - 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 - │ -231 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: ['true'] -Context expected type: ['false'] - │ - -Because in the expression's type: - [ - Here the type is: 'true' - 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 - │ -239 │ [Y || <> <= B, is_integer(Y) ]. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -267 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: [binary() | 'undefined'] -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: 'undefined' - 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 - │ -386 │ F() || F <- Fs, - │ ^ F. -Expected fun type with arity 0 -Got: fun(() -> atom()) | fun((number()) -> atom()) - -34 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions.pretty similarity index 88% rename from crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions.pretty index 396ce7fc52..2b387ca9b9 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/comprehensions.pretty @@ -15,12 +15,6 @@ 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 │ @@ -86,12 +80,6 @@ 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 │ @@ -270,12 +258,6 @@ 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 │ @@ -293,12 +275,6 @@ 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 │ @@ -316,12 +292,6 @@ 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 │ @@ -339,12 +309,6 @@ 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 │ @@ -363,14 +327,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/contravariant-OTP-26.pretty deleted file mode 100644 index 69c58c0e77..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/contravariant-OTP-26.pretty +++ /dev/null @@ -1,29 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/contravariant.erl:54:33 - │ -54 │ contravariant_subtype_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: ref_contravariant('a') -Context expected type: ref_contravariant_ab() - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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/contravariant-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/contravariant-OTP-28.pretty deleted file mode 100644 index 69c58c0e77..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/contravariant-OTP-28.pretty +++ /dev/null @@ -1,29 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/contravariant.erl:54:33 - │ -54 │ contravariant_subtype_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: ref_contravariant('a') -Context expected type: ref_contravariant_ab() - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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/contravariant-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/contravariant.pretty similarity index 62% rename from crates/elp/src/resources/test/eqwalizer_tests/check/contravariant-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/contravariant.pretty index 69c58c0e77..f228f5cd50 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/contravariant-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/contravariant.pretty @@ -16,14 +16,4 @@ 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-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-27.pretty deleted file mode 100644 index 92e20b1f1a..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-27.pretty +++ /dev/null @@ -1,3242 +0,0 @@ -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()} - │ - - #{'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: boolean() | {'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 boolean() - -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()} - │ - - 'wrong_ret' is not compatible with boolean() | {'true', term()} - because - 'wrong_ret' is not compatible with boolean() - -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: boolean() | {'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 boolean() - -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: boolean() | ['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 boolean() - -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'] - │ - - 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] - because - 'wrong_ret' is not compatible with boolean() - -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: boolean() | [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] - because - {'true', 'a'} is not compatible with boolean() - -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()] - │ - - {'true', 'a'} is not compatible with boolean() | [dynamic()] - because - {'true', 'a'} is not compatible with boolean() - -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: boolean() | ['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'] - because - {'true', 'a'} is not compatible with boolean() - -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'] - │ - - {'true', 'a'} is not compatible with boolean() | ['a' | 'b'] - because - {'true', 'a'} is not compatible with boolean() - -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: boolean() | ['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 boolean() - -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: boolean() | ['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 boolean() - -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: boolean() | [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 boolean() - -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: boolean() | ['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 boolean() - -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()} - │ - - 'err' is not compatible with boolean() | {'true', term()} - because - 'err' is not compatible with boolean() - -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: iodata() - ------------------------------- Detailed message ------------------------------ - - atom() is not compatible with iodata() | unicode:charlist() - because - atom() is not compatible with iodata() - -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() | none()]} -Context expected type: {[atom()], [number()]} - │ - -Because in the expression's type: - { - [ - Here the type is: number() - Context expects type: atom() - ] - , [atom() | none()]} - ------------------------------- Detailed message ------------------------------ - - at tuple index 1: - {[number()], [atom() | none()]} 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() | none()}]} -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() | none()}]} - ------------------------------- Detailed message ------------------------------ - - at tuple index 1: - {[{term(), number()}], [{term(), atom() | none()}]} 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() - │ - -Because in the expression's type: - Here the type is: atom() - Context expects 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() - │ - -Because in the expression's type: - Here the type is: binary() - Context expects 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() - │ - -Because in the expression's type: - Here the type is: number() - Context expects 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 deleted file mode 100644 index 6eb40f681a..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-28.pretty +++ /dev/null @@ -1,3242 +0,0 @@ -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()} - │ - - #{'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: boolean() | {'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 boolean() - -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()} - │ - - 'wrong_ret' is not compatible with boolean() | {'true', term()} - because - 'wrong_ret' is not compatible with boolean() - -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: boolean() | {'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 boolean() - -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: boolean() | ['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 boolean() - -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'] - │ - - 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] - because - 'wrong_ret' is not compatible with boolean() - -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: boolean() | [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] - because - {'true', 'a'} is not compatible with boolean() - -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()] - │ - - {'true', 'a'} is not compatible with boolean() | [dynamic()] - because - {'true', 'a'} is not compatible with boolean() - -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: boolean() | ['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'] - because - {'true', 'a'} is not compatible with boolean() - -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'] - │ - - {'true', 'a'} is not compatible with boolean() | ['a' | 'b'] - because - {'true', 'a'} is not compatible with boolean() - -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: boolean() | ['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 boolean() - -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: boolean() | ['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 boolean() - -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: boolean() | [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 boolean() - -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: boolean() | ['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 boolean() - -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()} - │ - - 'err' is not compatible with boolean() | {'true', term()} - because - 'err' is not compatible with boolean() - -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: iodata() - ------------------------------- Detailed message ------------------------------ - - atom() is not compatible with iodata() | unicode:charlist() - because - atom() is not compatible with iodata() - -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() | none()]} -Context expected type: {[atom()], [number()]} - │ - -Because in the expression's type: - { - [ - Here the type is: number() - Context expects type: atom() - ] - , [atom() | none()]} - ------------------------------- Detailed message ------------------------------ - - at tuple index 1: - {[number()], [atom() | none()]} 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() | none()}]} -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() | none()}]} - ------------------------------- Detailed message ------------------------------ - - at tuple index 1: - {[{term(), number()}], [{term(), atom() | none()}]} 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() - │ - -Because in the expression's type: - Here the type is: atom() - Context expects 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() - │ - -Because in the expression's type: - Here the type is: binary() - Context expects 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() - │ - -Because in the expression's type: - Here the type is: number() - Context expects type: binary() - -202 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/custom.pretty similarity index 75% rename from crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/custom.pretty index 92e20b1f1a..efc8c47aa0 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-26.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/custom.pretty @@ -37,12 +37,6 @@ 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 │ @@ -74,12 +68,6 @@ 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 │ @@ -96,12 +84,6 @@ 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 │ @@ -118,12 +100,6 @@ 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 │ @@ -202,12 +178,6 @@ 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 │ @@ -224,12 +194,6 @@ 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 │ @@ -249,15 +213,6 @@ 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 │ @@ -274,14 +229,6 @@ 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 │ @@ -298,14 +245,6 @@ 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 │ @@ -362,28 +301,13 @@ 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 @@ -403,13 +327,6 @@ 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 │ @@ -451,29 +368,13 @@ 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 @@ -502,14 +403,6 @@ 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 │ @@ -531,14 +424,6 @@ 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 │ @@ -555,16 +440,9 @@ 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 @@ -606,12 +484,6 @@ 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 │ @@ -682,30 +554,13 @@ 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 @@ -723,13 +578,6 @@ 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 │ @@ -746,13 +594,6 @@ 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 │ @@ -769,10 +610,6 @@ 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 │ @@ -792,10 +629,10 @@ Expression has type: #{'a' | 'b' => atom() | number()} Context expected type: #{a := atom(), b := number()} | #{a := atom()} │ - #{'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 +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. error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:721:9 @@ -811,18 +648,10 @@ Context expected type: fun((number()) -> boolean() | {'true', term()}) Because in the expression's type: fun((binary()) -> Here the type is: [number()] - Context expects type: boolean() | {'true', term()} + 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 boolean() - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:739:20 │ @@ -834,9 +663,10 @@ Expression has type: 'wrong_ret' Context expected type: boolean() | {'true', term()} │ - 'wrong_ret' is not compatible with boolean() | {'true', term()} - because - 'wrong_ret' is not compatible with boolean() +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. error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:749:9 @@ -860,15 +690,7 @@ 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: boolean() | {'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 boolean() + Differs from the expected type: 'false' | 'true' | {'true', term()} error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:827:9 @@ -885,19 +707,9 @@ 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: boolean() | ['a' | 'b'] + 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 boolean() - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:829:20 │ @@ -909,9 +721,10 @@ Expression has type: 'wrong_ret' Context expected type: boolean() | ['a' | 'b'] │ - 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] - because - 'wrong_ret' is not compatible with boolean() +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. error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:837:9 @@ -927,19 +740,9 @@ 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: boolean() | [Item] + 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] - because - {'true', 'a'} is not compatible with boolean() - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:837:20 │ @@ -951,9 +754,10 @@ Expression has type: {'true', 'a'} Context expected type: boolean() | [dynamic()] │ - {'true', 'a'} is not compatible with boolean() | [dynamic()] - because - {'true', 'a'} is not compatible with boolean() +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. error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:839:9 @@ -970,12 +774,6 @@ 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 │ @@ -991,12 +789,6 @@ 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 │ @@ -1025,19 +817,9 @@ 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: boolean() | ['a' | 'b'] + 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'] - because - {'true', 'a'} is not compatible with boolean() - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:857:20 │ @@ -1049,9 +831,10 @@ Expression has type: {'true', 'a'} Context expected type: boolean() | ['a' | 'b'] │ - {'true', 'a'} is not compatible with boolean() | ['a' | 'b'] - because - {'true', 'a'} is not compatible with boolean() +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. error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:873:9 @@ -1072,19 +855,9 @@ 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: boolean() | ['a' | 'b'] + 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 boolean() - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:881:17 │ @@ -1099,15 +872,7 @@ 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: boolean() | ['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 boolean() + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:891:9 @@ -1123,18 +888,10 @@ Context expected type: fun((dynamic()) -> boolean() | [dynamic()]) Because in the expression's type: fun((string()) -> Here the type is: atom() - Context expects type: boolean() | [dynamic()] + 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 boolean() - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:891:9 │ @@ -1149,18 +906,10 @@ 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: boolean() | ['a' | 'b'] + 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 boolean() - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:900:9 │ @@ -1178,12 +927,6 @@ 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 │ @@ -1201,12 +944,6 @@ 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 │ @@ -1224,12 +961,6 @@ 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 │ @@ -1247,12 +978,6 @@ 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 │ @@ -1270,12 +995,6 @@ 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 │ @@ -1293,12 +1012,6 @@ 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 │ @@ -1327,12 +1040,6 @@ 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 │ @@ -1350,12 +1057,6 @@ 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 │ @@ -1405,12 +1106,6 @@ 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 │ @@ -1511,14 +1206,6 @@ 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 │ @@ -1563,31 +1250,17 @@ 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 @@ -1601,31 +1274,17 @@ 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 @@ -1693,14 +1352,6 @@ 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 │ @@ -1719,14 +1370,6 @@ 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 │ @@ -1744,12 +1387,6 @@ 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 │ @@ -1817,12 +1454,6 @@ 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 │ @@ -1841,14 +1472,6 @@ 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 │ @@ -1874,41 +1497,21 @@ 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 @@ -1958,12 +1561,6 @@ 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 │ @@ -2036,17 +1633,6 @@ 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 │ @@ -2091,46 +1677,25 @@ 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 @@ -2165,12 +1730,6 @@ 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 │ @@ -2193,14 +1752,6 @@ 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 │ @@ -2344,17 +1895,6 @@ 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 │ @@ -2375,10 +1915,6 @@ 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 │ @@ -2422,10 +1958,6 @@ 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 │ @@ -2443,10 +1975,6 @@ 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 │ @@ -2472,10 +2000,6 @@ 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 │ @@ -2496,16 +2020,9 @@ 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 @@ -2525,15 +2042,6 @@ 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 │ @@ -2549,14 +2057,6 @@ 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 │ @@ -2572,14 +2072,6 @@ 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 │ @@ -2595,14 +2087,6 @@ 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 │ @@ -2619,14 +2103,6 @@ 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 │ @@ -2645,16 +2121,6 @@ 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 │ @@ -2670,14 +2136,6 @@ 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 │ @@ -2693,14 +2151,6 @@ 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 │ @@ -2716,14 +2166,6 @@ 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 │ @@ -2740,14 +2182,6 @@ 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 │ @@ -2764,14 +2198,6 @@ 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 │ @@ -2793,17 +2219,6 @@ 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 │ @@ -2822,15 +2237,6 @@ 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 │ @@ -2855,10 +2261,6 @@ 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 │ @@ -2879,10 +2281,6 @@ 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 │ @@ -2903,13 +2301,6 @@ 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 │ @@ -2921,9 +2312,10 @@ Expression has type: 'err' Context expected type: boolean() | {'true', term()} │ - 'err' is not compatible with boolean() | {'true', term()} - because - 'err' is not compatible with boolean() +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. error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2362:5 @@ -2943,13 +2335,6 @@ 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 │ @@ -2987,13 +2372,8 @@ Context expected type: iodata() | unicode:charlist() Because in the expression's type: Here the type is: atom() - Context expects type: iodata() - ------------------------------- Detailed message ------------------------------ - - atom() is not compatible with iodata() | unicode:charlist() - because - atom() is not compatible with iodata() + Context expects type: iolist() | binary() + No candidate matches in the expected union. error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2386:5 @@ -3023,17 +2403,6 @@ 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 │ @@ -3041,7 +2410,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ │ │ │ lists:partition(fun, L). -Expression has type: {[number()], [atom() | none()]} +Expression has type: {[number()], [atom()]} Context expected type: {[atom()], [number()]} │ @@ -3051,16 +2420,7 @@ Because in the expression's type: Here the type is: number() Context expects type: atom() ] - , [atom() | none()]} - ------------------------------- Detailed message ------------------------------ - - at tuple index 1: - {[number()], [atom() | none()]} is not compatible with {[atom()], [number()]} - because - [number()] is not compatible with [atom()] - because - number() is not compatible with atom() + , [atom()]} error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2518:5 @@ -3069,7 +2429,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ │ │ │ lists:partition(fun, L). -Expression has type: {[{term(), number()}], [{term(), atom() | none()}]} +Expression has type: {[{term(), number()}], [{term(), atom()}]} Context expected type: {[{term(), atom()}], [{term(), number()}]} │ @@ -3081,19 +2441,7 @@ Because in the expression's type: Context expects type: atom() } ] - , [{term(), atom() | none()}]} - ------------------------------- Detailed message ------------------------------ - - at tuple index 1: - {[{term(), number()}], [{term(), atom() | none()}]} 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() + , [{term(), atom()}]} error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/custom.erl:2536:5 @@ -3116,18 +2464,6 @@ 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 │ @@ -3144,10 +2480,6 @@ 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 │ @@ -3165,15 +2497,6 @@ 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 │ @@ -3190,53 +2513,28 @@ 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 │ 2709 │ (foo, A) -> binary_to_atom(A); - │ ^ - │ │ - │ A. + │ ^ A. Expression has type: atom() Context expected type: binary() - │ - -Because in the expression's type: - Here the type is: atom() - Context expects 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. + │ ^ B. Expression has type: binary() Context expected type: atom() - │ - -Because in the expression's type: - Here the type is: binary() - Context expects 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. + │ ^ I. Expression has type: number() Context expected type: binary() - │ - -Because in the expression's type: - Here the type is: number() - Context expects type: binary() 202 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks7_overload_pos-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs1.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/callbacks7_overload_pos-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs1.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks7_overload_pos-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs2.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/callbacks7_overload_pos-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs2.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_calls-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_calls-OTP-27.pretty deleted file mode 100644 index 4871b7bbeb..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_calls-OTP-27.pretty +++ /dev/null @@ -1,8 +0,0 @@ -error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) - ┌─ check/src/dyn_calls.erl:49:3 - │ -49 │ (fun() -> res end)(arg), - │ ^^^^^^^^^^^^^^^^^^ fun. -fun with arity 0 used as fun with 1 arguments - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_calls-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_calls-OTP-28.pretty deleted file mode 100644 index 4871b7bbeb..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_calls-OTP-28.pretty +++ /dev/null @@ -1,8 +0,0 @@ -error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) - ┌─ check/src/dyn_calls.erl:49:3 - │ -49 │ (fun() -> res end)(arg), - │ ^^^^^^^^^^^^^^^^^^ fun. -fun with arity 0 used as fun with 1 arguments - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_calls-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_calls.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dyn_calls-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/dyn_calls.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_remote_funs-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_remote_funs-OTP-27.pretty deleted file mode 100644 index 9c82c19829..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_remote_funs-OTP-27.pretty +++ /dev/null @@ -1,41 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dyn_remote_funs.erl:69:12 - │ -69 │ -> Res; - │ ^^^ Res. -Expression has type: fun((term(), term()) -> term()) -Context expected type: fun((none()) -> term()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dyn_remote_funs.erl:80:5 - │ -80 │ fun M:F/2. - │ ^^^^^^^^^ M:F/2. -Expression has type: fun((dynamic(), dynamic()) -> dynamic()) -Context expected type: 'a' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dyn_remote_funs.erl:85:9 - │ -85 │ fun M:F/A. - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dyn_remote_funs.erl:90:1 - │ -90 │ fun M:F/A. - │ ^^^^^^^^^ M:F/A. -Expression has type: fun() -Context expected type: 'a' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dyn_remote_funs.erl:90:9 - │ -90 │ fun M:F/A. - │ ^ A. -Expression has type: atom() -Context expected type: number() - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_remote_funs-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_remote_funs-OTP-28.pretty deleted file mode 100644 index 9c82c19829..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_remote_funs-OTP-28.pretty +++ /dev/null @@ -1,41 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dyn_remote_funs.erl:69:12 - │ -69 │ -> Res; - │ ^^^ Res. -Expression has type: fun((term(), term()) -> term()) -Context expected type: fun((none()) -> term()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dyn_remote_funs.erl:80:5 - │ -80 │ fun M:F/2. - │ ^^^^^^^^^ M:F/2. -Expression has type: fun((dynamic(), dynamic()) -> dynamic()) -Context expected type: 'a' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dyn_remote_funs.erl:85:9 - │ -85 │ fun M:F/A. - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dyn_remote_funs.erl:90:1 - │ -90 │ fun M:F/A. - │ ^^^^^^^^^ M:F/A. -Expression has type: fun() -Context expected type: 'a' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dyn_remote_funs.erl:90:9 - │ -90 │ fun M:F/A. - │ ^ A. -Expression has type: atom() -Context expected type: number() - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_remote_funs-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dyn_remote_funs.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dyn_remote_funs-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/dyn_remote_funs.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks7_overload_pos-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_1.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/callbacks7_overload_pos-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_1.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/compiler_macro-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_2.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/compiler_macro-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_2.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls-OTP-26.pretty deleted file mode 100644 index a8dc692a9b..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls-OTP-26.pretty +++ /dev/null @@ -1,217 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:22:5 - │ -22 │ F(X). - │ ^^^^ F(X). -Expression has type: 'b' -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:38:5 - │ -38 │ (Rec#rec.method)(atom). - │ ^^^^^^^^^^^^^^^^^^^^^^ (...#rec.method)('atom'). -Expression has type: pid() -Context expected type: number() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/dynamic_calls.erl:47:19 - │ -47 │ test_06_neg(F) -> F(1, 2). - │ ^ F. -Expected fun type with arity 2 -Got: fun(('a') -> 'b') - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:57:5 - │ -57 │ F(). - │ ^^^ F(). -Expression has type: 'ok' -Context expected type: pid() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/dynamic_calls.erl:62:5 - │ -62 │ F(1). - │ ^ F. -Expected fun type with arity 1 -Got: fun(() -> 'ok') - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/dynamic_calls.erl:71:5 - │ -71 │ (fun ret_ok/0)(1, 2). - │ ^^^^^^^^^^^^^^ ret_ok/0. -Expected fun type with arity 2 -Got: fun(() -> 'ok') - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:78:5 - │ -78 │ (FUnion)(false). - │ ^^^^^^^^^^^^^^^ FUnion('false'). -Expression has type: 'r1' | 'r2' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:78:5 - │ -78 │ (FUnion)(false). - │ ^^^^^^^^^^^^^^^ FUnion('false'). -Expression has type: 'r2' | 'r3' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:78:14 - │ -78 │ (FUnion)(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'. -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'. -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'. -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 - │ -87 │ Res. - │ ^^^ Res. -Expression has type: 'r1' | 'r2' | 'r3' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:94:5 - │ -94 │ (FUnion)(a2). - │ ^^^^^^^^^^^^ - │ │ - │ FUnion('a2'). -Expression has type: 'r1' | 'r2' -Context expected type: 'r1' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'r1' - 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 - │ -94 │ (FUnion)(a2). - │ ^^^^^^^^^^^^ FUnion('a2'). -Expression has type: 'r2' | 'r3' -Context expected type: 'r1' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:102:5 - │ -102 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: 'r1' | 'r2' | 'r3' -Context expected type: 'r1' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'r1' - 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 - │ -108 │ (F)(a). - │ ^^^ F. -Expected fun type with arity 1 -Got: fun(('a') -> 'b') | 'z' - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/dynamic_calls.erl:114:11 - │ -114 │ Res = (F)(a), - │ ^^^ F. -Expected fun type with arity 1 -Got: fun(('a') -> 'b') | 'z' - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/dynamic_calls.erl:138:5 - │ -138 │ (F)(a). - │ ^^^ F. -Expected fun type with arity 1 -Got: fun(('a') -> 'b') | fun(() -> 'b') - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/dynamic_calls.erl:144:11 - │ -144 │ Res = (F)(a), - │ ^^^ F. -Expected fun type with arity 1 -Got: fun(('a') -> 'b') | fun(() -> 'b') - -20 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls-OTP-28.pretty deleted file mode 100644 index a8dc692a9b..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls-OTP-28.pretty +++ /dev/null @@ -1,217 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:22:5 - │ -22 │ F(X). - │ ^^^^ F(X). -Expression has type: 'b' -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:38:5 - │ -38 │ (Rec#rec.method)(atom). - │ ^^^^^^^^^^^^^^^^^^^^^^ (...#rec.method)('atom'). -Expression has type: pid() -Context expected type: number() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/dynamic_calls.erl:47:19 - │ -47 │ test_06_neg(F) -> F(1, 2). - │ ^ F. -Expected fun type with arity 2 -Got: fun(('a') -> 'b') - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:57:5 - │ -57 │ F(). - │ ^^^ F(). -Expression has type: 'ok' -Context expected type: pid() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/dynamic_calls.erl:62:5 - │ -62 │ F(1). - │ ^ F. -Expected fun type with arity 1 -Got: fun(() -> 'ok') - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/dynamic_calls.erl:71:5 - │ -71 │ (fun ret_ok/0)(1, 2). - │ ^^^^^^^^^^^^^^ ret_ok/0. -Expected fun type with arity 2 -Got: fun(() -> 'ok') - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:78:5 - │ -78 │ (FUnion)(false). - │ ^^^^^^^^^^^^^^^ FUnion('false'). -Expression has type: 'r1' | 'r2' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:78:5 - │ -78 │ (FUnion)(false). - │ ^^^^^^^^^^^^^^^ FUnion('false'). -Expression has type: 'r2' | 'r3' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:78:14 - │ -78 │ (FUnion)(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'. -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'. -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'. -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 - │ -87 │ Res. - │ ^^^ Res. -Expression has type: 'r1' | 'r2' | 'r3' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:94:5 - │ -94 │ (FUnion)(a2). - │ ^^^^^^^^^^^^ - │ │ - │ FUnion('a2'). -Expression has type: 'r1' | 'r2' -Context expected type: 'r1' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'r1' - 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 - │ -94 │ (FUnion)(a2). - │ ^^^^^^^^^^^^ FUnion('a2'). -Expression has type: 'r2' | 'r3' -Context expected type: 'r1' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_calls.erl:102:5 - │ -102 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: 'r1' | 'r2' | 'r3' -Context expected type: 'r1' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'r1' - 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 - │ -108 │ (F)(a). - │ ^^^ F. -Expected fun type with arity 1 -Got: fun(('a') -> 'b') | 'z' - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/dynamic_calls.erl:114:11 - │ -114 │ Res = (F)(a), - │ ^^^ F. -Expected fun type with arity 1 -Got: fun(('a') -> 'b') | 'z' - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/dynamic_calls.erl:138:5 - │ -138 │ (F)(a). - │ ^^^ F. -Expected fun type with arity 1 -Got: fun(('a') -> 'b') | fun(() -> 'b') - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/dynamic_calls.erl:144:11 - │ -144 │ Res = (F)(a), - │ ^^^ F. -Expected fun type with arity 1 -Got: fun(('a') -> 'b') | fun(() -> 'b') - -20 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls.pretty similarity index 82% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls.pretty index a8dc692a9b..bc6265b8c1 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_calls.pretty @@ -66,61 +66,33 @@ 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 @@ -146,12 +118,6 @@ 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 │ @@ -176,12 +142,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_catch-OTP-26.pretty deleted file mode 100644 index a8135429d1..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_catch-OTP-26.pretty +++ /dev/null @@ -1,23 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_catch.erl:22:16 - │ -22 │ {ok, A} -> A; - │ ^ - │ │ - │ A. -Expression has type: atom() | dynamic() -Context expected type: binary() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dynamic() - 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_catch-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_catch-OTP-28.pretty deleted file mode 100644 index a8135429d1..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_catch-OTP-28.pretty +++ /dev/null @@ -1,23 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_catch.erl:22:16 - │ -22 │ {ok, A} -> A; - │ ^ - │ │ - │ A. -Expression has type: atom() | dynamic() -Context expected type: binary() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dynamic() - 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_catch-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_catch.pretty similarity index 74% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_catch-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_catch.pretty index a8135429d1..78fd9f16f2 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_catch-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_catch.pretty @@ -14,10 +14,4 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun-OTP-26.pretty deleted file mode 100644 index 1f55b0f88a..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun-OTP-26.pretty +++ /dev/null @@ -1,181 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:65:3 - │ -65 │ fun M:id/1. - │ ^^^^^^^^^^ M:'id'/1. -Expression has type: fun((dynamic()) -> dynamic()) -Context expected type: fun(() -> pid()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:71:3 - │ -71 │ Res. - │ ^^^ Res. -Expression has type: fun((dynamic()) -> dynamic()) -Context expected type: fun(() -> pid()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:87:3 - │ -87 │ fun M:F/2. - │ ^^^^^^^^^ M:F/2. -Expression has type: fun((dynamic(), dynamic()) -> dynamic()) -Context expected type: fun((pid()) -> pid()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:93:3 - │ -93 │ Res. - │ ^^^ Res. -Expression has type: fun((dynamic(), dynamic()) -> dynamic()) -Context expected type: fun((pid()) -> pid()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:98:7 - │ -98 │ fun M:F/1. - │ ^ M. -Expression has type: {atom()} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:103:9 - │ -103 │ fun M:F/1. - │ ^ F. -Expression has type: {atom()} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:109:11 - │ -109 │ fun M:F/A. - │ ^ A. -Expression has type: pid() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:146:24 - │ -146 │ f5_to_f4_cov_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: f5('a' | 'b') -Context expected type: f4('a') - │ - -Because in the expression's type: - fun((term()) -> - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -155 │ apply_f4_neg(F) -> F(a). - │ ^^^^ F('a'). -Expression has type: number() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:170:22 - │ -170 │ fun3_to_f4_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun((term()) -> 'a' | 'b') -Context expected type: f4('a') - │ - -Because in the expression's type: - fun((term()) -> - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -176 │ f4_to_fun_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: f4('a' | 'b') -Context expected type: fun((term()) -> 'a') - │ - -Because in the expression's type: - fun((term()) -> - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -208 │ apply_by_name_neg1(Mod, Name) -> Mod:Name(). - │ ^^^ Mod. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:208:38 - │ -208 │ apply_by_name_neg1(Mod, Name) -> Mod:Name(). - │ ^^^^ Name. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:212:9 - │ -212 │ Res = Mod:Name(), - │ ^^^ Mod. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:212:13 - │ -212 │ Res = Mod:Name(), - │ ^^^^ Name. -Expression has type: term() -Context expected type: atom() - -15 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun-OTP-28.pretty deleted file mode 100644 index 1f55b0f88a..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun-OTP-28.pretty +++ /dev/null @@ -1,181 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:65:3 - │ -65 │ fun M:id/1. - │ ^^^^^^^^^^ M:'id'/1. -Expression has type: fun((dynamic()) -> dynamic()) -Context expected type: fun(() -> pid()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:71:3 - │ -71 │ Res. - │ ^^^ Res. -Expression has type: fun((dynamic()) -> dynamic()) -Context expected type: fun(() -> pid()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:87:3 - │ -87 │ fun M:F/2. - │ ^^^^^^^^^ M:F/2. -Expression has type: fun((dynamic(), dynamic()) -> dynamic()) -Context expected type: fun((pid()) -> pid()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:93:3 - │ -93 │ Res. - │ ^^^ Res. -Expression has type: fun((dynamic(), dynamic()) -> dynamic()) -Context expected type: fun((pid()) -> pid()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:98:7 - │ -98 │ fun M:F/1. - │ ^ M. -Expression has type: {atom()} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:103:9 - │ -103 │ fun M:F/1. - │ ^ F. -Expression has type: {atom()} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:109:11 - │ -109 │ fun M:F/A. - │ ^ A. -Expression has type: pid() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:146:24 - │ -146 │ f5_to_f4_cov_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: f5('a' | 'b') -Context expected type: f4('a') - │ - -Because in the expression's type: - fun((term()) -> - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -155 │ apply_f4_neg(F) -> F(a). - │ ^^^^ F('a'). -Expression has type: number() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:170:22 - │ -170 │ fun3_to_f4_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun((term()) -> 'a' | 'b') -Context expected type: f4('a') - │ - -Because in the expression's type: - fun((term()) -> - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -176 │ f4_to_fun_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: f4('a' | 'b') -Context expected type: fun((term()) -> 'a') - │ - -Because in the expression's type: - fun((term()) -> - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -208 │ apply_by_name_neg1(Mod, Name) -> Mod:Name(). - │ ^^^ Mod. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:208:38 - │ -208 │ apply_by_name_neg1(Mod, Name) -> Mod:Name(). - │ ^^^^ Name. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:212:9 - │ -212 │ Res = Mod:Name(), - │ ^^^ Mod. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_fun.erl:212:13 - │ -212 │ Res = Mod:Name(), - │ ^^^^ Name. -Expression has type: term() -Context expected type: atom() - -15 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun.pretty similarity index 83% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun.pretty index 1f55b0f88a..7f7add29a8 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_fun.pretty @@ -72,16 +72,6 @@ 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 │ @@ -108,16 +98,6 @@ 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 │ @@ -136,16 +116,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics-OTP-26.pretty deleted file mode 100644 index cd54f2d176..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics-OTP-26.pretty +++ /dev/null @@ -1,181 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:33:3 - │ -33 │ lists:map(fun inc/1, Ns). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ lists:map(inc/1, Ns). -Expression has type: [number()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:43:3 - │ -43 │ lists:map(fun dyn_fun/1, Ns). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lists:map(dyn_fun/1, Ns). -Expression has type: [dynamic()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:53:3 - │ -53 │ lists:foldl(fun add/2, 0, Ns). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lists:foldl(add/2, 0, Ns). -Expression has type: number() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:65:3 - │ -65 │ lists:foldl(fun add/2, Acc, Ns). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ lists:foldl(add/2, Acc, Ns). -Expression has type: number() | dynamic() -Context expected type: none() - │ - -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: 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 - │ -72 │ {Res}. - │ ^^^^^ {Res}. -Expression has type: {number() | dynamic()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:78:3 - │ -78 │ lists:foldl(fun dyn_fun/2, Acc, Ns). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ lists:foldl(dyn_fun/2, Acc, Ns). -Expression has type: dynamic() | string() -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dynamic() - 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 - │ -87 │ fapply(fun inc/1, dyn_val()). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fapply(inc/1, dyn_val()). -Expression has type: number() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:92:3 - │ -92 │ {Res}. - │ ^^^^^ {Res}. -Expression has type: {dynamic()} -Context expected type: X - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:108:3 - │ -108 │ ╭ ╭ lists:map( -109 │ │ │ fun -110 │ │ │ Fib(N) when N < 2 -111 │ │ │ -> 1; - · │ │ -117 │ │ │ [1, 2, 3] -118 │ │ │ ). - │ ╰─│───^ lists:map(fun, [1, 2, 3]). -Expression has type: [number() | 'three'] -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: 'three' - 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 - │ -115 │ Fib(N - 2) + Fib(N - 1) - │ ^^^^^^^^^^ - │ │ - │ Fib(_ - _). -Expression has type: number() | 'three' -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: '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 - │ -115 │ Fib(N - 2) + Fib(N - 1) - │ ^^^^^^^^^^ - │ │ - │ Fib(_ - _). -Expression has type: number() | 'three' -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: '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 - │ -127 │ Fib(undefined) + Fib(N - 1) - │ ^^^^^^^^^ 'undefined'. -Expression has type: 'undefined' -Context expected type: number() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/dynamic_generics.erl:171:47 - │ -171 │ unify_dyn_atom(D, A) -> eqwalizer:reveal_type(either(D, A)). - │ ^^^^^^^^^^^^ dynamic() | 'undef' - -13 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics-OTP-28.pretty deleted file mode 100644 index cd54f2d176..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics-OTP-28.pretty +++ /dev/null @@ -1,181 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:33:3 - │ -33 │ lists:map(fun inc/1, Ns). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ lists:map(inc/1, Ns). -Expression has type: [number()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:43:3 - │ -43 │ lists:map(fun dyn_fun/1, Ns). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lists:map(dyn_fun/1, Ns). -Expression has type: [dynamic()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:53:3 - │ -53 │ lists:foldl(fun add/2, 0, Ns). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lists:foldl(add/2, 0, Ns). -Expression has type: number() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:65:3 - │ -65 │ lists:foldl(fun add/2, Acc, Ns). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ lists:foldl(add/2, Acc, Ns). -Expression has type: number() | dynamic() -Context expected type: none() - │ - -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: 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 - │ -72 │ {Res}. - │ ^^^^^ {Res}. -Expression has type: {number() | dynamic()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:78:3 - │ -78 │ lists:foldl(fun dyn_fun/2, Acc, Ns). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ lists:foldl(dyn_fun/2, Acc, Ns). -Expression has type: dynamic() | string() -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dynamic() - 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 - │ -87 │ fapply(fun inc/1, dyn_val()). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fapply(inc/1, dyn_val()). -Expression has type: number() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:92:3 - │ -92 │ {Res}. - │ ^^^^^ {Res}. -Expression has type: {dynamic()} -Context expected type: X - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_generics.erl:108:3 - │ -108 │ ╭ ╭ lists:map( -109 │ │ │ fun -110 │ │ │ Fib(N) when N < 2 -111 │ │ │ -> 1; - · │ │ -117 │ │ │ [1, 2, 3] -118 │ │ │ ). - │ ╰─│───^ lists:map(fun, [1, 2, 3]). -Expression has type: [number() | 'three'] -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: 'three' - 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 - │ -115 │ Fib(N - 2) + Fib(N - 1) - │ ^^^^^^^^^^ - │ │ - │ Fib(_ - _). -Expression has type: number() | 'three' -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: '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 - │ -115 │ Fib(N - 2) + Fib(N - 1) - │ ^^^^^^^^^^ - │ │ - │ Fib(_ - _). -Expression has type: number() | 'three' -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: '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 - │ -127 │ Fib(undefined) + Fib(N - 1) - │ ^^^^^^^^^ 'undefined'. -Expression has type: 'undefined' -Context expected type: number() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/dynamic_generics.erl:171:47 - │ -171 │ unify_dyn_atom(D, A) -> eqwalizer:reveal_type(either(D, A)). - │ ^^^^^^^^^^^^ dynamic() | 'undef' - -13 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics.pretty similarity index 83% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics.pretty index cd54f2d176..78c9a41f3f 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_generics.pretty @@ -38,12 +38,6 @@ 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 │ @@ -68,12 +62,6 @@ 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 │ @@ -112,14 +100,6 @@ 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 │ @@ -136,12 +116,6 @@ 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 │ @@ -158,12 +132,6 @@ 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-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs-OTP-27.pretty deleted file mode 100644 index 3ca5a136e6..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs-OTP-27.pretty +++ /dev/null @@ -1,47 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_local_funs.erl:30:3 - │ -30 │ lists:foldl(F, 0, L). - │ ^^^^^^^^^^^^^^^^^^^^ - │ │ - │ lists:foldl(F, 0, L). -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/dynamic_local_funs.erl:36:15 - │ -36 │ N1 + N2 + binary_to_atom(Acc) - │ ^^^^^^^^^^^^^^^^^^^ erlang:binary_to_atom(Acc). -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_local_funs.erl:48:3 - │ -48 │ X. - │ ^ X. -Expression has type: fun((dynamic(), dynamic()) -> dynamic()) -Context expected type: fun(('a') -> 'b') - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_local_funs.erl:111:3 - │ -111 │ ok. - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: pid() - -4 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs-OTP-28.pretty deleted file mode 100644 index 3ca5a136e6..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs-OTP-28.pretty +++ /dev/null @@ -1,47 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_local_funs.erl:30:3 - │ -30 │ lists:foldl(F, 0, L). - │ ^^^^^^^^^^^^^^^^^^^^ - │ │ - │ lists:foldl(F, 0, L). -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/dynamic_local_funs.erl:36:15 - │ -36 │ N1 + N2 + binary_to_atom(Acc) - │ ^^^^^^^^^^^^^^^^^^^ erlang:binary_to_atom(Acc). -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_local_funs.erl:48:3 - │ -48 │ X. - │ ^ X. -Expression has type: fun((dynamic(), dynamic()) -> dynamic()) -Context expected type: fun(('a') -> 'b') - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_local_funs.erl:111:3 - │ -111 │ ok. - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: pid() - -4 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs.pretty similarity index 87% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs.pretty index 3ca5a136e6..6e82aa3702 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs-OTP-26.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_local_funs.pretty @@ -14,12 +14,6 @@ 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/compiler_macro-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_receive.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/compiler_macro-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_receive.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine-OTP-26.pretty deleted file mode 100644 index 16ed8f0a82..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine-OTP-26.pretty +++ /dev/null @@ -1,176 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:86:21 - │ -86 │ is_list(Arg) -> {Arg} - │ ^^^^^ {Arg}. -Expression has type: {[term()]} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:95:21 - │ -95 │ is_list(Dyn) -> {Dyn} - │ ^^^^^ {Dyn}. -Expression has type: {dynamic([term()])} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:102:23 - │ -102 │ is_binary(Arg) -> {Arg} - │ ^^^^^ {Arg}. -Expression has type: {binary()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:111:23 - │ -111 │ is_binary(Dyn) -> {Dyn}; - │ ^^^^^ {Dyn}. -Expression has type: {dynamic(binary())} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:123:3 - │ -123 │ {Mixed}. - │ ^^^^^^^ {Mixed}. -Expression has type: {term()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:133:3 - │ -133 │ {Mixed}. - │ ^^^^^^^ {Mixed}. -Expression has type: {term()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:143:3 - │ -143 │ {Mixed}. - │ ^^^^^^^ {Mixed}. -Expression has type: {boolean() | dynamic()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:153:3 - │ -153 │ {Mixed}. - │ ^^^^^^^ {Mixed}. -Expression has type: {dynamic() | binary()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:168:3 - │ -168 │ {Mixed2}. - │ ^^^^^^^^ {Mixed2}. -Expression has type: {binary() | atom() | dynamic()} -Context expected type: 'ok' - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/dynamic_refine.erl:180:25 - │ -180 │ eqwalizer:reveal_type(Name), - │ ^^^^ atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:181:3 - │ -181 │ Name. - │ ^^^^ Name. -Expression has type: atom() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:221:28 - │ -221 │ dyn_refine_union_neg(D) -> D. - │ ^ - │ │ - │ D. -Expression has type: dynamic() | 'error' | none() -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dynamic() - However the following candidate: 'error' - Differs from the expected type: 'ok' - ------------------------------- Detailed message ------------------------------ - - dynamic() | 'error' | none() 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 - │ -236 │ atom_to_binary(Id). - │ ^^^^^^^^^^^^^^^^^^ erlang:atom_to_binary(Id). -Expression has type: binary() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:236:18 - │ -236 │ atom_to_binary(Id). - │ ^^ Id. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:247:32 - │ -247 │ refine_union_alias_neg({X}) -> X. - │ ^ - │ │ - │ X. -Expression has type: dyn_alias() | 'err' -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dyn_alias() - 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 - │ -260 │ refine_in_tuple_neg(T) -> T. - │ ^ - │ │ - │ T. -Expression has type: union() -Context expected type: {'ok'} - │ - -Because in the expression's type: - { - Here the type is a union type with some valid candidates: dyn_alias() - However the following candidate: 'err' - 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/dynamic_refine-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine-OTP-28.pretty deleted file mode 100644 index 16ed8f0a82..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine-OTP-28.pretty +++ /dev/null @@ -1,176 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:86:21 - │ -86 │ is_list(Arg) -> {Arg} - │ ^^^^^ {Arg}. -Expression has type: {[term()]} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:95:21 - │ -95 │ is_list(Dyn) -> {Dyn} - │ ^^^^^ {Dyn}. -Expression has type: {dynamic([term()])} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:102:23 - │ -102 │ is_binary(Arg) -> {Arg} - │ ^^^^^ {Arg}. -Expression has type: {binary()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:111:23 - │ -111 │ is_binary(Dyn) -> {Dyn}; - │ ^^^^^ {Dyn}. -Expression has type: {dynamic(binary())} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:123:3 - │ -123 │ {Mixed}. - │ ^^^^^^^ {Mixed}. -Expression has type: {term()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:133:3 - │ -133 │ {Mixed}. - │ ^^^^^^^ {Mixed}. -Expression has type: {term()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:143:3 - │ -143 │ {Mixed}. - │ ^^^^^^^ {Mixed}. -Expression has type: {boolean() | dynamic()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:153:3 - │ -153 │ {Mixed}. - │ ^^^^^^^ {Mixed}. -Expression has type: {dynamic() | binary()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:168:3 - │ -168 │ {Mixed2}. - │ ^^^^^^^^ {Mixed2}. -Expression has type: {binary() | atom() | dynamic()} -Context expected type: 'ok' - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/dynamic_refine.erl:180:25 - │ -180 │ eqwalizer:reveal_type(Name), - │ ^^^^ atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:181:3 - │ -181 │ Name. - │ ^^^^ Name. -Expression has type: atom() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:221:28 - │ -221 │ dyn_refine_union_neg(D) -> D. - │ ^ - │ │ - │ D. -Expression has type: dynamic() | 'error' | none() -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dynamic() - However the following candidate: 'error' - Differs from the expected type: 'ok' - ------------------------------- Detailed message ------------------------------ - - dynamic() | 'error' | none() 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 - │ -236 │ atom_to_binary(Id). - │ ^^^^^^^^^^^^^^^^^^ erlang:atom_to_binary(Id). -Expression has type: binary() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:236:18 - │ -236 │ atom_to_binary(Id). - │ ^^ Id. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/dynamic_refine.erl:247:32 - │ -247 │ refine_union_alias_neg({X}) -> X. - │ ^ - │ │ - │ X. -Expression has type: dyn_alias() | 'err' -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dyn_alias() - 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 - │ -260 │ refine_in_tuple_neg(T) -> T. - │ ^ - │ │ - │ T. -Expression has type: union() -Context expected type: {'ok'} - │ - -Because in the expression's type: - { - Here the type is a union type with some valid candidates: dyn_alias() - However the following candidate: 'err' - 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/dynamic_refine-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine.pretty similarity index 87% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine.pretty index 16ed8f0a82..ce03971816 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_refine.pretty @@ -91,7 +91,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^ │ │ │ D. -Expression has type: dynamic() | 'error' | none() +Expression has type: dynamic() | 'error' Context expected type: 'ok' │ @@ -100,12 +100,6 @@ Because in the expression's type: However the following candidate: 'error' Differs from the expected type: 'ok' ------------------------------- Detailed message ------------------------------ - - dynamic() | 'error' | none() 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 │ @@ -138,12 +132,6 @@ 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 │ @@ -162,15 +150,4 @@ 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/compiler_macro-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_try_catch.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/compiler_macro-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_try_catch.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause-OTP-26.pretty deleted file mode 100644 index b9fdc2fbce..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause-OTP-26.pretty +++ /dev/null @@ -1,85 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/elab_clause.erl:30:5 - │ -30 │ Res. - │ ^^^ Res. -Expression has type: atom() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/elab_clause.erl:48:5 - │ -48 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: atom() | {number()} -Context expected type: {atom()} | number() - │ - -Because in the expression's type: - Here the type is: atom() - Context expects type: {atom()} | number() - No candidate matches in the expected union. - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/elab_clause.erl:76:5 - │ -76 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: 'error' | 'exit' | 'throw' | 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: '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 - │ -86 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: number() | [dynamic()] -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: [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 - │ -93 │ A:_ -> A - │ ^ A. -Expression has type: 'error' | 'exit' | 'throw' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/elab_clause.erl:101:27 - │ -101 │ Class:_:Stack -> {Class, Stack} - │ ^^^^^^^^^^^^^^ {Class, Stack}. -Expression has type: {'error' | 'exit' | 'throw', [dynamic()]} -Context expected type: number() - -6 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause-OTP-27.pretty deleted file mode 100644 index b9fdc2fbce..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause-OTP-27.pretty +++ /dev/null @@ -1,85 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/elab_clause.erl:30:5 - │ -30 │ Res. - │ ^^^ Res. -Expression has type: atom() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/elab_clause.erl:48:5 - │ -48 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: atom() | {number()} -Context expected type: {atom()} | number() - │ - -Because in the expression's type: - Here the type is: atom() - Context expects type: {atom()} | number() - No candidate matches in the expected union. - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/elab_clause.erl:76:5 - │ -76 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: 'error' | 'exit' | 'throw' | 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: '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 - │ -86 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: number() | [dynamic()] -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: [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 - │ -93 │ A:_ -> A - │ ^ A. -Expression has type: 'error' | 'exit' | 'throw' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/elab_clause.erl:101:27 - │ -101 │ Class:_:Stack -> {Class, Stack} - │ ^^^^^^^^^^^^^^ {Class, Stack}. -Expression has type: {'error' | 'exit' | 'throw', [dynamic()]} -Context expected type: number() - -6 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause.pretty similarity index 85% rename from crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause.pretty index b9fdc2fbce..e02928cc14 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause-OTP-28.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/elab_clause.pretty @@ -38,12 +38,6 @@ 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 │ @@ -60,12 +54,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/error_messages-OTP-26.pretty deleted file mode 100644 index ee63204870..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/error_messages-OTP-26.pretty +++ /dev/null @@ -1,128 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/error_messages.erl:16:22 - │ -16 │ map_candidates(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{bar := atom(), baz := atom()} -Context expected type: foo_map() | #{foo => atom()} - │ - -Because in the expression's type: - #{ baz => - Here the type is: atom() - 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 - │ -19 │ map_candidates_2(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: [#{bar => 'a' | 'b'} | #{baz => 'a' | 'b'}] -Context expected type: [#{bar => 'a'}] - │ - -Because in the expression's type: - [ - Here the type is: #{baz => ...} - Context expects 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 - │ -22 │ no_map_rewrite(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{'undefined' | binary() => atom()} -Context expected type: #{binary() => atom()} - │ - -Because in the expression's type: - #{ map domains are incompatible: - Here the type is a union type with some valid candidates: binary() - However the following candidate: 'undefined' - 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 - │ -27 │ no_record_conversion_1(Foo) -> Foo. - │ ^^^ Foo. -Expression has type: #foo{} -Context expected type: {'foobar', atom()} - -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. -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 - │ -33 │ record_conversion(Foo) -> Foo. - │ ^^^ - │ │ - │ Foo. -Expression has type: #foo{} -Context expected type: {'foo', binary(), atom()} - │ - -Because in the expression's type: - { 'foo', - Here the type is: atom() - 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() - -6 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/error_messages-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/error_messages-OTP-28.pretty deleted file mode 100644 index ee63204870..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/error_messages-OTP-28.pretty +++ /dev/null @@ -1,128 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/error_messages.erl:16:22 - │ -16 │ map_candidates(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{bar := atom(), baz := atom()} -Context expected type: foo_map() | #{foo => atom()} - │ - -Because in the expression's type: - #{ baz => - Here the type is: atom() - 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 - │ -19 │ map_candidates_2(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: [#{bar => 'a' | 'b'} | #{baz => 'a' | 'b'}] -Context expected type: [#{bar => 'a'}] - │ - -Because in the expression's type: - [ - Here the type is: #{baz => ...} - Context expects 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 - │ -22 │ no_map_rewrite(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{'undefined' | binary() => atom()} -Context expected type: #{binary() => atom()} - │ - -Because in the expression's type: - #{ map domains are incompatible: - Here the type is a union type with some valid candidates: binary() - However the following candidate: 'undefined' - 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 - │ -27 │ no_record_conversion_1(Foo) -> Foo. - │ ^^^ Foo. -Expression has type: #foo{} -Context expected type: {'foobar', atom()} - -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. -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 - │ -33 │ record_conversion(Foo) -> Foo. - │ ^^^ - │ │ - │ Foo. -Expression has type: #foo{} -Context expected type: {'foo', binary(), atom()} - │ - -Because in the expression's type: - { 'foo', - Here the type is: atom() - 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() - -6 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/error_messages-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/error_messages.pretty similarity index 61% rename from crates/elp/src/resources/test/eqwalizer_tests/check/error_messages-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/error_messages.pretty index ee63204870..fab550d5e6 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/error_messages-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/error_messages.pretty @@ -15,17 +15,6 @@ 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 │ @@ -44,12 +33,6 @@ 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 │ @@ -68,15 +51,6 @@ 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 │ @@ -89,17 +63,9 @@ 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 @@ -118,11 +84,40 @@ Because in the expression's type: Context expects type: binary() , atom()} ------------------------------- Detailed message ------------------------------ +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/error_messages.erl:37:31 + │ +37 │ no_good_map_candidate_1(M) -> M. + │ ^ + │ │ + │ M. +Expression has type: #{foo => #{large_map_key_a => 'large_map_val_a', large_map_key_b => 'large_map_val_b'}} +Context expected type: #{foo => #{large_map_key_c => 'large_map_val_c'} | #{large_map_key_d => 'large_map_val_d'}} + │ - at tuple index 2: - {'foo', atom(), atom()} is not compatible with {'foo', binary(), atom()} - because - atom() is not compatible with binary() +Because in the expression's type: + #{ foo => + Here the type is: #{large_map_key_a => ...} + Context expects type: #{...} + The expected map has no corresponding key for: large_map_key_a. + , ... } -6 ERRORS +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/error_messages.erl:41:31 + │ +41 │ no_good_map_candidate_2(M) -> M. + │ ^ + │ │ + │ M. +Expression has type: #{foo => #{large_map_key_a => 'large_map_val_a', large_map_key_b => 'large_map_val_b'}} +Context expected type: #{foo => #{large_map_key_c => 'large_map_val_c', large_map_key_d => 'large_map_val_d'} | 'any'} + │ + +Because in the expression's type: + #{ foo => + Here the type is: #{large_map_key_a => ...} + Context expects type: #{...} + The expected map has no corresponding key for: large_map_key_a. + , ... } + +8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs1-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/fancy_generics.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs1-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/fancy_generics.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/format-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/format-OTP-26.pretty deleted file mode 100644 index f6d7701c2e..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/format-OTP-26.pretty +++ /dev/null @@ -1,22 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/format.erl:13:3 - │ -13 │ io_lib:format("~p", [X]). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ io_lib:format(string_lit, [X]). -Expression has type: io_lib:chars() -Context expected type: string() - │ - -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/format-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/format-OTP-28.pretty deleted file mode 100644 index f6d7701c2e..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/format-OTP-28.pretty +++ /dev/null @@ -1,22 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/format.erl:13:3 - │ -13 │ io_lib:format("~p", [X]). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ io_lib:format(string_lit, [X]). -Expression has type: io_lib:chars() -Context expected type: string() - │ - -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/format-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/format.pretty similarity index 69% rename from crates/elp/src/resources/test/eqwalizer_tests/check/format-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/format.pretty index f6d7701c2e..1a6ae465e8 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/format-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/format.pretty @@ -13,10 +13,4 @@ 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/fun_stats-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats-OTP-27.pretty deleted file mode 100644 index a8ac75c742..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats-OTP-27.pretty +++ /dev/null @@ -1,41 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats.erl:36:3 - │ -36 │ wn_ey_sy() + 3. - │ ^^^^^^^^^^ wn_ey_sy(). -Expression has type: 'ok' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats.erl:36:3 - │ -36 │ wn_ey_sy() + 3. - │ ^^^^^^^^^^^^^^ _ + _. -Expression has type: number() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats.erl:43:3 - │ -43 │ wy_ey_sy() + 3. - │ ^^^^^^^^^^ wy_ey_sy(). -Expression has type: 'ok' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats.erl:46:3 - │ -46 │ wy_ey_sy() + 3. - │ ^^^^^^^^^^ wy_ey_sy(). -Expression has type: 'ok' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats.erl:55:3 - │ -55 │ wy_ey_sy() + 3. - │ ^^^^^^^^^^ wy_ey_sy(). -Expression has type: 'ok' -Context expected type: number() - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats-OTP-28.pretty deleted file mode 100644 index a8ac75c742..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats-OTP-28.pretty +++ /dev/null @@ -1,41 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats.erl:36:3 - │ -36 │ wn_ey_sy() + 3. - │ ^^^^^^^^^^ wn_ey_sy(). -Expression has type: 'ok' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats.erl:36:3 - │ -36 │ wn_ey_sy() + 3. - │ ^^^^^^^^^^^^^^ _ + _. -Expression has type: number() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats.erl:43:3 - │ -43 │ wy_ey_sy() + 3. - │ ^^^^^^^^^^ wy_ey_sy(). -Expression has type: 'ok' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats.erl:46:3 - │ -46 │ wy_ey_sy() + 3. - │ ^^^^^^^^^^ wy_ey_sy(). -Expression has type: 'ok' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats.erl:55:3 - │ -55 │ wy_ey_sy() + 3. - │ ^^^^^^^^^^ wy_ey_sy(). -Expression has type: 'ok' -Context expected type: number() - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats2-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats2-OTP-27.pretty deleted file mode 100644 index 0fdf42f94d..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats2-OTP-27.pretty +++ /dev/null @@ -1,25 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats2.erl:15:11 - │ -15 │ _ = 1 + Atom, - │ ^^^^ Atom. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats2.erl:16:22 - │ -16 │ _ = binary_to_atom(Atom), - │ ^^^^ Atom. -Expression has type: atom() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats2.erl:17:13 - │ -17 │ _ = "" ++ Atom, - │ ^^^^ Atom. -Expression has type: atom() -Context expected type: [term()] - -3 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats2-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats2-OTP-28.pretty deleted file mode 100644 index 0fdf42f94d..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats2-OTP-28.pretty +++ /dev/null @@ -1,25 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats2.erl:15:11 - │ -15 │ _ = 1 + Atom, - │ ^^^^ Atom. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats2.erl:16:22 - │ -16 │ _ = binary_to_atom(Atom), - │ ^^^^ Atom. -Expression has type: atom() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/fun_stats2.erl:17:13 - │ -17 │ _ = "" ++ Atom, - │ ^^^^ Atom. -Expression has type: atom() -Context expected type: [term()] - -3 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats2-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats2.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats2-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/fun_stats2.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/funs-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/funs-OTP-26.pretty deleted file mode 100644 index 589448836f..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/funs-OTP-26.pretty +++ /dev/null @@ -1,373 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:23:20 - │ -23 │ check_fun_neg() -> fun() -> ok end. - │ ^^^^^^^^^^^^^^^ fun. -Expression has type: fun(() -> 'ok') -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:28:27 - │ -28 │ fun() -> list_to_atom(Tup) end. - │ ^^^ Tup. -Expression has type: {} -Context expected type: string() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:63:9 - │ -63 │ X ++ [] end, - │ ^ - │ │ - │ X. -Expression has type: n() -Context expected type: [term()] - │ - -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 - │ -63 │ X ++ [] end, - │ ^^^^^^^ - │ │ - │ _ ++ _. -Expression has type: [dynamic()] -Context expected type: n() - │ - -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 - │ -70 │ erlang:atom_to_binary(X) - │ ^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ erlang:atom_to_binary(X). -Expression has type: binary() -Context expected type: n() - │ - -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 - │ -70 │ erlang:atom_to_binary(X) - │ ^ - │ │ - │ X. -Expression has type: n() -Context expected type: atom() - │ - -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 - │ -77 │ ╭ ╭ lmap_n_to_n( -78 │ │ │ fun(X) -> X end, -79 │ │ │ [1,2,3] -80 │ │ │ ). - │ ╰─│─────^ lmap_n_to_n(fun, [1, 2, 3]). -Expression has type: [n()] -Context expected type: ['a'] - │ ╰─────' - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -90 │ fun(X, Y) -> X ++ Y end. - │ ^ - │ │ - │ X. -Expression has type: n() -Context expected type: [term()] - │ - -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 - │ -90 │ fun(X, Y) -> X ++ Y end. - │ ^^^^^^ - │ │ - │ _ ++ _. -Expression has type: [dynamic()] -Context expected type: n() - │ - -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 - │ -90 │ fun(X, Y) -> X ++ Y end. - │ ^ - │ │ - │ Y. -Expression has type: n() -Context expected type: [term()] - │ - -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 - │ -96 │ erlang:atom_to_binary(X), - │ ^ - │ │ - │ X. -Expression has type: n() -Context expected type: atom() - │ - -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 - │ -97 │ X ++ Y - │ ^ - │ │ - │ X. -Expression has type: n() -Context expected type: [term()] - │ - -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 - │ -97 │ X ++ Y - │ ^^^^^^ - │ │ - │ _ ++ _. -Expression has type: [dynamic()] -Context expected type: n() - │ - -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 - │ -97 │ X ++ Y - │ ^ - │ │ - │ Y. -Expression has type: n() -Context expected type: [term()] - │ - -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 - │ -104 │ erlang:is_number(X) - │ ^^^^^^^^^^^^^^^^^^^ erlang:is_number(X). -Expression has type: boolean() -Context expected type: n() - -error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) - ┌─ check/src/funs.erl:127:9 - │ -127 │ fun (X, _) -> X 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/funs.erl:134:24 - │ -134 │ fun (Y) -> Y + N end, - │ ^ N. -Expression has type: atom() -Context expected type: number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/funs.erl:155:1 - │ -155 │ ╭ x6(L, B) -> -156 │ │ xmap(fun (_) -> B end, L). - │ ╰─────────────────────────────^ Clause is not covered by spec - -error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) - ┌─ check/src/funs.erl:195:5 - │ -195 │ (fun () -> ok end)(1, 2, 3). - │ ^^^^^^^^^^^^^^^^^^ fun. -fun with arity 0 used as fun with 3 arguments - -error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) - ┌─ check/src/funs.erl:199:5 - │ -199 │ (fun (_X) -> ok end)(1, 2, 3). - │ ^^^^^^^^^^^^^^^^^^^^ fun. -fun with arity 1 used as fun with 3 arguments - -error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) - ┌─ check/src/funs.erl:203:5 - │ -203 │ (fun (_X) -> ok end)(). - │ ^^^^^^^^^^^^^^^^^^^^ fun. -fun with arity 1 used as fun with 0 arguments - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:224:16 - │ -224 │ fun F() -> F end. - │ ^ F. -Expression has type: fun(() -> 'a') -Context expected type: 'a' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:329:9 - │ -329 │ F(A) - │ ^^^^ F(A). -Expression has type: term() -Context expected type: 'other' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:336:11 - │ -336 │ F(A) - │ ^ A. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:363:5 - │ -363 │ Fun(). - │ ^^^^^ Fun(). -Expression has type: 'no_ok' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:368:5 - │ -368 │ Fun(). - │ ^^^^^ Fun(). -Expression has type: 'no_ok' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:374:54 - │ -374 │ use_callback_test_neg() -> callback_test(fun (_T) -> ok end). - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: none() - -27 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/funs-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/funs-OTP-28.pretty deleted file mode 100644 index 589448836f..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/funs-OTP-28.pretty +++ /dev/null @@ -1,373 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:23:20 - │ -23 │ check_fun_neg() -> fun() -> ok end. - │ ^^^^^^^^^^^^^^^ fun. -Expression has type: fun(() -> 'ok') -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:28:27 - │ -28 │ fun() -> list_to_atom(Tup) end. - │ ^^^ Tup. -Expression has type: {} -Context expected type: string() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:63:9 - │ -63 │ X ++ [] end, - │ ^ - │ │ - │ X. -Expression has type: n() -Context expected type: [term()] - │ - -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 - │ -63 │ X ++ [] end, - │ ^^^^^^^ - │ │ - │ _ ++ _. -Expression has type: [dynamic()] -Context expected type: n() - │ - -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 - │ -70 │ erlang:atom_to_binary(X) - │ ^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ erlang:atom_to_binary(X). -Expression has type: binary() -Context expected type: n() - │ - -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 - │ -70 │ erlang:atom_to_binary(X) - │ ^ - │ │ - │ X. -Expression has type: n() -Context expected type: atom() - │ - -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 - │ -77 │ ╭ ╭ lmap_n_to_n( -78 │ │ │ fun(X) -> X end, -79 │ │ │ [1,2,3] -80 │ │ │ ). - │ ╰─│─────^ lmap_n_to_n(fun, [1, 2, 3]). -Expression has type: [n()] -Context expected type: ['a'] - │ ╰─────' - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -90 │ fun(X, Y) -> X ++ Y end. - │ ^ - │ │ - │ X. -Expression has type: n() -Context expected type: [term()] - │ - -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 - │ -90 │ fun(X, Y) -> X ++ Y end. - │ ^^^^^^ - │ │ - │ _ ++ _. -Expression has type: [dynamic()] -Context expected type: n() - │ - -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 - │ -90 │ fun(X, Y) -> X ++ Y end. - │ ^ - │ │ - │ Y. -Expression has type: n() -Context expected type: [term()] - │ - -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 - │ -96 │ erlang:atom_to_binary(X), - │ ^ - │ │ - │ X. -Expression has type: n() -Context expected type: atom() - │ - -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 - │ -97 │ X ++ Y - │ ^ - │ │ - │ X. -Expression has type: n() -Context expected type: [term()] - │ - -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 - │ -97 │ X ++ Y - │ ^^^^^^ - │ │ - │ _ ++ _. -Expression has type: [dynamic()] -Context expected type: n() - │ - -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 - │ -97 │ X ++ Y - │ ^ - │ │ - │ Y. -Expression has type: n() -Context expected type: [term()] - │ - -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 - │ -104 │ erlang:is_number(X) - │ ^^^^^^^^^^^^^^^^^^^ erlang:is_number(X). -Expression has type: boolean() -Context expected type: n() - -error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) - ┌─ check/src/funs.erl:127:9 - │ -127 │ fun (X, _) -> X 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/funs.erl:134:24 - │ -134 │ fun (Y) -> Y + N end, - │ ^ N. -Expression has type: atom() -Context expected type: number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/funs.erl:155:1 - │ -155 │ ╭ x6(L, B) -> -156 │ │ xmap(fun (_) -> B end, L). - │ ╰─────────────────────────────^ Clause is not covered by spec - -error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) - ┌─ check/src/funs.erl:195:5 - │ -195 │ (fun () -> ok end)(1, 2, 3). - │ ^^^^^^^^^^^^^^^^^^ fun. -fun with arity 0 used as fun with 3 arguments - -error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) - ┌─ check/src/funs.erl:199:5 - │ -199 │ (fun (_X) -> ok end)(1, 2, 3). - │ ^^^^^^^^^^^^^^^^^^^^ fun. -fun with arity 1 used as fun with 3 arguments - -error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) - ┌─ check/src/funs.erl:203:5 - │ -203 │ (fun (_X) -> ok end)(). - │ ^^^^^^^^^^^^^^^^^^^^ fun. -fun with arity 1 used as fun with 0 arguments - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:224:16 - │ -224 │ fun F() -> F end. - │ ^ F. -Expression has type: fun(() -> 'a') -Context expected type: 'a' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:329:9 - │ -329 │ F(A) - │ ^^^^ F(A). -Expression has type: term() -Context expected type: 'other' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:336:11 - │ -336 │ F(A) - │ ^ A. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:363:5 - │ -363 │ Fun(). - │ ^^^^^ Fun(). -Expression has type: 'no_ok' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:368:5 - │ -368 │ Fun(). - │ ^^^^^ Fun(). -Expression has type: 'no_ok' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs.erl:374:54 - │ -374 │ use_callback_test_neg() -> callback_test(fun (_T) -> ok end). - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: none() - -27 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/funs-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/funs.pretty similarity index 81% rename from crates/elp/src/resources/test/eqwalizer_tests/check/funs-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/funs.pretty index 589448836f..1e2c339ecc 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/funs-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/funs.pretty @@ -29,12 +29,6 @@ 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 │ @@ -50,12 +44,6 @@ 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 │ @@ -71,12 +59,6 @@ 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 │ @@ -92,12 +74,6 @@ 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 │ @@ -116,14 +92,6 @@ 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 │ @@ -139,12 +107,6 @@ 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 │ @@ -160,12 +122,6 @@ 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 │ @@ -181,12 +137,6 @@ 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 │ @@ -202,12 +152,6 @@ 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 │ @@ -223,12 +167,6 @@ 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 │ @@ -244,12 +182,6 @@ 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 │ @@ -265,12 +197,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/funs2-OTP-26.pretty deleted file mode 100644 index 7b20cba52c..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/funs2-OTP-26.pretty +++ /dev/null @@ -1,135 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs2.erl:32:20 - │ -32 │ 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/funs2.erl:54:5 - │ -54 │ X. - │ ^ X. -Expression has type: [dynamic()] -Context expected type: number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/funs2.erl:95:1 - │ -95 │ generic({}, {}, {}) -> nok. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs2.erl:95:24 - │ -95 │ generic({}, {}, {}) -> nok. - │ ^^^ 'nok'. -Expression has type: 'nok' -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs2.erl:101:9 - │ -101 │ fun erlang:atom_to_list/1, - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ erlang:atom_to_list/1. -Expression has type: fun((atom()) -> string()) -Context expected type: fun((atom()) -> atom()) - │ - -Because in the expression's type: - fun((atom()) -> - Here the type is: string() - 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 - │ -101 │ fun erlang:atom_to_list/1, - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ erlang:atom_to_list/1. -Expression has type: fun((atom()) -> string()) -Context expected type: fun((dynamic() | fun((string()) -> atom())) -> dynamic() | fun((string()) -> atom())) - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: dynamic() - However the following candidate: fun((string()) -> atom()) - 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 - │ -101 │ fun erlang:atom_to_list/1, - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ erlang:atom_to_list/1. -Expression has type: fun((atom()) -> string()) -Context expected type: fun((dynamic() | string() | fun((string()) -> atom())) -> dynamic() | string() | fun((string()) -> atom())) - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: dynamic() - However the following candidate: string() - 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 - │ -152 │ (X, X) -> X + A - │ ^ A. -Expression has type: atom() -Context expected type: number() - -8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/funs2-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/funs2-OTP-28.pretty deleted file mode 100644 index 7b20cba52c..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/funs2-OTP-28.pretty +++ /dev/null @@ -1,135 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs2.erl:32:20 - │ -32 │ 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/funs2.erl:54:5 - │ -54 │ X. - │ ^ X. -Expression has type: [dynamic()] -Context expected type: number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/funs2.erl:95:1 - │ -95 │ generic({}, {}, {}) -> nok. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs2.erl:95:24 - │ -95 │ generic({}, {}, {}) -> nok. - │ ^^^ 'nok'. -Expression has type: 'nok' -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs2.erl:101:9 - │ -101 │ fun erlang:atom_to_list/1, - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ erlang:atom_to_list/1. -Expression has type: fun((atom()) -> string()) -Context expected type: fun((atom()) -> atom()) - │ - -Because in the expression's type: - fun((atom()) -> - Here the type is: string() - 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 - │ -101 │ fun erlang:atom_to_list/1, - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ erlang:atom_to_list/1. -Expression has type: fun((atom()) -> string()) -Context expected type: fun((dynamic() | fun((string()) -> atom())) -> dynamic() | fun((string()) -> atom())) - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: dynamic() - However the following candidate: fun((string()) -> atom()) - 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 - │ -101 │ fun erlang:atom_to_list/1, - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ erlang:atom_to_list/1. -Expression has type: fun((atom()) -> string()) -Context expected type: fun((dynamic() | string() | fun((string()) -> atom())) -> dynamic() | string() | fun((string()) -> atom())) - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: dynamic() - However the following candidate: string() - 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 - │ -152 │ (X, X) -> X + A - │ ^ A. -Expression has type: atom() -Context expected type: number() - -8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/funs2-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/funs2.pretty similarity index 74% rename from crates/elp/src/resources/test/eqwalizer_tests/check/funs2-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/funs2.pretty index 7b20cba52c..f3a82abfd6 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/funs2-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/funs2.pretty @@ -19,14 +19,6 @@ 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 │ @@ -66,12 +58,6 @@ 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 │ @@ -90,14 +76,6 @@ 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 │ @@ -116,14 +94,6 @@ 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/funs_uncommon-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/funs_uncommon-OTP-27.pretty deleted file mode 100644 index 269917ecb4..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/funs_uncommon-OTP-27.pretty +++ /dev/null @@ -1,9 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs_uncommon.erl:38:13 - │ -38 │ field = {fun(X) -> X end, an_atom} - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ {fun, 'an_atom'}. -Expression has type: {fun((dynamic()) -> dynamic()), 'an_atom'} -Context expected type: fun(('a') -> 'a') - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/funs_uncommon-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/funs_uncommon-OTP-28.pretty deleted file mode 100644 index 269917ecb4..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/funs_uncommon-OTP-28.pretty +++ /dev/null @@ -1,9 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/funs_uncommon.erl:38:13 - │ -38 │ field = {fun(X) -> X end, an_atom} - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ {fun, 'an_atom'}. -Expression has type: {fun((dynamic()) -> dynamic()), 'an_atom'} -Context expected type: fun(('a') -> 'a') - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/funs_uncommon-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/funs_uncommon.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/funs_uncommon-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/funs_uncommon.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application-OTP-27.pretty deleted file mode 100644 index c10af08c9d..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application-OTP-27.pretty +++ /dev/null @@ -1,1232 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:27:18 - │ -27 │ test01_neg(X) -> fapply(fun id/1, X). - │ ^^^^^^^^^^^^^^^^^^^ fapply(id/1, X). -Expression has type: atom() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:38:5 - │ -38 │ lmap(fun atom_to_pid/1, [2, 4]). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lmap(atom_to_pid/1, [2, 4]). -Expression has type: [pid()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:38:29 - │ -38 │ lmap(fun atom_to_pid/1, [2, 4]). - │ ^^^^^^ - │ │ - │ [2, 4]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -38 │ lmap(fun atom_to_pid/1, [2, 4]). - │ ^^^^^^ - │ │ - │ [2, 4]. -Expression has type: [number()] -Context expected type: [dynamic(atom())] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -43 │ mapl([2, 4], fun atom_to_pid/1). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mapl([2, 4], atom_to_pid/1). -Expression has type: [pid()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:43:18 - │ -43 │ mapl([2, 4], fun atom_to_pid/1). - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ atom_to_pid/1. -Expression has type: fun((atom()) -> pid()) -Context expected type: fun((number()) -> B) - │ - -Because in the expression's type: - fun((atom()) -> - Here the type is: pid() - 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 - │ -43 │ mapl([2, 4], fun atom_to_pid/1). - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ atom_to_pid/1. -Expression has type: fun((atom()) -> pid()) -Context expected type: fun((dynamic() | number()) -> pid()) - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: dynamic() - However the following candidate: number() - 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 - │ -47 │ X = lmap(fun atom_to_pid/1, [2, 4]), - │ ^^^^^^ - │ │ - │ [2, 4]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -47 │ X = lmap(fun atom_to_pid/1, [2, 4]), - │ ^^^^^^ - │ │ - │ [2, 4]. -Expression has type: [number()] -Context expected type: [dynamic(atom())] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -48 │ X. - │ ^ X. -Expression has type: [pid()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:52:22 - │ -52 │ X = mapl([2, 4], fun atom_to_pid/1), - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ atom_to_pid/1. -Expression has type: fun((atom()) -> pid()) -Context expected type: fun((number()) -> B) - │ - -Because in the expression's type: - fun((atom()) -> - Here the type is: pid() - 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 - │ -52 │ X = mapl([2, 4], fun atom_to_pid/1), - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ atom_to_pid/1. -Expression has type: fun((atom()) -> pid()) -Context expected type: fun((dynamic() | number()) -> pid()) - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: dynamic() - However the following candidate: number() - 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 - │ -53 │ X. - │ ^ X. -Expression has type: [pid()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:67:23 - │ -67 │ test08_neg() -> lhead(h). - │ ^ 'h'. -Expression has type: 'h' -Context expected type: [LH] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:67:23 - │ -67 │ test08_neg() -> lhead(h). - │ ^ 'h'. -Expression has type: 'h' -Context expected type: [dynamic()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:80:18 - │ -80 │ test09_neg(M) -> maptt(M). - │ ^^^^^^^^ maptt(M). -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:95:13 - │ -95 │ map_att(M). - │ ^ - │ │ - │ M. -Expression has type: #{true => pid()} -Context expected type: #{a => dynamic()} - │ - -Because in the expression's type: - Here the type is: #{true => ...} - 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 - │ -99 │ map_att(3). - │ ^ 3. -Expression has type: number() -Context expected type: #{a => T} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:99:13 - │ -99 │ map_att(3). - │ ^ 3. -Expression has type: number() -Context expected type: #{a => dynamic()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:102:17 - │ -102 │ test13_neg() -> lmap({}, [2, 4]). - │ ^^^^^^^^^^^^^^^^ lmap({}, [2, 4]). -Expression has type: [dynamic()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:102:22 - │ -102 │ test13_neg() -> lmap({}, [2, 4]). - │ ^^ {}. -Expression has type: {} -Context expected type: fun((A) -> B) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:102:22 - │ -102 │ test13_neg() -> lmap({}, [2, 4]). - │ ^^ {}. -Expression has type: {} -Context expected type: fun((number()) -> dynamic()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:105:18 - │ -105 │ test13b_neg() -> mapl([2, 4], {}). - │ ^^^^^^^^^^^^^^^^ mapl([2, 4], {}). -Expression has type: [dynamic()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:105:31 - │ -105 │ test13b_neg() -> mapl([2, 4], {}). - │ ^^ {}. -Expression has type: {} -Context expected type: fun((number()) -> B) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:105:31 - │ -105 │ test13b_neg() -> mapl([2, 4], {}). - │ ^^ {}. -Expression has type: {} -Context expected type: fun((number()) -> dynamic()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:119:5 - │ -119 │ F(Shape). - │ ^^^^^^^^ F(Shape). -Expression has type: T -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:119:7 - │ -119 │ F(Shape). - │ ^^^^^ - │ │ - │ Shape. -Expression has type: #{a => number()} -Context expected type: #{atom() => T} - │ - -Because in the expression's type: - #{ a => - Here the type is: number() - 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 - │ -126 │ F(Tuple). - │ ^^^^^^^^ F(Tuple). -Expression has type: X -Context expected type: 'false' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:130:5 - │ -130 │ lmap(F, [2, 4]). - │ ^^^^^^^^^^^^^^^ lmap(F, [2, 4]). -Expression has type: [dynamic()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:134:5 - │ -134 │ mapl([2, 4], F). - │ ^^^^^^^^^^^^^^^ mapl([2, 4], F). -Expression has type: [dynamic()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:144:5 - │ -144 │ ttt(AB, a). - │ ^^^^^^^^^^ - │ │ - │ ttt(AB, 'a'). -Expression has type: 'a' | 'b' -Context expected type: 'a' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'a' - 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 - │ -157 │ ttt(a, b). - │ ^^^^^^^^^ ttt('a', 'b'). -Expression has type: 'a' | 'b' -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:167:5 - │ -167 │ ttt(a, b). - │ ^^^^^^^^^ - │ │ - │ ttt('a', 'b'). -Expression has type: 'a' | 'b' -Context expected type: 'a' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'a' - 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 - │ -172 │ ttt(a, b). - │ ^^^^^^^^^ - │ │ - │ ttt('a', 'b'). -Expression has type: 'a' | 'b' -Context expected type: 'b' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'b' - 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 - │ -226 │ ╭ test31_pos(Any, None) -> -227 │ │ X = ttt(Any, None), -228 │ │ X. - │ ╰─────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/generic_fun_application.erl:242:1 - │ -242 │ ╭ test33_pos(None, Pid) -> -243 │ │ X = ttt(None, Pid), -244 │ │ X. - │ ╰─────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/generic_fun_application.erl:249:1 - │ -249 │ ╭ test34_pos(None) -> -250 │ │ X=lmap(fun atom_to_pid/1, [None, a]), -251 │ │ X. - │ ╰─────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:258:23 - │ -258 │ test36_neg(F, X) -> F(X). - │ ^ X. -Expression has type: T -Context expected type: {T} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:270:5 - │ -270 │ fun0_id(F). - │ ^^^^^^^^^^ - │ │ - │ fun0_id(F). -Expression has type: fun(() -> A) -Context expected type: fun(() -> X) - │ - -Because in the expression's type: - fun(() -> - Here the type is: A - 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 - │ -276 │ fun0_id(F). - │ ^^^^^^^^^^ fun0_id(F). -Expression has type: fun(() -> dynamic()) -Context expected type: fun((X) -> Y) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:276:13 - │ -276 │ fun0_id(F). - │ ^ F. -Expression has type: fun((A) -> B) -Context expected type: fun(() -> X) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:276:13 - │ -276 │ fun0_id(F). - │ ^ F. -Expression has type: fun((A) -> B) -Context expected type: fun(() -> dynamic()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:288:5 - │ -288 │ X. - │ ^ - │ │ - │ X. -Expression has type: 'first' | Last -Context expected type: 'first' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'first' - 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 - │ -296 │ X. - │ ^ - │ │ - │ X. -Expression has type: atom() | T -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: 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 - │ -322 │ ╭ ╭ expect_shape( -323 │ │ │ #{t => 1, u => Pid} -324 │ │ │ ). - │ ╰─│─────^ expect_shape(#{..}). -Expression has type: {number(), pid()} -Context expected type: {pid(), number()} - │ ╰─────' - -Because in the expression's type: - { - Here the type is: number() - 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 - │ -330 │ F(A). - │ ^^^^ F(A). -Expression has type: B -Context expected type: C - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:346:9 - │ -346 │ fun fun1_id_pos_a/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_a/1'. -Expression has type: fun((Z) -> Z) with 1 type parameter -Context expected type: fun((A) -> A) with 0 type parameters - │ - -Because in the expression's type: - Here the type is: fun((Z) -> Z) with 1 type parameter - Context expects type: fun((A) -> A) 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/generic_fun_application.erl:346:9 - │ -346 │ fun fun1_id_pos_a/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_a/1'. -Expression has type: fun((Z) -> Z) with 1 type parameter -Context expected type: fun((dynamic()) -> dynamic()) with 0 type parameters - │ - -Because in the expression's type: - Here the type is: fun((Z) -> Z) with 1 type parameter - Context expects type: fun((dynamic()) -> dynamic()) 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/generic_fun_application.erl:346:9 - │ -346 │ fun fun1_id_pos_a/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_a/1'. -Expression has type: fun((Z) -> Z) | fun((dynamic()) -> dynamic()) -Context expected type: fun((A) -> A) - │ - -Because in the expression's type: - The type is a union type with some valid candidates: fun((dynamic()) -> dynamic()) - However, the following candidate doesn't match: - Here the type is: fun((Z) -> Z) with 1 type parameter - 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 - │ -346 │ fun fun1_id_pos_a/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_a/1'. -Expression has type: fun((Z) -> Z) | fun((dynamic()) -> dynamic()) -Context expected type: fun((dynamic()) -> dynamic()) - │ - -Because in the expression's type: - The type is a union type with some valid candidates: fun((dynamic()) -> dynamic()) - However, the following candidate doesn't match: - Here the type is: fun((Z) -> Z) with 1 type parameter - 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 - │ -346 │ fun fun1_id_pos_a/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_a/1'. -Expression has type: fun((Z) -> Z) | fun((dynamic()) -> dynamic()) -Context expected type: fun((A) -> A) - │ - -Because in the expression's type: - The type is a union type with some valid candidates: fun((dynamic()) -> dynamic()) - However, the following candidate doesn't match: - Here the type is: fun((Z) -> Z) with 1 type parameter - 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 - │ -358 │ fun fun1_id_pos_z/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_z/1'. -Expression has type: fun((Z) -> Z) with 1 type parameter -Context expected type: fun((Z) -> Z) with 0 type parameters - │ - -Because in the expression's type: - Here the type is: fun((Z) -> Z) with 1 type parameter - Context expects type: fun((Z) -> Z) 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/generic_fun_application.erl:358:9 - │ -358 │ fun fun1_id_pos_z/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_z/1'. -Expression has type: fun((Z) -> Z) with 1 type parameter -Context expected type: fun((dynamic()) -> dynamic()) with 0 type parameters - │ - -Because in the expression's type: - Here the type is: fun((Z) -> Z) with 1 type parameter - Context expects type: fun((dynamic()) -> dynamic()) 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/generic_fun_application.erl:358:9 - │ -358 │ fun fun1_id_pos_z/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_z/1'. -Expression has type: fun((Z) -> Z) | fun((dynamic()) -> dynamic()) -Context expected type: fun((Z) -> Z) - │ - -Because in the expression's type: - The type is a union type with some valid candidates: fun((dynamic()) -> dynamic()) - However, the following candidate doesn't match: - Here the type is: fun((Z) -> Z) with 1 type parameter - 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 - │ -358 │ fun fun1_id_pos_z/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_z/1'. -Expression has type: fun((Z) -> Z) | fun((dynamic()) -> dynamic()) -Context expected type: fun((dynamic()) -> dynamic()) - │ - -Because in the expression's type: - The type is a union type with some valid candidates: fun((dynamic()) -> dynamic()) - However, the following candidate doesn't match: - Here the type is: fun((Z) -> Z) with 1 type parameter - 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 - │ -358 │ fun fun1_id_pos_z/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_z/1'. -Expression has type: fun((Z) -> Z) | fun((dynamic()) -> dynamic()) -Context expected type: fun((Z) -> Z) - │ - -Because in the expression's type: - The type is a union type with some valid candidates: fun((dynamic()) -> dynamic()) - However, the following candidate doesn't match: - Here the type is: fun((Z) -> Z) with 1 type parameter - 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 - │ -432 │ test_dict1(D) -> num_and_t(D, D). - │ ^^^^^^^^^^^^^^^ num_and_t(D, D). -Expression has type: #{atom() => pid()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:432:28 - │ -432 │ test_dict1(D) -> num_and_t(D, D). - │ ^ D. -Expression has type: #{atom() => pid()} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:441:5 - │ -441 │ shape_vars(#{T => 3}, 3). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ shape_vars(#{..}, 3). -Expression has type: 'ok' -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:441:16 - │ -441 │ shape_vars(#{T => 3}, 3). - │ ^^^^^^^^^ - │ │ - │ #{..}. -Expression has type: #{T => number()} -Context expected type: #{a := T} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -441 │ shape_vars(#{T => 3}, 3). - │ ^^^^^^^^^ - │ │ - │ #{..}. -Expression has type: #{T => number()} -Context expected type: #{a := term()} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -446 │ dict_vars(F, N). - │ ^ - │ │ - │ F. -Expression has type: fun((#{a => number()}) -> number()) -Context expected type: fun((#{{T} => T}) -> T) - │ - -Because in the expression's type: - fun((#{a => number()}) -> - Here the type is: number() - 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 - │ -446 │ dict_vars(F, N). - │ ^ - │ │ - │ F. -Expression has type: fun((#{a => number()}) -> number()) -Context expected type: fun((#{{number()} => number()}) -> number()) - │ - -Because in the expression's type: - fun(( - Here the type is: #{{number()} => number()} - Context expects type: #{...} (no default association) - 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 - │ -471 │ test_aliases_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun(('a') -> 'b') -Context expected type: fun(('a') -> 'c') - │ - -Because in the expression's type: - fun(('a') -> - Here the type is: 'b' - 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 - │ -478 │ takesShape1(#{}). - │ ^^^ - │ │ - │ #{..}. -Expression has type: #{} -Context expected type: #{a := T} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -478 │ takesShape1(#{}). - │ ^^^ - │ │ - │ #{..}. -Expression has type: #{} -Context expected type: #{a := dynamic()} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -500 │ test_quanitifer_scope_neg(F, X) -> F(X). - │ ^^^^ F(X). -Expression has type: T -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:500:38 - │ -500 │ test_quanitifer_scope_neg(F, X) -> F(X). - │ ^ X. -Expression has type: number() -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:551:5 - │ -551 │ X. - │ ^ - │ │ - │ X. -Expression has type: contravar(contravar('a' | 'b')) -Context expected type: contravar(contravar('a')) - │ - -Because in the expression's type: - fun(( - fun(( - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - Differs from the expected type: 'a' - ) -> '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 - │ -563 │ X. - │ ^ - │ │ - │ X. -Expression has type: invar('a') -Context expected type: fun((atom()) -> atom()) - │ - -Because in the expression's type: - fun(( - Here the type is: atom() - 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 - │ -569 │ X. - │ ^ - │ │ - │ X. -Expression has type: invar('a') -Context expected type: invar(atom()) - │ - -Because in the expression's type: - fun(( - Here the type is: atom() - 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 - │ -585 │ a. - │ ^ - │ │ - │ 'a'. -Expression has type: 'a' -Context expected type: invar('a') - │ - -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 - │ -625 │ stuff_1(0) -> erlang:self(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/generic_fun_application.erl:633:1 - │ -633 │ stuff_2(0) -> erlang:self(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/generic_fun_application.erl:645:5 - │ -645 │ F(1, 2), - │ ^ F. -Expected fun type with arity 2 -Got: fun((Z) -> Z) - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/generic_fun_application.erl:651:5 - │ -651 │ F(1, 2). - │ ^ F. -Expected fun type with arity 2 -Got: fun((Z) -> Z) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:684:9 - │ -684 │ #{u => 1, t => Pid, extra => 3} - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #{..}. -Expression has type: #{extra := number(), t := pid(), u := number()} -Context expected type: #{t := pid(), u := number()} - │ - -Because in the expression's type: - Here the type is: #{extra := ...} - 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 - │ -721 │ test_apply2() -> apply2(fun tat/2, 1, 1). - │ ^^^^^^^^^ Arg 2 of 'tat/2'. -Expression has type: number() -Context expected type: 'a' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:739:5 - │ -739 │ invar(a, a). - │ ^^^^^^^^^^^ - │ │ - │ invar('a', 'a'). -Expression has type: fun(('a') -> 'a') -Context expected type: fun(('a' | 'b') -> 'a' | 'b') - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -752 │ _ = fun_with_tuple({a, b}, {}), - │ ^^ {}. -Expression has type: {} -Context expected type: [A] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:752:32 - │ -752 │ _ = fun_with_tuple({a, b}, {}), - │ ^^ {}. -Expression has type: {} -Context expected type: [dynamic()] - -81 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application-OTP-28.pretty deleted file mode 100644 index c10af08c9d..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application-OTP-28.pretty +++ /dev/null @@ -1,1232 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:27:18 - │ -27 │ test01_neg(X) -> fapply(fun id/1, X). - │ ^^^^^^^^^^^^^^^^^^^ fapply(id/1, X). -Expression has type: atom() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:38:5 - │ -38 │ lmap(fun atom_to_pid/1, [2, 4]). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lmap(atom_to_pid/1, [2, 4]). -Expression has type: [pid()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:38:29 - │ -38 │ lmap(fun atom_to_pid/1, [2, 4]). - │ ^^^^^^ - │ │ - │ [2, 4]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -38 │ lmap(fun atom_to_pid/1, [2, 4]). - │ ^^^^^^ - │ │ - │ [2, 4]. -Expression has type: [number()] -Context expected type: [dynamic(atom())] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -43 │ mapl([2, 4], fun atom_to_pid/1). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mapl([2, 4], atom_to_pid/1). -Expression has type: [pid()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:43:18 - │ -43 │ mapl([2, 4], fun atom_to_pid/1). - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ atom_to_pid/1. -Expression has type: fun((atom()) -> pid()) -Context expected type: fun((number()) -> B) - │ - -Because in the expression's type: - fun((atom()) -> - Here the type is: pid() - 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 - │ -43 │ mapl([2, 4], fun atom_to_pid/1). - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ atom_to_pid/1. -Expression has type: fun((atom()) -> pid()) -Context expected type: fun((dynamic() | number()) -> pid()) - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: dynamic() - However the following candidate: number() - 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 - │ -47 │ X = lmap(fun atom_to_pid/1, [2, 4]), - │ ^^^^^^ - │ │ - │ [2, 4]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -47 │ X = lmap(fun atom_to_pid/1, [2, 4]), - │ ^^^^^^ - │ │ - │ [2, 4]. -Expression has type: [number()] -Context expected type: [dynamic(atom())] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -48 │ X. - │ ^ X. -Expression has type: [pid()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:52:22 - │ -52 │ X = mapl([2, 4], fun atom_to_pid/1), - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ atom_to_pid/1. -Expression has type: fun((atom()) -> pid()) -Context expected type: fun((number()) -> B) - │ - -Because in the expression's type: - fun((atom()) -> - Here the type is: pid() - 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 - │ -52 │ X = mapl([2, 4], fun atom_to_pid/1), - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ atom_to_pid/1. -Expression has type: fun((atom()) -> pid()) -Context expected type: fun((dynamic() | number()) -> pid()) - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: dynamic() - However the following candidate: number() - 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 - │ -53 │ X. - │ ^ X. -Expression has type: [pid()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:67:23 - │ -67 │ test08_neg() -> lhead(h). - │ ^ 'h'. -Expression has type: 'h' -Context expected type: [LH] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:67:23 - │ -67 │ test08_neg() -> lhead(h). - │ ^ 'h'. -Expression has type: 'h' -Context expected type: [dynamic()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:80:18 - │ -80 │ test09_neg(M) -> maptt(M). - │ ^^^^^^^^ maptt(M). -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:95:13 - │ -95 │ map_att(M). - │ ^ - │ │ - │ M. -Expression has type: #{true => pid()} -Context expected type: #{a => dynamic()} - │ - -Because in the expression's type: - Here the type is: #{true => ...} - 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 - │ -99 │ map_att(3). - │ ^ 3. -Expression has type: number() -Context expected type: #{a => T} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:99:13 - │ -99 │ map_att(3). - │ ^ 3. -Expression has type: number() -Context expected type: #{a => dynamic()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:102:17 - │ -102 │ test13_neg() -> lmap({}, [2, 4]). - │ ^^^^^^^^^^^^^^^^ lmap({}, [2, 4]). -Expression has type: [dynamic()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:102:22 - │ -102 │ test13_neg() -> lmap({}, [2, 4]). - │ ^^ {}. -Expression has type: {} -Context expected type: fun((A) -> B) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:102:22 - │ -102 │ test13_neg() -> lmap({}, [2, 4]). - │ ^^ {}. -Expression has type: {} -Context expected type: fun((number()) -> dynamic()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:105:18 - │ -105 │ test13b_neg() -> mapl([2, 4], {}). - │ ^^^^^^^^^^^^^^^^ mapl([2, 4], {}). -Expression has type: [dynamic()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:105:31 - │ -105 │ test13b_neg() -> mapl([2, 4], {}). - │ ^^ {}. -Expression has type: {} -Context expected type: fun((number()) -> B) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:105:31 - │ -105 │ test13b_neg() -> mapl([2, 4], {}). - │ ^^ {}. -Expression has type: {} -Context expected type: fun((number()) -> dynamic()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:119:5 - │ -119 │ F(Shape). - │ ^^^^^^^^ F(Shape). -Expression has type: T -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:119:7 - │ -119 │ F(Shape). - │ ^^^^^ - │ │ - │ Shape. -Expression has type: #{a => number()} -Context expected type: #{atom() => T} - │ - -Because in the expression's type: - #{ a => - Here the type is: number() - 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 - │ -126 │ F(Tuple). - │ ^^^^^^^^ F(Tuple). -Expression has type: X -Context expected type: 'false' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:130:5 - │ -130 │ lmap(F, [2, 4]). - │ ^^^^^^^^^^^^^^^ lmap(F, [2, 4]). -Expression has type: [dynamic()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:134:5 - │ -134 │ mapl([2, 4], F). - │ ^^^^^^^^^^^^^^^ mapl([2, 4], F). -Expression has type: [dynamic()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:144:5 - │ -144 │ ttt(AB, a). - │ ^^^^^^^^^^ - │ │ - │ ttt(AB, 'a'). -Expression has type: 'a' | 'b' -Context expected type: 'a' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'a' - 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 - │ -157 │ ttt(a, b). - │ ^^^^^^^^^ ttt('a', 'b'). -Expression has type: 'a' | 'b' -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:167:5 - │ -167 │ ttt(a, b). - │ ^^^^^^^^^ - │ │ - │ ttt('a', 'b'). -Expression has type: 'a' | 'b' -Context expected type: 'a' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'a' - 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 - │ -172 │ ttt(a, b). - │ ^^^^^^^^^ - │ │ - │ ttt('a', 'b'). -Expression has type: 'a' | 'b' -Context expected type: 'b' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'b' - 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 - │ -226 │ ╭ test31_pos(Any, None) -> -227 │ │ X = ttt(Any, None), -228 │ │ X. - │ ╰─────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/generic_fun_application.erl:242:1 - │ -242 │ ╭ test33_pos(None, Pid) -> -243 │ │ X = ttt(None, Pid), -244 │ │ X. - │ ╰─────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/generic_fun_application.erl:249:1 - │ -249 │ ╭ test34_pos(None) -> -250 │ │ X=lmap(fun atom_to_pid/1, [None, a]), -251 │ │ X. - │ ╰─────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:258:23 - │ -258 │ test36_neg(F, X) -> F(X). - │ ^ X. -Expression has type: T -Context expected type: {T} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:270:5 - │ -270 │ fun0_id(F). - │ ^^^^^^^^^^ - │ │ - │ fun0_id(F). -Expression has type: fun(() -> A) -Context expected type: fun(() -> X) - │ - -Because in the expression's type: - fun(() -> - Here the type is: A - 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 - │ -276 │ fun0_id(F). - │ ^^^^^^^^^^ fun0_id(F). -Expression has type: fun(() -> dynamic()) -Context expected type: fun((X) -> Y) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:276:13 - │ -276 │ fun0_id(F). - │ ^ F. -Expression has type: fun((A) -> B) -Context expected type: fun(() -> X) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:276:13 - │ -276 │ fun0_id(F). - │ ^ F. -Expression has type: fun((A) -> B) -Context expected type: fun(() -> dynamic()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:288:5 - │ -288 │ X. - │ ^ - │ │ - │ X. -Expression has type: 'first' | Last -Context expected type: 'first' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'first' - 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 - │ -296 │ X. - │ ^ - │ │ - │ X. -Expression has type: atom() | T -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: 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 - │ -322 │ ╭ ╭ expect_shape( -323 │ │ │ #{t => 1, u => Pid} -324 │ │ │ ). - │ ╰─│─────^ expect_shape(#{..}). -Expression has type: {number(), pid()} -Context expected type: {pid(), number()} - │ ╰─────' - -Because in the expression's type: - { - Here the type is: number() - 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 - │ -330 │ F(A). - │ ^^^^ F(A). -Expression has type: B -Context expected type: C - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:346:9 - │ -346 │ fun fun1_id_pos_a/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_a/1'. -Expression has type: fun((Z) -> Z) with 1 type parameter -Context expected type: fun((A) -> A) with 0 type parameters - │ - -Because in the expression's type: - Here the type is: fun((Z) -> Z) with 1 type parameter - Context expects type: fun((A) -> A) 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/generic_fun_application.erl:346:9 - │ -346 │ fun fun1_id_pos_a/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_a/1'. -Expression has type: fun((Z) -> Z) with 1 type parameter -Context expected type: fun((dynamic()) -> dynamic()) with 0 type parameters - │ - -Because in the expression's type: - Here the type is: fun((Z) -> Z) with 1 type parameter - Context expects type: fun((dynamic()) -> dynamic()) 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/generic_fun_application.erl:346:9 - │ -346 │ fun fun1_id_pos_a/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_a/1'. -Expression has type: fun((Z) -> Z) | fun((dynamic()) -> dynamic()) -Context expected type: fun((A) -> A) - │ - -Because in the expression's type: - The type is a union type with some valid candidates: fun((dynamic()) -> dynamic()) - However, the following candidate doesn't match: - Here the type is: fun((Z) -> Z) with 1 type parameter - 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 - │ -346 │ fun fun1_id_pos_a/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_a/1'. -Expression has type: fun((Z) -> Z) | fun((dynamic()) -> dynamic()) -Context expected type: fun((dynamic()) -> dynamic()) - │ - -Because in the expression's type: - The type is a union type with some valid candidates: fun((dynamic()) -> dynamic()) - However, the following candidate doesn't match: - Here the type is: fun((Z) -> Z) with 1 type parameter - 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 - │ -346 │ fun fun1_id_pos_a/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_a/1'. -Expression has type: fun((Z) -> Z) | fun((dynamic()) -> dynamic()) -Context expected type: fun((A) -> A) - │ - -Because in the expression's type: - The type is a union type with some valid candidates: fun((dynamic()) -> dynamic()) - However, the following candidate doesn't match: - Here the type is: fun((Z) -> Z) with 1 type parameter - 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 - │ -358 │ fun fun1_id_pos_z/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_z/1'. -Expression has type: fun((Z) -> Z) with 1 type parameter -Context expected type: fun((Z) -> Z) with 0 type parameters - │ - -Because in the expression's type: - Here the type is: fun((Z) -> Z) with 1 type parameter - Context expects type: fun((Z) -> Z) 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/generic_fun_application.erl:358:9 - │ -358 │ fun fun1_id_pos_z/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_z/1'. -Expression has type: fun((Z) -> Z) with 1 type parameter -Context expected type: fun((dynamic()) -> dynamic()) with 0 type parameters - │ - -Because in the expression's type: - Here the type is: fun((Z) -> Z) with 1 type parameter - Context expects type: fun((dynamic()) -> dynamic()) 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/generic_fun_application.erl:358:9 - │ -358 │ fun fun1_id_pos_z/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_z/1'. -Expression has type: fun((Z) -> Z) | fun((dynamic()) -> dynamic()) -Context expected type: fun((Z) -> Z) - │ - -Because in the expression's type: - The type is a union type with some valid candidates: fun((dynamic()) -> dynamic()) - However, the following candidate doesn't match: - Here the type is: fun((Z) -> Z) with 1 type parameter - 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 - │ -358 │ fun fun1_id_pos_z/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_z/1'. -Expression has type: fun((Z) -> Z) | fun((dynamic()) -> dynamic()) -Context expected type: fun((dynamic()) -> dynamic()) - │ - -Because in the expression's type: - The type is a union type with some valid candidates: fun((dynamic()) -> dynamic()) - However, the following candidate doesn't match: - Here the type is: fun((Z) -> Z) with 1 type parameter - 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 - │ -358 │ fun fun1_id_pos_z/1), - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ Arg 1 of 'fun1_id_pos_z/1'. -Expression has type: fun((Z) -> Z) | fun((dynamic()) -> dynamic()) -Context expected type: fun((Z) -> Z) - │ - -Because in the expression's type: - The type is a union type with some valid candidates: fun((dynamic()) -> dynamic()) - However, the following candidate doesn't match: - Here the type is: fun((Z) -> Z) with 1 type parameter - 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 - │ -432 │ test_dict1(D) -> num_and_t(D, D). - │ ^^^^^^^^^^^^^^^ num_and_t(D, D). -Expression has type: #{atom() => pid()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:432:28 - │ -432 │ test_dict1(D) -> num_and_t(D, D). - │ ^ D. -Expression has type: #{atom() => pid()} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:441:5 - │ -441 │ shape_vars(#{T => 3}, 3). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ shape_vars(#{..}, 3). -Expression has type: 'ok' -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:441:16 - │ -441 │ shape_vars(#{T => 3}, 3). - │ ^^^^^^^^^ - │ │ - │ #{..}. -Expression has type: #{T => number()} -Context expected type: #{a := T} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -441 │ shape_vars(#{T => 3}, 3). - │ ^^^^^^^^^ - │ │ - │ #{..}. -Expression has type: #{T => number()} -Context expected type: #{a := term()} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -446 │ dict_vars(F, N). - │ ^ - │ │ - │ F. -Expression has type: fun((#{a => number()}) -> number()) -Context expected type: fun((#{{T} => T}) -> T) - │ - -Because in the expression's type: - fun((#{a => number()}) -> - Here the type is: number() - 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 - │ -446 │ dict_vars(F, N). - │ ^ - │ │ - │ F. -Expression has type: fun((#{a => number()}) -> number()) -Context expected type: fun((#{{number()} => number()}) -> number()) - │ - -Because in the expression's type: - fun(( - Here the type is: #{{number()} => number()} - Context expects type: #{...} (no default association) - 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 - │ -471 │ test_aliases_neg(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun(('a') -> 'b') -Context expected type: fun(('a') -> 'c') - │ - -Because in the expression's type: - fun(('a') -> - Here the type is: 'b' - 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 - │ -478 │ takesShape1(#{}). - │ ^^^ - │ │ - │ #{..}. -Expression has type: #{} -Context expected type: #{a := T} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -478 │ takesShape1(#{}). - │ ^^^ - │ │ - │ #{..}. -Expression has type: #{} -Context expected type: #{a := dynamic()} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -500 │ test_quanitifer_scope_neg(F, X) -> F(X). - │ ^^^^ F(X). -Expression has type: T -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:500:38 - │ -500 │ test_quanitifer_scope_neg(F, X) -> F(X). - │ ^ X. -Expression has type: number() -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:551:5 - │ -551 │ X. - │ ^ - │ │ - │ X. -Expression has type: contravar(contravar('a' | 'b')) -Context expected type: contravar(contravar('a')) - │ - -Because in the expression's type: - fun(( - fun(( - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - Differs from the expected type: 'a' - ) -> '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 - │ -563 │ X. - │ ^ - │ │ - │ X. -Expression has type: invar('a') -Context expected type: fun((atom()) -> atom()) - │ - -Because in the expression's type: - fun(( - Here the type is: atom() - 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 - │ -569 │ X. - │ ^ - │ │ - │ X. -Expression has type: invar('a') -Context expected type: invar(atom()) - │ - -Because in the expression's type: - fun(( - Here the type is: atom() - 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 - │ -585 │ a. - │ ^ - │ │ - │ 'a'. -Expression has type: 'a' -Context expected type: invar('a') - │ - -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 - │ -625 │ stuff_1(0) -> erlang:self(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/generic_fun_application.erl:633:1 - │ -633 │ stuff_2(0) -> erlang:self(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/generic_fun_application.erl:645:5 - │ -645 │ F(1, 2), - │ ^ F. -Expected fun type with arity 2 -Got: fun((Z) -> Z) - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/generic_fun_application.erl:651:5 - │ -651 │ F(1, 2). - │ ^ F. -Expected fun type with arity 2 -Got: fun((Z) -> Z) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:684:9 - │ -684 │ #{u => 1, t => Pid, extra => 3} - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #{..}. -Expression has type: #{extra := number(), t := pid(), u := number()} -Context expected type: #{t := pid(), u := number()} - │ - -Because in the expression's type: - Here the type is: #{extra := ...} - 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 - │ -721 │ test_apply2() -> apply2(fun tat/2, 1, 1). - │ ^^^^^^^^^ Arg 2 of 'tat/2'. -Expression has type: number() -Context expected type: 'a' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:739:5 - │ -739 │ invar(a, a). - │ ^^^^^^^^^^^ - │ │ - │ invar('a', 'a'). -Expression has type: fun(('a') -> 'a') -Context expected type: fun(('a' | 'b') -> 'a' | 'b') - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -752 │ _ = fun_with_tuple({a, b}, {}), - │ ^^ {}. -Expression has type: {} -Context expected type: [A] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generic_fun_application.erl:752:32 - │ -752 │ _ = fun_with_tuple({a, b}, {}), - │ ^^ {}. -Expression has type: {} -Context expected type: [dynamic()] - -81 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application.pretty similarity index 80% rename from crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application.pretty index c10af08c9d..ae03bc49c8 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application-OTP-26.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/generic_fun_application.pretty @@ -31,12 +31,6 @@ 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 │ @@ -54,14 +48,6 @@ 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 │ @@ -87,12 +73,6 @@ 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 │ @@ -111,14 +91,6 @@ 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 │ @@ -136,12 +108,6 @@ 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 │ @@ -159,14 +125,6 @@ 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 │ @@ -192,12 +150,6 @@ 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 │ @@ -216,14 +168,6 @@ 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 │ @@ -272,10 +216,6 @@ 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 │ @@ -365,15 +305,6 @@ 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 │ @@ -414,12 +345,6 @@ 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 │ @@ -444,12 +369,6 @@ 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 │ @@ -466,12 +385,6 @@ 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 │ @@ -521,12 +434,6 @@ 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 │ @@ -567,12 +474,6 @@ 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 │ @@ -589,12 +490,6 @@ 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 │ @@ -612,13 +507,6 @@ 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 │ @@ -677,12 +565,6 @@ 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 │ @@ -701,12 +583,6 @@ 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 │ @@ -725,12 +601,6 @@ 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 │ @@ -781,12 +651,6 @@ 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 │ @@ -805,12 +669,6 @@ 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 │ @@ -829,12 +687,6 @@ 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 │ @@ -875,10 +727,6 @@ 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 │ @@ -895,10 +743,6 @@ 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 │ @@ -916,12 +760,6 @@ 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 │ @@ -940,15 +778,6 @@ 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 │ @@ -966,12 +795,6 @@ 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 │ @@ -988,10 +811,6 @@ 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 │ @@ -1008,10 +827,6 @@ 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 │ @@ -1048,16 +863,6 @@ 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 │ @@ -1075,14 +880,6 @@ 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 │ @@ -1100,16 +897,6 @@ 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 │ @@ -1125,12 +912,6 @@ 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 │ @@ -1175,10 +956,6 @@ 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 │ @@ -1205,14 +982,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/generics_with_unions-OTP-26.pretty deleted file mode 100644 index 53cd1350ec..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/generics_with_unions-OTP-26.pretty +++ /dev/null @@ -1,249 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:17:18 - │ -17 │ test02_neg(X) -> {X, X}. - │ ^^^^^^ - │ │ - │ {X, X}. -Expression has type: {T | U, T | U} -Context expected type: {T, U} - │ - -Because in the expression's type: - { - Here the type is a union type with some valid candidates: T - However the following candidate: U - 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 - │ -70 │ test_ret_neg() -> union(a, b). - │ ^^^^^^^^^^^ union('a', 'b'). -Expression has type: 'a' | 'b' -Context expected type: 'ok' - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ check/src/generics_with_unions.erl:72:1 - │ -72 │ -type ty_var_from_nowhere() :: _T. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _T: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/generics_with_unions.erl:74:1 - │ -74 │ ╭ -spec test_uses_ty_var_from_nowhere -75 │ │ (pid() | ty_var_from_nowhere()) -76 │ │ -> nok. - │ ╰──────────^ test_uses_ty_var_from_nowhere/1 references type with invalid definition: ty_var_from_nowhere/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:132:5 - │ -132 │ set_list([{a, 5}], [{a, 5}]). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ set_list([{'a', 5}], [{'a', 5}]). -Expression has type: props('a', number()) -Context expected type: 'wrong_ret' - │ - -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 - │ -217 │ overlap_1([T]) -> T; - │ ^ T. -Expression has type: term() -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:218:17 - │ -218 │ overlap_1(T) -> T. - │ ^ - │ │ - │ T. -Expression has type: [T] | T -Context expected type: T - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: T - 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 - │ -221 │ overlap_2(T) -> T; - │ ^ - │ │ - │ T. -Expression has type: T | [T] -Context expected type: T - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: T - 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 - │ -222 │ overlap_2([T]) -> T. - │ ^ T. -Expression has type: term() -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:230:5 - │ -230 │ overlap_2([ok]). - │ ^^^^^^^^^^^^^^^ overlap_2(['ok']). -Expression has type: 'ok' -Context expected type: ['ok'] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:233:18 - │ -233 │ trick(_, {B}) -> B. - │ ^ B. -Expression has type: term() -Context expected type: B - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:256:5 - │ -256 │ Default; - │ ^^^^^^^ Default. -Expression has type: term() -Context expected type: Value - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:328:29 - │ -328 │ overlapping_union_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: [K] | [[K]] -Context expected type: [K] - │ - -Because in the expression's type: - The type is a union type with some valid candidates: [K] - However, the following candidate doesn't match: - [ - Here the type is: [K] - 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 - │ -332 │ _ = overlapping_union_neg([]), - │ ^^ []. -Expression has type [] which matches multiple generic types in [K] | [[K]] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:379:28 - │ -379 │ Q2 = where1({i, atom}, Q), - │ ^ - │ │ - │ Q. -Expression has type: query() -Context expected type: fun(({'i', 'atom'}) -> 'ok') - │ - -Because in the expression's type: - fun(( - { 'i', - Here the type is: 'atom' - Context expects type: number() - } - ) -> '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 - │ -392 │ Q2 = where2(Q, {a, 123}), - │ ^ - │ │ - │ Q. -Expression has type: query() -Context expected type: fun(({'a', number()}) -> 'ok') - │ - -Because in the expression's type: - fun(( - { 'a', - Here the type is: number() - Context expects type: atom() - } - ) -> '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/generics_with_unions-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/generics_with_unions-OTP-28.pretty deleted file mode 100644 index 53cd1350ec..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/generics_with_unions-OTP-28.pretty +++ /dev/null @@ -1,249 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:17:18 - │ -17 │ test02_neg(X) -> {X, X}. - │ ^^^^^^ - │ │ - │ {X, X}. -Expression has type: {T | U, T | U} -Context expected type: {T, U} - │ - -Because in the expression's type: - { - Here the type is a union type with some valid candidates: T - However the following candidate: U - 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 - │ -70 │ test_ret_neg() -> union(a, b). - │ ^^^^^^^^^^^ union('a', 'b'). -Expression has type: 'a' | 'b' -Context expected type: 'ok' - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ check/src/generics_with_unions.erl:72:1 - │ -72 │ -type ty_var_from_nowhere() :: _T. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _T: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/generics_with_unions.erl:74:1 - │ -74 │ ╭ -spec test_uses_ty_var_from_nowhere -75 │ │ (pid() | ty_var_from_nowhere()) -76 │ │ -> nok. - │ ╰──────────^ test_uses_ty_var_from_nowhere/1 references type with invalid definition: ty_var_from_nowhere/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:132:5 - │ -132 │ set_list([{a, 5}], [{a, 5}]). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ set_list([{'a', 5}], [{'a', 5}]). -Expression has type: props('a', number()) -Context expected type: 'wrong_ret' - │ - -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 - │ -217 │ overlap_1([T]) -> T; - │ ^ T. -Expression has type: term() -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:218:17 - │ -218 │ overlap_1(T) -> T. - │ ^ - │ │ - │ T. -Expression has type: [T] | T -Context expected type: T - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: T - 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 - │ -221 │ overlap_2(T) -> T; - │ ^ - │ │ - │ T. -Expression has type: T | [T] -Context expected type: T - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: T - 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 - │ -222 │ overlap_2([T]) -> T. - │ ^ T. -Expression has type: term() -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:230:5 - │ -230 │ overlap_2([ok]). - │ ^^^^^^^^^^^^^^^ overlap_2(['ok']). -Expression has type: 'ok' -Context expected type: ['ok'] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:233:18 - │ -233 │ trick(_, {B}) -> B. - │ ^ B. -Expression has type: term() -Context expected type: B - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:256:5 - │ -256 │ Default; - │ ^^^^^^^ Default. -Expression has type: term() -Context expected type: Value - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:328:29 - │ -328 │ overlapping_union_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: [K] | [[K]] -Context expected type: [K] - │ - -Because in the expression's type: - The type is a union type with some valid candidates: [K] - However, the following candidate doesn't match: - [ - Here the type is: [K] - 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 - │ -332 │ _ = overlapping_union_neg([]), - │ ^^ []. -Expression has type [] which matches multiple generic types in [K] | [[K]] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/generics_with_unions.erl:379:28 - │ -379 │ Q2 = where1({i, atom}, Q), - │ ^ - │ │ - │ Q. -Expression has type: query() -Context expected type: fun(({'i', 'atom'}) -> 'ok') - │ - -Because in the expression's type: - fun(( - { 'i', - Here the type is: 'atom' - Context expects type: number() - } - ) -> '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 - │ -392 │ Q2 = where2(Q, {a, 123}), - │ ^ - │ │ - │ Q. -Expression has type: query() -Context expected type: fun(({'a', number()}) -> 'ok') - │ - -Because in the expression's type: - fun(( - { 'a', - Here the type is: number() - Context expects type: atom() - } - ) -> '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/generics_with_unions-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/generics_with_unions.pretty similarity index 77% rename from crates/elp/src/resources/test/eqwalizer_tests/check/generics_with_unions-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/generics_with_unions.pretty index 53cd1350ec..9c03aa9a60 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/generics_with_unions-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/generics_with_unions.pretty @@ -16,15 +16,6 @@ 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 │ @@ -62,12 +53,6 @@ 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 │ @@ -92,12 +77,6 @@ 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 │ @@ -114,12 +93,6 @@ 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 │ @@ -171,14 +144,6 @@ 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 │ @@ -205,17 +170,6 @@ 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 │ @@ -235,15 +189,4 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_bounded-OTP-26.pretty deleted file mode 100644 index bbd9109d68..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_bounded-OTP-26.pretty +++ /dev/null @@ -1,116 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_bounded.erl:16:21 - │ -16 │ bd_unsafe_neg(V) -> V. - │ ^ - │ │ - │ V. -Expression has type: dyn('a') | 'b' -Context expected type: 'c' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dyn('a') - 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 - │ -25 │ bd_coerce_safe_neg(V) -> V. - │ ^ - │ │ - │ V. -Expression has type: 'a' -Context expected type: dyn('b') - │ - -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 - │ -44 │ eqwalizer:reveal_type(V). - │ ^ #{b => dynamic('c'), number() => 'a'} - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_bounded.erl:51:27 - │ -51 │ eqwalizer:reveal_type(V). - │ ^ #{a := 'b', b => dynamic('c')} - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/gradual_bounded.erl:62:1 - │ -62 │ bd_tuple_02({V, _}) -> V. - │ ^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_bounded.erl:66:51 - │ -66 │ bd_distrib_print({a, V}) -> eqwalizer:reveal_type(V). - │ ^ dynamic('b') - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_bounded.erl:79:5 - │ -79 │ bd_generic_fun(test, 42). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ bd_generic_fun('test', 42). -Expression has type: 'test' | 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: '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 - │ -89 │ bd_generic_fun(test, N). - │ ^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ bd_generic_fun('test', N). -Expression has type: 'test' | dyn(number()) -Context expected type: number() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dyn(number()) - 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_bounded-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_bounded-OTP-28.pretty deleted file mode 100644 index bbd9109d68..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_bounded-OTP-28.pretty +++ /dev/null @@ -1,116 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_bounded.erl:16:21 - │ -16 │ bd_unsafe_neg(V) -> V. - │ ^ - │ │ - │ V. -Expression has type: dyn('a') | 'b' -Context expected type: 'c' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dyn('a') - 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 - │ -25 │ bd_coerce_safe_neg(V) -> V. - │ ^ - │ │ - │ V. -Expression has type: 'a' -Context expected type: dyn('b') - │ - -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 - │ -44 │ eqwalizer:reveal_type(V). - │ ^ #{b => dynamic('c'), number() => 'a'} - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_bounded.erl:51:27 - │ -51 │ eqwalizer:reveal_type(V). - │ ^ #{a := 'b', b => dynamic('c')} - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/gradual_bounded.erl:62:1 - │ -62 │ bd_tuple_02({V, _}) -> V. - │ ^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_bounded.erl:66:51 - │ -66 │ bd_distrib_print({a, V}) -> eqwalizer:reveal_type(V). - │ ^ dynamic('b') - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_bounded.erl:79:5 - │ -79 │ bd_generic_fun(test, 42). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ bd_generic_fun('test', 42). -Expression has type: 'test' | 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: '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 - │ -89 │ bd_generic_fun(test, N). - │ ^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ bd_generic_fun('test', N). -Expression has type: 'test' | dyn(number()) -Context expected type: number() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dyn(number()) - 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_bounded-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_bounded.pretty similarity index 78% rename from crates/elp/src/resources/test/eqwalizer_tests/check/gradual_bounded-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/gradual_bounded.pretty index bbd9109d68..1987f06692 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_bounded-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_bounded.pretty @@ -14,12 +14,6 @@ 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 │ @@ -35,16 +29,6 @@ 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 │ @@ -85,12 +69,6 @@ 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 │ @@ -107,10 +85,4 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_complex_types-OTP-26.pretty deleted file mode 100644 index b7111f9239..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_complex_types-OTP-26.pretty +++ /dev/null @@ -1,120 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_complex_types.erl:24:3 - │ -24 │ undefined. - │ ^^^^^^^^^ - │ │ - │ 'undefined'. -Expression has type: 'undefined' -Context expected type: complex_map() - │ - -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 - │ -29 │ eqwalizer:reveal_type(Map), - │ ^^^ complex_map() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_complex_types.erl:35:25 - │ -35 │ eqwalizer:reveal_type(List), - │ ^^^^ [complex_map()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_complex_types.erl:48:16 - │ -48 │ lists:nth(7, Map). - │ ^^^ - │ │ - │ Map. -Expression has type: complex_map() -Context expected type: [T] - │ - -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 - │ -48 │ lists:nth(7, Map). - │ ^^^ - │ │ - │ Map. -Expression has type: complex_map() -Context expected type: [dynamic()] - │ - -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 - │ -55 │ eqwalizer:reveal_type(M1), - │ ^^ #{a := number(), dynamic() => dynamic()} - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_complex_types.erl:63:25 - │ -63 │ eqwalizer:reveal_type(M1), - │ ^^ #{a := number(), dynamic() => dynamic()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_complex_types.erl:110:3 - │ -110 │ generic(DM, S). - │ ^^^^^^^^^^^^^^ generic(DM, S). -Expression has type: dyn_map() | #{a => atom()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_complex_types.erl:115:3 - │ -115 │ {DM, ok}. - │ ^^^^^^^^ - │ │ - │ {DM, 'ok'}. -Expression has type: {dyn_map(), 'ok'} -Context expected type: {#{a => 'atom'}, number()} - │ - -Because in the expression's type: - { dyn_map(), - Here the type is: 'ok' - 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_complex_types-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_complex_types-OTP-28.pretty deleted file mode 100644 index b7111f9239..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_complex_types-OTP-28.pretty +++ /dev/null @@ -1,120 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_complex_types.erl:24:3 - │ -24 │ undefined. - │ ^^^^^^^^^ - │ │ - │ 'undefined'. -Expression has type: 'undefined' -Context expected type: complex_map() - │ - -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 - │ -29 │ eqwalizer:reveal_type(Map), - │ ^^^ complex_map() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_complex_types.erl:35:25 - │ -35 │ eqwalizer:reveal_type(List), - │ ^^^^ [complex_map()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_complex_types.erl:48:16 - │ -48 │ lists:nth(7, Map). - │ ^^^ - │ │ - │ Map. -Expression has type: complex_map() -Context expected type: [T] - │ - -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 - │ -48 │ lists:nth(7, Map). - │ ^^^ - │ │ - │ Map. -Expression has type: complex_map() -Context expected type: [dynamic()] - │ - -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 - │ -55 │ eqwalizer:reveal_type(M1), - │ ^^ #{a := number(), dynamic() => dynamic()} - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_complex_types.erl:63:25 - │ -63 │ eqwalizer:reveal_type(M1), - │ ^^ #{a := number(), dynamic() => dynamic()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_complex_types.erl:110:3 - │ -110 │ generic(DM, S). - │ ^^^^^^^^^^^^^^ generic(DM, S). -Expression has type: dyn_map() | #{a => atom()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_complex_types.erl:115:3 - │ -115 │ {DM, ok}. - │ ^^^^^^^^ - │ │ - │ {DM, 'ok'}. -Expression has type: {dyn_map(), 'ok'} -Context expected type: {#{a => 'atom'}, number()} - │ - -Because in the expression's type: - { dyn_map(), - Here the type is: 'ok' - 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_complex_types-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_complex_types.pretty similarity index 75% rename from crates/elp/src/resources/test/eqwalizer_tests/check/gradual_complex_types-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/gradual_complex_types.pretty index b7111f9239..a7a81c8fb4 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_complex_types-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_complex_types.pretty @@ -13,12 +13,6 @@ 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 │ @@ -46,12 +40,6 @@ 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 │ @@ -67,12 +55,6 @@ 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 │ @@ -110,11 +92,4 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_custom-OTP-26.pretty deleted file mode 100644 index 34e16f1479..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_custom-OTP-26.pretty +++ /dev/null @@ -1,457 +0,0 @@ -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_custom.erl:14:27 - │ -14 │ eqwalizer:reveal_type(element(42, Tup)). - │ ^^^^^^^^^^^^^^^^ dynamic() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_custom.erl:18:27 - │ -18 │ eqwalizer:reveal_type(element(2, Tup)). - │ ^^^^^^^^^^^^^^^ dynamic(atom()) - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_custom.erl:22:27 - │ -22 │ eqwalizer:reveal_type(element(1, Tup)). - │ ^^^^^^^^^^^^^^^ dynamic(number()) - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_custom.erl:26:27 - │ -26 │ eqwalizer:reveal_type(element(1, Tup)). - │ ^^^^^^^^^^^^^^^ dynamic(none()) - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_custom.erl:30:27 - │ -30 │ eqwalizer:reveal_type(element(N, Tup)). - │ ^^^^^^^^^^^^^^^ dynamic(number() | atom()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:43:3 - │ -43 │ application:get_env(app1). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ application:get_env('app1'). -Expression has type: 'undefined' | {'ok', dynamic()} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:56:3 - │ -56 │ application:get_env(app1, key1). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ application:get_env('app1', 'key1'). -Expression has type: 'undefined' | {'ok', dynamic()} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:73:3 - │ -73 │ lists:flatten(In). - │ ^^^^^^^^^^^^^^^^^ lists:flatten(In). -Expression has type: ['b' | 'c' | 'a'] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:85:3 - │ -85 │ lists:flatten(In, Tail). - │ ^^^^^^^^^^^^^^^^^^^^^^^ lists:flatten(In, Tail). -Expression has type: ['b' | 'a' | 'y' | 'z' | 'c' | 'x'] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:94:3 - │ -94 │ 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/gradual_custom.erl:99:3 - │ -99 │ abs(dynamic()). - │ ^^^^^^^^^^^^^^ erlang:abs(dynamic()). -Expression has type: number() -Context expected type: 'anything' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:108:3 - │ -108 │ abs(N). - │ ^^^^^^ erlang:abs(N). -Expression has type: number() -Context expected type: 'anything' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:108:7 - │ -108 │ abs(N). - │ ^ - │ │ - │ N. -Expression has type: dynamic() | 'a' -Context expected type: number() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dynamic() - 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 - │ -120 │ 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/gradual_custom.erl:124:3 - │ -124 │ 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/gradual_custom.erl:124:14 - │ -124 │ 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/gradual_custom.erl:143:16 - │ -143 │ 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/gradual_custom.erl:158:3 - │ -158 │ ╭ maps:without( -159 │ │ [a], -160 │ │ Dyn -161 │ │ ). - │ ╰───^ maps:without(['a'], Dyn). -Expression has type: #{dynamic() => dynamic()} -Context expected type: 'wrong_ret' - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/gradual_custom.erl:166:1 - │ -166 │ ╭ maps_without_3_neg(None) -> -167 │ │ maps:without( -168 │ │ [a, b], -169 │ │ None -170 │ │ ). - │ ╰───^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:185:3 - │ -185 │ ╭ maps:with( -186 │ │ [a], -187 │ │ Dyn -188 │ │ ). - │ ╰───^ maps:with(['a'], Dyn). -Expression has type: #{a := dynamic()} -Context expected type: 'wrong_ret' - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/gradual_custom.erl:193:1 - │ -193 │ ╭ maps_with_3(None) -> -194 │ │ maps:with( -195 │ │ [a, b], -196 │ │ None -197 │ │ ). - │ ╰───^ Clause is not covered by spec - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_custom.erl:203:25 - │ -203 │ eqwalizer:reveal_type(Res), - │ ^^^ file:filename_all() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:204:3 - │ -204 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: file:filename_all() -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is: string() | binary() - 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 - │ -210 │ eqwalizer:reveal_type(Res), - │ ^^^ file:filename_all() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:211:3 - │ -211 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: file:filename_all() -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is: string() | binary() - 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 - │ -217 │ eqwalizer:reveal_type(Res), - │ ^^^ file:filename_all() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:218:3 - │ -218 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: file:filename_all() -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is: string() | binary() - 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 - │ -224 │ eqwalizer:reveal_type(Res), - │ ^^^ file:filename_all() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:225:3 - │ -225 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: file:filename_all() -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is: string() | binary() - 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 - │ -245 │ min3_neg(X, Y) -> min(X, Y). - │ ^^^^^^^^^ - │ │ - │ erlang:min(X, Y). -Expression has type: number() | 'undefined' -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: '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 - │ -257 │ min5_neg(X, Y) -> min(X, Y). - │ ^^^^^^^^^ - │ │ - │ erlang:min(X, Y). -Expression has type: number() | atom() | binary() -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: 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 - │ -263 │ min6_neg(X, Y) -> min(X, Y). - │ ^^^^^^^^^ - │ │ - │ erlang:min(X, Y). -Expression has type: number() | dynamic() | number() | atom() | dynamic() -Context expected type: number() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: number() | dynamic() - 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 - │ -269 │ min7_neg(X, Y) -> min(X, Y). - │ ^^^^^^^^^ - │ │ - │ erlang:min(X, Y). -Expression has type: number() | dynamic() | atom() | dynamic() -Context expected type: number() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: number() | dynamic() - 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 - │ -277 │ eqwalizer:reveal_type(Y), - │ ^ dynamic() | {none()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:278:3 - │ -278 │ Y. - │ ^ - │ │ - │ Y. -Expression has type: dynamic() | {none()} -Context expected type: number() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dynamic() - 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 - │ -325 │ true -> Atom; - │ ^^^^ - │ │ - │ Atom. -Expression has type: 'bar' | 'undefined' | 'foo' -Context expected type: 'foo' | 'bar' | binary() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'bar' | 'foo' - 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 - │ -343 │ parse_atom(Bin, [foo, bar]). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ parse_atom(Bin, ['foo', 'bar']). -Expression has type: 'foo' | 'bar' -Context expected type: 'foo' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'foo' - 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_custom-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_custom-OTP-28.pretty deleted file mode 100644 index 34e16f1479..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_custom-OTP-28.pretty +++ /dev/null @@ -1,457 +0,0 @@ -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_custom.erl:14:27 - │ -14 │ eqwalizer:reveal_type(element(42, Tup)). - │ ^^^^^^^^^^^^^^^^ dynamic() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_custom.erl:18:27 - │ -18 │ eqwalizer:reveal_type(element(2, Tup)). - │ ^^^^^^^^^^^^^^^ dynamic(atom()) - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_custom.erl:22:27 - │ -22 │ eqwalizer:reveal_type(element(1, Tup)). - │ ^^^^^^^^^^^^^^^ dynamic(number()) - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_custom.erl:26:27 - │ -26 │ eqwalizer:reveal_type(element(1, Tup)). - │ ^^^^^^^^^^^^^^^ dynamic(none()) - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_custom.erl:30:27 - │ -30 │ eqwalizer:reveal_type(element(N, Tup)). - │ ^^^^^^^^^^^^^^^ dynamic(number() | atom()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:43:3 - │ -43 │ application:get_env(app1). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ application:get_env('app1'). -Expression has type: 'undefined' | {'ok', dynamic()} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:56:3 - │ -56 │ application:get_env(app1, key1). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ application:get_env('app1', 'key1'). -Expression has type: 'undefined' | {'ok', dynamic()} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:73:3 - │ -73 │ lists:flatten(In). - │ ^^^^^^^^^^^^^^^^^ lists:flatten(In). -Expression has type: ['b' | 'c' | 'a'] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:85:3 - │ -85 │ lists:flatten(In, Tail). - │ ^^^^^^^^^^^^^^^^^^^^^^^ lists:flatten(In, Tail). -Expression has type: ['b' | 'a' | 'y' | 'z' | 'c' | 'x'] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:94:3 - │ -94 │ 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/gradual_custom.erl:99:3 - │ -99 │ abs(dynamic()). - │ ^^^^^^^^^^^^^^ erlang:abs(dynamic()). -Expression has type: number() -Context expected type: 'anything' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:108:3 - │ -108 │ abs(N). - │ ^^^^^^ erlang:abs(N). -Expression has type: number() -Context expected type: 'anything' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:108:7 - │ -108 │ abs(N). - │ ^ - │ │ - │ N. -Expression has type: dynamic() | 'a' -Context expected type: number() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dynamic() - 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 - │ -120 │ 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/gradual_custom.erl:124:3 - │ -124 │ 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/gradual_custom.erl:124:14 - │ -124 │ 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/gradual_custom.erl:143:16 - │ -143 │ 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/gradual_custom.erl:158:3 - │ -158 │ ╭ maps:without( -159 │ │ [a], -160 │ │ Dyn -161 │ │ ). - │ ╰───^ maps:without(['a'], Dyn). -Expression has type: #{dynamic() => dynamic()} -Context expected type: 'wrong_ret' - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/gradual_custom.erl:166:1 - │ -166 │ ╭ maps_without_3_neg(None) -> -167 │ │ maps:without( -168 │ │ [a, b], -169 │ │ None -170 │ │ ). - │ ╰───^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:185:3 - │ -185 │ ╭ maps:with( -186 │ │ [a], -187 │ │ Dyn -188 │ │ ). - │ ╰───^ maps:with(['a'], Dyn). -Expression has type: #{a := dynamic()} -Context expected type: 'wrong_ret' - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/gradual_custom.erl:193:1 - │ -193 │ ╭ maps_with_3(None) -> -194 │ │ maps:with( -195 │ │ [a, b], -196 │ │ None -197 │ │ ). - │ ╰───^ Clause is not covered by spec - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_custom.erl:203:25 - │ -203 │ eqwalizer:reveal_type(Res), - │ ^^^ file:filename_all() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:204:3 - │ -204 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: file:filename_all() -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is: string() | binary() - 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 - │ -210 │ eqwalizer:reveal_type(Res), - │ ^^^ file:filename_all() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:211:3 - │ -211 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: file:filename_all() -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is: string() | binary() - 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 - │ -217 │ eqwalizer:reveal_type(Res), - │ ^^^ file:filename_all() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:218:3 - │ -218 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: file:filename_all() -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is: string() | binary() - 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 - │ -224 │ eqwalizer:reveal_type(Res), - │ ^^^ file:filename_all() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:225:3 - │ -225 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: file:filename_all() -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is: string() | binary() - 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 - │ -245 │ min3_neg(X, Y) -> min(X, Y). - │ ^^^^^^^^^ - │ │ - │ erlang:min(X, Y). -Expression has type: number() | 'undefined' -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: '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 - │ -257 │ min5_neg(X, Y) -> min(X, Y). - │ ^^^^^^^^^ - │ │ - │ erlang:min(X, Y). -Expression has type: number() | atom() | binary() -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: 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 - │ -263 │ min6_neg(X, Y) -> min(X, Y). - │ ^^^^^^^^^ - │ │ - │ erlang:min(X, Y). -Expression has type: number() | dynamic() | number() | atom() | dynamic() -Context expected type: number() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: number() | dynamic() - 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 - │ -269 │ min7_neg(X, Y) -> min(X, Y). - │ ^^^^^^^^^ - │ │ - │ erlang:min(X, Y). -Expression has type: number() | dynamic() | atom() | dynamic() -Context expected type: number() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: number() | dynamic() - 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 - │ -277 │ eqwalizer:reveal_type(Y), - │ ^ dynamic() | {none()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_custom.erl:278:3 - │ -278 │ Y. - │ ^ - │ │ - │ Y. -Expression has type: dynamic() | {none()} -Context expected type: number() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: dynamic() - 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 - │ -325 │ true -> Atom; - │ ^^^^ - │ │ - │ Atom. -Expression has type: 'bar' | 'undefined' | 'foo' -Context expected type: 'foo' | 'bar' | binary() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'bar' | 'foo' - 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 - │ -343 │ parse_atom(Bin, [foo, bar]). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ parse_atom(Bin, ['foo', 'bar']). -Expression has type: 'foo' | 'bar' -Context expected type: 'foo' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'foo' - 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_custom-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_custom.pretty similarity index 84% rename from crates/elp/src/resources/test/eqwalizer_tests/check/gradual_custom-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/gradual_custom.pretty index 34e16f1479..065a377d0d 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_custom-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_custom.pretty @@ -100,12 +100,6 @@ 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 │ @@ -202,12 +196,6 @@ 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 │ @@ -230,12 +218,6 @@ 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 │ @@ -258,12 +240,6 @@ 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 │ @@ -286,12 +262,6 @@ 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 │ @@ -308,12 +278,6 @@ 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 │ @@ -330,12 +294,6 @@ 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 │ @@ -352,12 +310,6 @@ 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 │ @@ -374,12 +326,6 @@ 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 │ @@ -402,12 +348,6 @@ 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 │ @@ -424,14 +364,6 @@ 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 │ @@ -448,10 +380,4 @@ 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_lambdas-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_lambdas-OTP-27.pretty deleted file mode 100644 index 60301786c5..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_lambdas-OTP-27.pretty +++ /dev/null @@ -1,33 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_lambdas.erl:39:17 - │ -39 │ true -> A + 1; - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/gradual_lambdas.erl:55:3 - │ -55 │ DoWork(). - │ ^^^^^^ DoWork. -Expected fun type with arity 0 -Got: fun((dynamic()) -> dynamic()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_lambdas.erl:70:13 - │ -70 │ fun(X) -> X + 1 end. - │ ^ X. -Expression has type: string() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_lambdas.erl:70:13 - │ -70 │ fun(X) -> X + 1 end. - │ ^^^^^ _ + _. -Expression has type: number() -Context expected type: string() - -4 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_lambdas-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_lambdas-OTP-28.pretty deleted file mode 100644 index 60301786c5..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_lambdas-OTP-28.pretty +++ /dev/null @@ -1,33 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_lambdas.erl:39:17 - │ -39 │ true -> A + 1; - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/gradual_lambdas.erl:55:3 - │ -55 │ DoWork(). - │ ^^^^^^ DoWork. -Expected fun type with arity 0 -Got: fun((dynamic()) -> dynamic()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_lambdas.erl:70:13 - │ -70 │ fun(X) -> X + 1 end. - │ ^ X. -Expression has type: string() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_lambdas.erl:70:13 - │ -70 │ fun(X) -> X + 1 end. - │ ^^^^^ _ + _. -Expression has type: number() -Context expected type: string() - -4 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_lambdas-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_lambdas.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/gradual_lambdas-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/gradual_lambdas.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe-OTP-26.pretty deleted file mode 100644 index 5587da0d7e..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe-OTP-26.pretty +++ /dev/null @@ -1,93 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:26:9 - │ -26 │ A - │ ^ A. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:50:14 - │ -50 │ _ -> 3 - │ ^ 3. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:58:21 - │ -58 │ {err, A} ?= T, - │ ^ T. -Expression has type: {'ok', atom()} | {'err', term()} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:67:20 - │ -67 │ {ok, A} ?= T, - │ ^ T. -Expression has type: {'ok', atom()} | {'err', term()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:91:9 - │ -91 │ B - │ ^ B. -Expression has type: 'ok' -Context expected type: 'err' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:93:14 - │ -93 │ _ -> ok - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: 'err' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:123:18 - │ -123 │ a = A ?= T, - │ ^ - │ │ - │ T. -Expression has type: 'a' | 'b' | 'c' -Context expected type: 'b' | 'c' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'b' | 'c' - 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 - │ -147 │ c -> err - │ ^^^ 'err'. -Expression has type: 'err' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:156:13 - │ -156 │ ╭ maybe -157 │ │ B ?= {a, T}, -158 │ │ V = {b, B}, -159 │ │ C ?= V -160 │ │ end - │ ╰───────────────^ maybe ... -Expression has type: {'a', term()} | {'b', {'a', term()}} -Context expected type: 'err' - -9 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe-OTP-27.pretty deleted file mode 100644 index 5587da0d7e..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe-OTP-27.pretty +++ /dev/null @@ -1,93 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:26:9 - │ -26 │ A - │ ^ A. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:50:14 - │ -50 │ _ -> 3 - │ ^ 3. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:58:21 - │ -58 │ {err, A} ?= T, - │ ^ T. -Expression has type: {'ok', atom()} | {'err', term()} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:67:20 - │ -67 │ {ok, A} ?= T, - │ ^ T. -Expression has type: {'ok', atom()} | {'err', term()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:91:9 - │ -91 │ B - │ ^ B. -Expression has type: 'ok' -Context expected type: 'err' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:93:14 - │ -93 │ _ -> ok - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: 'err' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:123:18 - │ -123 │ a = A ?= T, - │ ^ - │ │ - │ T. -Expression has type: 'a' | 'b' | 'c' -Context expected type: 'b' | 'c' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'b' | 'c' - 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 - │ -147 │ c -> err - │ ^^^ 'err'. -Expression has type: 'err' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_maybe.erl:156:13 - │ -156 │ ╭ maybe -157 │ │ B ?= {a, T}, -158 │ │ V = {b, B}, -159 │ │ C ?= V -160 │ │ end - │ ╰───────────────^ maybe ... -Expression has type: {'a', term()} | {'b', {'a', term()}} -Context expected type: 'err' - -9 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe.pretty similarity index 92% rename from crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe.pretty index 5587da0d7e..35a509f2f6 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe-OTP-28.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_maybe.pretty @@ -62,14 +62,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc-OTP-26.pretty deleted file mode 100644 index 33b6c1bf38..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc-OTP-26.pretty +++ /dev/null @@ -1,60 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_misc.erl:15:3 - │ -15 │ X. - │ ^ - │ │ - │ X. -Expression has type: opaque:contravariant('a') -Context expected type: opaque:contravariant('a' | 'b') - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -38 │ <>. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ << || >>. -Expression has type: binary() -Context expected type: 'ok' - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/gradual_misc.erl:41:1 - │ -41 │ ╭ fuzz03([_ | {}]) -> -42 │ │ ok. - │ ╰──────^ Clause is not covered by spec - -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. -Expression has type: none() | {'b', 'c'} -Context expected type: 'a' | {none()} - │ - -Because in the expression's type: - Here the type is: {'b', 'c'} - Context expects type: 'a' | {none()} - No candidate matches in the expected union. - -4 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc-OTP-27.pretty deleted file mode 100644 index 33b6c1bf38..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc-OTP-27.pretty +++ /dev/null @@ -1,60 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_misc.erl:15:3 - │ -15 │ X. - │ ^ - │ │ - │ X. -Expression has type: opaque:contravariant('a') -Context expected type: opaque:contravariant('a' | 'b') - │ - -Because in the expression's type: - fun(( - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -38 │ <>. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ << || >>. -Expression has type: binary() -Context expected type: 'ok' - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/gradual_misc.erl:41:1 - │ -41 │ ╭ fuzz03([_ | {}]) -> -42 │ │ ok. - │ ╰──────^ Clause is not covered by spec - -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. -Expression has type: none() | {'b', 'c'} -Context expected type: 'a' | {none()} - │ - -Because in the expression's type: - Here the type is: {'b', 'c'} - Context expects type: 'a' | {none()} - No candidate matches in the expected union. - -4 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc.pretty similarity index 61% rename from crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc.pretty index 33b6c1bf38..28618b5f77 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc-OTP-28.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_misc.pretty @@ -16,16 +16,6 @@ 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 │ @@ -45,16 +35,8 @@ 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. -Expression has type: none() | {'b', 'c'} + │ ^ T. +Expression has type: {'b', 'c'} Context expected type: 'a' | {none()} - │ - -Because in the expression's type: - Here the type is: {'b', 'c'} - Context expects type: 'a' | {none()} - No candidate matches in the expected union. 4 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_overloaded-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_overloaded-OTP-27.pretty deleted file mode 100644 index 957e329439..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_overloaded-OTP-27.pretty +++ /dev/null @@ -1,77 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:38:20 - │ -38 │ binary_to_atom(Y). - │ ^ Y. -Expression has type: pid() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:61:5 - │ -61 │ {Y}. - │ ^^^ {Y}. -Expression has type: {dynamic()} -Context expected type: number() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_overloaded.erl:90:27 - │ -90 │ eqwalizer:reveal_type(Res), - │ ^^^ dynamic() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:112:5 - │ -112 │ ╭ rec_each( -113 │ │ fun(R) -> R#r{count = 0} end, -114 │ │ Rec -115 │ │ ). - │ ╰─────^ rec_each(fun, Rec). -Expression has type: #r{} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:119:5 - │ -119 │ ╭ rec_each( -120 │ │ fun(I) -> I + 1 end, -121 │ │ Rec -122 │ │ ). - │ ╰─────^ rec_each(fun, Rec). -Expression has type: #r{} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:120:19 - │ -120 │ fun(I) -> I + 1 end, - │ ^ I. -Expression has type: #r{} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:120:19 - │ -120 │ fun(I) -> I + 1 end, - │ ^^^^^ _ + _. -Expression has type: number() -Context expected type: #r{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:128:19 - │ -128 │ fun(I) -> I + 1 end, - │ ^ I. -Expression has type: #r{} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:128:19 - │ -128 │ fun(I) -> I + 1 end, - │ ^^^^^ _ + _. -Expression has type: number() -Context expected type: #r{} - -9 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_overloaded-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_overloaded-OTP-28.pretty deleted file mode 100644 index 957e329439..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_overloaded-OTP-28.pretty +++ /dev/null @@ -1,77 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:38:20 - │ -38 │ binary_to_atom(Y). - │ ^ Y. -Expression has type: pid() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:61:5 - │ -61 │ {Y}. - │ ^^^ {Y}. -Expression has type: {dynamic()} -Context expected type: number() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_overloaded.erl:90:27 - │ -90 │ eqwalizer:reveal_type(Res), - │ ^^^ dynamic() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:112:5 - │ -112 │ ╭ rec_each( -113 │ │ fun(R) -> R#r{count = 0} end, -114 │ │ Rec -115 │ │ ). - │ ╰─────^ rec_each(fun, Rec). -Expression has type: #r{} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:119:5 - │ -119 │ ╭ rec_each( -120 │ │ fun(I) -> I + 1 end, -121 │ │ Rec -122 │ │ ). - │ ╰─────^ rec_each(fun, Rec). -Expression has type: #r{} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:120:19 - │ -120 │ fun(I) -> I + 1 end, - │ ^ I. -Expression has type: #r{} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:120:19 - │ -120 │ fun(I) -> I + 1 end, - │ ^^^^^ _ + _. -Expression has type: number() -Context expected type: #r{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:128:19 - │ -128 │ fun(I) -> I + 1 end, - │ ^ I. -Expression has type: #r{} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/gradual_overloaded.erl:128:19 - │ -128 │ fun(I) -> I + 1 end, - │ ^^^^^ _ + _. -Expression has type: number() -Context expected type: #r{} - -9 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_overloaded-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_overloaded.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/gradual_overloaded-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/gradual_overloaded.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs1-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_regression_01.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs1-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/gradual_regression_01.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_untyped-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_untyped-OTP-27.pretty deleted file mode 100644 index e82d8ee3f2..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_untyped-OTP-27.pretty +++ /dev/null @@ -1,25 +0,0 @@ -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_untyped.erl:11:25 - │ -11 │ eqwalizer:reveal_type(_L), - │ ^^ [dynamic()] - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_untyped.erl:23:25 - │ -23 │ eqwalizer:reveal_type(Field2), - │ ^^^^^^ dynamic() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_untyped.erl:28:25 - │ -28 │ eqwalizer:reveal_type(A), - │ ^ dynamic() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_untyped.erl:33:25 - │ -33 │ eqwalizer:reveal_type(B), - │ ^ dynamic() - -4 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_untyped-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_untyped-OTP-28.pretty deleted file mode 100644 index e82d8ee3f2..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_untyped-OTP-28.pretty +++ /dev/null @@ -1,25 +0,0 @@ -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_untyped.erl:11:25 - │ -11 │ eqwalizer:reveal_type(_L), - │ ^^ [dynamic()] - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_untyped.erl:23:25 - │ -23 │ eqwalizer:reveal_type(Field2), - │ ^^^^^^ dynamic() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_untyped.erl:28:25 - │ -28 │ eqwalizer:reveal_type(A), - │ ^ dynamic() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/gradual_untyped.erl:33:25 - │ -33 │ eqwalizer:reveal_type(B), - │ ^ dynamic() - -4 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_untyped-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_untyped.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/gradual_untyped-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/gradual_untyped.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections-OTP-26.pretty deleted file mode 100644 index 88bcfb1267..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections-OTP-26.pretty +++ /dev/null @@ -1,121 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guard_b_connections.erl:22:3 - │ -22 │ R. - │ ^ - │ │ - │ R. -Expression has type: #r1{} | #r2{} -Context expected type: r1() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #r1{} - 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 - │ -27 │ R. - │ ^ - │ │ - │ R. -Expression has type: #r1{} | #r2{} -Context expected type: r1() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #r1{} - 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 - │ -32 │ R. - │ ^ - │ │ - │ R. -Expression has type: #r1{} | #r2{} -Context expected type: r1() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #r1{} - 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 - │ -38 │ R. - │ ^ - │ │ - │ R. -Expression has type: #r1{} | #r2{} -Context expected type: r1() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #r1{} - 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 - │ -44 │ R. - │ ^ - │ │ - │ R. -Expression has type: #r1{} | #r2{} -Context expected type: r1() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #r1{} - 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/guard_b_connections-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections-OTP-28.pretty deleted file mode 100644 index 88bcfb1267..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections-OTP-28.pretty +++ /dev/null @@ -1,121 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guard_b_connections.erl:22:3 - │ -22 │ R. - │ ^ - │ │ - │ R. -Expression has type: #r1{} | #r2{} -Context expected type: r1() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #r1{} - 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 - │ -27 │ R. - │ ^ - │ │ - │ R. -Expression has type: #r1{} | #r2{} -Context expected type: r1() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #r1{} - 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 - │ -32 │ R. - │ ^ - │ │ - │ R. -Expression has type: #r1{} | #r2{} -Context expected type: r1() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #r1{} - 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 - │ -38 │ R. - │ ^ - │ │ - │ R. -Expression has type: #r1{} | #r2{} -Context expected type: r1() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #r1{} - 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 - │ -44 │ R. - │ ^ - │ │ - │ R. -Expression has type: #r1{} | #r2{} -Context expected type: r1() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #r1{} - 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/guard_b_connections-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections.pretty similarity index 66% rename from crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections.pretty index 88bcfb1267..74cd6b4ca4 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/guard_b_connections.pretty @@ -14,14 +14,6 @@ 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 │ @@ -38,14 +30,6 @@ 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 │ @@ -62,14 +46,6 @@ 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 │ @@ -86,14 +62,6 @@ 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 │ @@ -110,12 +78,4 @@ 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-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guards-OTP-27.pretty deleted file mode 100644 index c17a7e6267..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/guards-OTP-27.pretty +++ /dev/null @@ -1,37 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards.erl:51:5 - │ -51 │ X. - │ ^ X. -Expression has type: term() -Context expected type: #{number() => number()} - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/guards.erl:53:1 - │ -53 │ -type loop() :: loop(). - │ ^^^^^^^^^^^^^^^^^^^^ recursive type loop/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/guards.erl:54:1 - │ -54 │ -record(invalid, {field :: loop()}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid references type with invalid definition: loop/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards.erl:89:25 - │ -89 │ guard_element_neg(T) -> T + 1. - │ ^ T. -Expression has type: tuple() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards.erl:89:25 - │ -89 │ guard_element_neg(T) -> T + 1. - │ ^^^^^ _ + _. -Expression has type: number() -Context expected type: tuple() - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/guards-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guards-OTP-28.pretty deleted file mode 100644 index c17a7e6267..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/guards-OTP-28.pretty +++ /dev/null @@ -1,37 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards.erl:51:5 - │ -51 │ X. - │ ^ X. -Expression has type: term() -Context expected type: #{number() => number()} - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/guards.erl:53:1 - │ -53 │ -type loop() :: loop(). - │ ^^^^^^^^^^^^^^^^^^^^ recursive type loop/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/guards.erl:54:1 - │ -54 │ -record(invalid, {field :: loop()}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid references type with invalid definition: loop/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards.erl:89:25 - │ -89 │ guard_element_neg(T) -> T + 1. - │ ^ T. -Expression has type: tuple() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards.erl:89:25 - │ -89 │ guard_element_neg(T) -> T + 1. - │ ^^^^^ _ + _. -Expression has type: number() -Context expected type: tuple() - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/guards-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guards.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/guards-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/guards.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic-OTP-27.pretty deleted file mode 100644 index c287958c68..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic-OTP-27.pretty +++ /dev/null @@ -1,73 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_logic.erl:32:38 - │ -32 │ test07_neg(X, Y) when X andalso Y -> Y. - │ ^ Y. -Expression has type: 'true' -Context expected type: 'false' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_logic.erl:35:40 - │ -35 │ test08_neg(X) when not is_number(X) -> X. - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_logic.erl:57:20 - │ -57 │ is_pid(X)-> X. - │ ^ - │ │ - │ X. -Expression has type: number() | atom() | pid() -Context expected type: number() | atom() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: number() | atom() - 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 - │ -73 │ {X, Y}. - │ ^^^^^^ - │ │ - │ {X, Y}. -Expression has type: {term(), term()} -Context expected type: {number(), number()} - │ - -Because in the expression's type: - { - Here the type is: term() - 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 - │ -101 │ test21_neg(X) when (X =:= a) or (X =:= b) -> X. - │ ^ X. -Expression has type: 'a' | 'b' -Context expected type: 'c' - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic-OTP-28.pretty deleted file mode 100644 index c287958c68..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic-OTP-28.pretty +++ /dev/null @@ -1,73 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_logic.erl:32:38 - │ -32 │ test07_neg(X, Y) when X andalso Y -> Y. - │ ^ Y. -Expression has type: 'true' -Context expected type: 'false' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_logic.erl:35:40 - │ -35 │ test08_neg(X) when not is_number(X) -> X. - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_logic.erl:57:20 - │ -57 │ is_pid(X)-> X. - │ ^ - │ │ - │ X. -Expression has type: number() | atom() | pid() -Context expected type: number() | atom() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: number() | atom() - 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 - │ -73 │ {X, Y}. - │ ^^^^^^ - │ │ - │ {X, Y}. -Expression has type: {term(), term()} -Context expected type: {number(), number()} - │ - -Because in the expression's type: - { - Here the type is: term() - 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 - │ -101 │ test21_neg(X) when (X =:= a) or (X =:= b) -> X. - │ ^ X. -Expression has type: 'a' | 'b' -Context expected type: 'c' - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic.pretty similarity index 80% rename from crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic.pretty index c287958c68..bc1b2fff4a 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic-OTP-26.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/guards_logic.pretty @@ -30,14 +30,6 @@ 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 │ @@ -55,13 +47,6 @@ 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/guards_simple-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guards_simple-OTP-27.pretty deleted file mode 100644 index 7bc05b8ab1..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/guards_simple-OTP-27.pretty +++ /dev/null @@ -1,97 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:26:36 - │ -26 │ atom_neg_1(X) when is_number(X) -> X. - │ ^ X. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:31:23 - │ -31 │ is_list(X) -> X - │ ^ X. -Expression has type: [term()] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:37:31 - │ -37 │ Y when is_tuple(Y) -> Y - │ ^ Y. -Expression has type: tuple() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:56:37 - │ -56 │ boolean_neg_1(X) when is_atom(X) -> X. - │ ^ X. -Expression has type: atom() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:61:23 - │ -61 │ is_atom(X) -> X - │ ^ X. -Expression has type: atom() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:67:30 - │ -67 │ Y when is_atom(Y) -> Y - │ ^ Y. -Expression has type: atom() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:74:36 - │ -74 │ float_neg(X) when is_boolean(X) -> X. - │ ^ X. -Expression has type: 'false' | 'true' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:80:38 - │ -80 │ integer_neg(X) when is_boolean(X) -> X. - │ ^ X. -Expression has type: 'false' | 'true' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:86:33 - │ -86 │ pid_neg(X) when is_number(X) -> X. - │ ^ X. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:92:37 - │ -92 │ port_neg(X) when is_reference(X) -> X. - │ ^ X. -Expression has type: reference() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:95:42 - │ -95 │ reference_pos(X) when is_reference(X) -> X. - │ ^ X. -Expression has type: reference() -Context expected type: port() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:98:37 - │ -98 │ reference_neg(X) when is_port(X) -> X. - │ ^ X. -Expression has type: port() -Context expected type: pid() - -12 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/guards_simple-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guards_simple-OTP-28.pretty deleted file mode 100644 index 7bc05b8ab1..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/guards_simple-OTP-28.pretty +++ /dev/null @@ -1,97 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:26:36 - │ -26 │ atom_neg_1(X) when is_number(X) -> X. - │ ^ X. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:31:23 - │ -31 │ is_list(X) -> X - │ ^ X. -Expression has type: [term()] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:37:31 - │ -37 │ Y when is_tuple(Y) -> Y - │ ^ Y. -Expression has type: tuple() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:56:37 - │ -56 │ boolean_neg_1(X) when is_atom(X) -> X. - │ ^ X. -Expression has type: atom() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:61:23 - │ -61 │ is_atom(X) -> X - │ ^ X. -Expression has type: atom() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:67:30 - │ -67 │ Y when is_atom(Y) -> Y - │ ^ Y. -Expression has type: atom() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:74:36 - │ -74 │ float_neg(X) when is_boolean(X) -> X. - │ ^ X. -Expression has type: 'false' | 'true' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:80:38 - │ -80 │ integer_neg(X) when is_boolean(X) -> X. - │ ^ X. -Expression has type: 'false' | 'true' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:86:33 - │ -86 │ pid_neg(X) when is_number(X) -> X. - │ ^ X. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:92:37 - │ -92 │ port_neg(X) when is_reference(X) -> X. - │ ^ X. -Expression has type: reference() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:95:42 - │ -95 │ reference_pos(X) when is_reference(X) -> X. - │ ^ X. -Expression has type: reference() -Context expected type: port() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/guards_simple.erl:98:37 - │ -98 │ reference_neg(X) when is_port(X) -> X. - │ ^ X. -Expression has type: port() -Context expected type: pid() - -12 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/guards_simple-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/guards_simple.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/guards_simple-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/guards_simple.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/hints-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/hints-OTP-26.pretty deleted file mode 100644 index c1dae73601..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/hints-OTP-26.pretty +++ /dev/null @@ -1,83 +0,0 @@ -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/hints.erl:13:27 - │ -13 │ eqwalizer:reveal_type(A), - │ ^ atom() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/hints.erl:24:27 - │ -24 │ eqwalizer:reveal_type(_A), - │ ^^ atom() | binary() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/hints.erl:32:27 - │ -32 │ eqwalizer:reveal_type(B), - │ ^ none() | binary() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/hints.erl:41:27 - │ -41 │ eqwalizer:reveal_type(BT), - │ ^^ none() | binary() | tuple() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/hints.erl:47:5 - │ -47 │ Key. - │ ^^^ - │ │ - │ Key. -Expression has type: term() | 'undefined' -Context expected type: atom() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'undefined' - 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 - │ -52 │ Key. - │ ^^^ - │ │ - │ Key. -Expression has type: term() | 'undefined' -Context expected type: atom() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'undefined' - 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 - │ -55 │ ╭ reveal_none(X) -> -56 │ │ eqwalizer:reveal_type(X), -57 │ │ error(none). - │ ╰───────────────^ Clause is not covered by spec - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/hints.erl:56:27 - │ -56 │ eqwalizer:reveal_type(X), - │ ^ none() - -8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/hints-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/hints-OTP-28.pretty deleted file mode 100644 index c1dae73601..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/hints-OTP-28.pretty +++ /dev/null @@ -1,83 +0,0 @@ -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/hints.erl:13:27 - │ -13 │ eqwalizer:reveal_type(A), - │ ^ atom() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/hints.erl:24:27 - │ -24 │ eqwalizer:reveal_type(_A), - │ ^^ atom() | binary() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/hints.erl:32:27 - │ -32 │ eqwalizer:reveal_type(B), - │ ^ none() | binary() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/hints.erl:41:27 - │ -41 │ eqwalizer:reveal_type(BT), - │ ^^ none() | binary() | tuple() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/hints.erl:47:5 - │ -47 │ Key. - │ ^^^ - │ │ - │ Key. -Expression has type: term() | 'undefined' -Context expected type: atom() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'undefined' - 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 - │ -52 │ Key. - │ ^^^ - │ │ - │ Key. -Expression has type: term() | 'undefined' -Context expected type: atom() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'undefined' - 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 - │ -55 │ ╭ reveal_none(X) -> -56 │ │ eqwalizer:reveal_type(X), -57 │ │ error(none). - │ ╰───────────────^ Clause is not covered by spec - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/hints.erl:56:27 - │ -56 │ eqwalizer:reveal_type(X), - │ ^ none() - -8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/hints-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/hints.pretty similarity index 81% rename from crates/elp/src/resources/test/eqwalizer_tests/check/hints-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/hints.pretty index c1dae73601..f990884695 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/hints-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/hints.pretty @@ -14,13 +14,13 @@ error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) ┌─ check/src/hints.erl:32:27 │ 32 │ eqwalizer:reveal_type(B), - │ ^ none() | binary() + │ ^ binary() error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) ┌─ check/src/hints.erl:41:27 │ 41 │ eqwalizer:reveal_type(BT), - │ ^^ none() | binary() | tuple() + │ ^^ binary() | tuple() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/hints.erl:47:5 @@ -38,12 +38,6 @@ 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 │ @@ -60,12 +54,6 @@ 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/index1-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/index1-OTP-27.pretty deleted file mode 100644 index 53b66665b2..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/index1-OTP-27.pretty +++ /dev/null @@ -1,23 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/index1.erl:31:21 - │ -31 │ _ = X#rec{field = 3}, - │ ^ 3. -Expression has type: number() -Context expected type: [number()] - -error: undefined_field (See https://fb.me/eqwalizer_errors#undefined_field) - ┌─ check/src/index1.erl:32:7 - │ -32 │ _ = #rec{}, - │ ^^^^^^ #rec{...}: field is 'undefined' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/index1.erl:39:5 - │ -39 │ _ = fun index2:foo/1. - │ ^^^^^^^^^^^^^^^^^^ match_expr. -Expression has type: fun((#rec{}) -> {index2:ty_a(), ty_a(), rec()}) -Context expected type: {ty_a(), ty_b(), ty_a(), ty_b(), index2:ty_a(), #rec{}, rec()} - -3 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/index1-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/index1-OTP-28.pretty deleted file mode 100644 index 53b66665b2..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/index1-OTP-28.pretty +++ /dev/null @@ -1,23 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/index1.erl:31:21 - │ -31 │ _ = X#rec{field = 3}, - │ ^ 3. -Expression has type: number() -Context expected type: [number()] - -error: undefined_field (See https://fb.me/eqwalizer_errors#undefined_field) - ┌─ check/src/index1.erl:32:7 - │ -32 │ _ = #rec{}, - │ ^^^^^^ #rec{...}: field is 'undefined' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/index1.erl:39:5 - │ -39 │ _ = fun index2:foo/1. - │ ^^^^^^^^^^^^^^^^^^ match_expr. -Expression has type: fun((#rec{}) -> {index2:ty_a(), ty_a(), rec()}) -Context expected type: {ty_a(), ty_b(), ty_a(), ty_b(), index2:ty_a(), #rec{}, rec()} - -3 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/index1-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/index1.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/index1-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/index1.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/index2-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/index2-OTP-27.pretty deleted file mode 100644 index cf62c97c82..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/index2-OTP-27.pretty +++ /dev/null @@ -1,9 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/index2.erl:21:3 - │ -21 │ X#rec.field. - │ ^^^^^^^^^^^ ...#rec.field. -Expression has type: [atom()] -Context expected type: {ty_a(), index1:ty_a(), index1:rec()} - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/index2-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/index2-OTP-28.pretty deleted file mode 100644 index cf62c97c82..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/index2-OTP-28.pretty +++ /dev/null @@ -1,9 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/index2.erl:21:3 - │ -21 │ X#rec.field. - │ ^^^^^^^^^^^ ...#rec.field. -Expression has type: [atom()] -Context expected type: {ty_a(), index1:ty_a(), index1:rec()} - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/index2-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/index2.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/index2-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/index2.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/iolists-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/iolists-OTP-26.pretty deleted file mode 100644 index bf9d6e219b..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/iolists-OTP-26.pretty +++ /dev/null @@ -1,85 +0,0 @@ -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/iolists.erl:18:1 - │ -18 │ ╭ first(IoList) -19 │ │ when is_binary(IoList) -> IoList; - │ ╰────────────────────────────────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/iolists.erl:50:18 - │ -50 │ refine5(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: [atom() | binary()] -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: atom() - 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 - │ -55 │ refine6_neg(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: [atom() | binary()] -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: binary() - 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 - │ -60 │ refine_to_empty1(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: [atom()] -Context expected type: [] - │ - -Because in the expression's type: - [ - Here the type is: atom() - Context expects type: none() - ] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/iolists.erl:83:17 - │ -83 │ test2_neg(X) -> X. - │ ^ X. -Expression has type: iolist() -Context expected type: 'wrong_ret' - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/iolists-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/iolists-OTP-28.pretty deleted file mode 100644 index bf9d6e219b..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/iolists-OTP-28.pretty +++ /dev/null @@ -1,85 +0,0 @@ -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/iolists.erl:18:1 - │ -18 │ ╭ first(IoList) -19 │ │ when is_binary(IoList) -> IoList; - │ ╰────────────────────────────────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/iolists.erl:50:18 - │ -50 │ refine5(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: [atom() | binary()] -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: atom() - 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 - │ -55 │ refine6_neg(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: [atom() | binary()] -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: binary() - 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 - │ -60 │ refine_to_empty1(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: [atom()] -Context expected type: [] - │ - -Because in the expression's type: - [ - Here the type is: atom() - Context expects type: none() - ] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/iolists.erl:83:17 - │ -83 │ test2_neg(X) -> X. - │ ^ X. -Expression has type: iolist() -Context expected type: 'wrong_ret' - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/iolists-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/iolists.pretty similarity index 81% rename from crates/elp/src/resources/test/eqwalizer_tests/check/iolists-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/iolists.pretty index bf9d6e219b..00e34f9cb8 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/iolists-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/iolists.pretty @@ -23,14 +23,6 @@ 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 │ @@ -49,14 +41,6 @@ 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/detached_specs1-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/kp_01.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs1-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/kp_01.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/kp_02-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/kp_02-OTP-27.pretty deleted file mode 100644 index 5613ac7817..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/kp_02-OTP-27.pretty +++ /dev/null @@ -1,33 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/kp_02.erl:24:21 - │ -24 │ Res = transform(pure_fun(fun id/1), A), - │ ^^^^^^^^^^^^^^^^^^ - │ │ - │ pure_fun(id/1). -Expression has type: fun((X) -> X) with 1 type parameter -Context expected type: fun((T1) -> Ret) with 0 type parameters - │ - -Because in the expression's type: - Here the type is: fun((X) -> X) with 1 type parameter - Context expects type: fun((T1) -> Ret) 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/kp_02.erl:24:21 - │ -24 │ Res = transform(pure_fun(fun id/1), A), - │ ^^^^^^^^^^^^^^^^^^ - │ │ - │ pure_fun(id/1). -Expression has type: fun((X) -> X) with 1 type parameter -Context expected type: fun((number()) -> dynamic()) with 0 type parameters - │ - -Because in the expression's type: - Here the type is: fun((X) -> X) with 1 type parameter - Context expects type: fun((number()) -> dynamic()) with 0 type parameters - The number of type parameters doesn't match. - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/kp_02-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/kp_02-OTP-28.pretty deleted file mode 100644 index 5613ac7817..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/kp_02-OTP-28.pretty +++ /dev/null @@ -1,33 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/kp_02.erl:24:21 - │ -24 │ Res = transform(pure_fun(fun id/1), A), - │ ^^^^^^^^^^^^^^^^^^ - │ │ - │ pure_fun(id/1). -Expression has type: fun((X) -> X) with 1 type parameter -Context expected type: fun((T1) -> Ret) with 0 type parameters - │ - -Because in the expression's type: - Here the type is: fun((X) -> X) with 1 type parameter - Context expects type: fun((T1) -> Ret) 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/kp_02.erl:24:21 - │ -24 │ Res = transform(pure_fun(fun id/1), A), - │ ^^^^^^^^^^^^^^^^^^ - │ │ - │ pure_fun(id/1). -Expression has type: fun((X) -> X) with 1 type parameter -Context expected type: fun((number()) -> dynamic()) with 0 type parameters - │ - -Because in the expression's type: - Here the type is: fun((X) -> X) with 1 type parameter - Context expects type: fun((number()) -> dynamic()) with 0 type parameters - The number of type parameters doesn't match. - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/kp_02-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/kp_02.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/kp_02-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/kp_02.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests-OTP-26.pretty deleted file mode 100644 index d0768e5669..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests-OTP-26.pretty +++ /dev/null @@ -1,57 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/lists_tests.erl:12:28 - │ -12 │ lists_union_neg(V1, V2) -> [V1, V2]. - │ ^^^^^^^^ - │ │ - │ [V1, V2]. -Expression has type: [atom() | binary()] -Context expected type: [atom()] | [binary()] - │ - -Because in the expression's type: - [ - Here the type is a union type with some valid candidates: atom() - However the following candidate: binary() - 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 - │ -16 │ lists_union_2_neg(V, L) -> [V | L]. - │ ^^^^^^^ - │ │ - │ [V | L]. -Expression has type: [atom() | binary()] -Context expected type: [atom()] | [binary()] - │ - -Because in the expression's type: - [ - Here the type is a union type with some valid candidates: atom() - However the following candidate: binary() - 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/lists_tests-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests-OTP-27.pretty deleted file mode 100644 index d0768e5669..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests-OTP-27.pretty +++ /dev/null @@ -1,57 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/lists_tests.erl:12:28 - │ -12 │ lists_union_neg(V1, V2) -> [V1, V2]. - │ ^^^^^^^^ - │ │ - │ [V1, V2]. -Expression has type: [atom() | binary()] -Context expected type: [atom()] | [binary()] - │ - -Because in the expression's type: - [ - Here the type is a union type with some valid candidates: atom() - However the following candidate: binary() - 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 - │ -16 │ lists_union_2_neg(V, L) -> [V | L]. - │ ^^^^^^^ - │ │ - │ [V | L]. -Expression has type: [atom() | binary()] -Context expected type: [atom()] | [binary()] - │ - -Because in the expression's type: - [ - Here the type is a union type with some valid candidates: atom() - However the following candidate: binary() - 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/lists_tests-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests.pretty similarity index 66% rename from crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests.pretty index d0768e5669..4b2ec521dd 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests-OTP-28.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/lists_tests.pretty @@ -16,16 +16,6 @@ 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 │ @@ -44,14 +34,4 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/misc-OTP-26.pretty deleted file mode 100644 index 22e373f816..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/misc-OTP-26.pretty +++ /dev/null @@ -1,1011 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:46:23 - │ -46 │ test03_neg(-4 = X) -> X. - │ ^ X. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:49:26 - │ -49 │ test04_neg(6 / 3 = Y) -> Y. - │ ^ Y. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:52:20 - │ -52 │ test05_neg(X) -> + X. - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:55:36 - │ -55 │ test06_neg(X) when is_number(X) -> + X. - │ ^^^ + _. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:63:5 - │ -63 │ not X. - │ ^^^^^ not _. -Expression has type: boolean() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:73:25 - │ -73 │ is_number(X) -> X + Y. - │ ^ Y. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:77:21 - │ -77 │ test11_neg(X, Y) -> X + Y. - │ ^^^^^ _ + _. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:81:19 - │ -81 │ test12_neg(X) -> -X. - │ ^ X. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:85:21 - │ -85 │ test13_neg(X, Y) -> X or Y. - │ ^ X. -Expression has type: term() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:85:26 - │ -85 │ test13_neg(X, Y) -> X or Y. - │ ^ Y. -Expression has type: term() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:97:21 - │ -97 │ test16_neg(X, Y) -> X or Y. - │ ^^^^^^ _ or _. -Expression has type: boolean() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:101:26 - │ -101 │ test17_neg(X, Y) -> X or Y. - │ ^ Y. -Expression has type: atom() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:105:21 - │ -105 │ test18_neg(X, Y) -> X orelse Y. - │ ^^^^^^^^^^ _ orelse _. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:109:21 - │ -109 │ test19_neg(X, Y) -> X andalso Y. - │ ^^^^^^^^^^^ _ andalso _. -Expression has type: 'false' | number() -Context expected type: {number()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:112:18 - │ -112 │ test20_neg(X) -> [- X]. - │ ^^^^^ - │ │ - │ [- _]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -116 │ test21_neg(X, Y) -> [X / Y]. - │ ^^^^^^^ - │ │ - │ [_ / _]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -120 │ test22_neg(X) -> [not X]. - │ ^^^^^^^ - │ │ - │ [not _]. -Expression has type: [boolean()] -Context expected type: [number()] - │ - -Because in the expression's type: - [ - Here the type is: boolean() - Context expects type: number() - ] - ------------------------------- Detailed message ------------------------------ - - [boolean()] is not compatible with [number()] - because - boolean() is not compatible with number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:124:21 - │ -124 │ test23_neg(X, Y) -> [X or Y]. - │ ^^^^^^^^ - │ │ - │ [_ or _]. -Expression has type: [boolean()] -Context expected type: [number()] - │ - -Because in the expression's type: - [ - Here the type is: boolean() - Context expects type: number() - ] - ------------------------------- Detailed message ------------------------------ - - [boolean()] is not compatible with [number()] - because - boolean() is not compatible with number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:128:21 - │ -128 │ test24_neg(X, Y) -> [X orelse Y]. - │ ^^^^^^^^^^^^ - │ │ - │ [_ orelse _]. -Expression has type: [atom()] -Context expected type: [number()] - │ - -Because in the expression's type: - [ - Here the type is: atom() - 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 - │ -143 │ test28_neg(B) -> boolean_id(B). - │ ^ B. -Expression has type: atom() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:146:17 - │ -146 │ test29_neg() -> [true, false]. - │ ^^^^^^^^^^^^^ - │ │ - │ ['true', 'false']. -Expression has type: ['true' | 'false'] -Context expected type: [] - │ - -Because in the expression's type: - [ - Here the type is: 'true' | 'false' - Context expects type: none() - No candidate of the expression's type matches the expected type. - ] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:149:17 - │ -149 │ test30_neg() -> 1. - │ ^ 1. -Expression has type: number() -Context expected type: 'atom' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:152:17 - │ -152 │ test31_neg() -> fun test30_neg/0. - │ ^^^^^^^^^^^^^^^^ test30_neg/0. -Expression has type: fun(() -> 'atom') -Context expected type: 'atom' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:155:17 - │ -155 │ test32_neg() -> fun misc_lib:boolean_id/1. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ misc_lib:boolean_id/1. -Expression has type: fun((boolean()) -> boolean()) -Context expected type: 'atom' - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:192:1 - │ -192 │ test40_pos({X, Y}) -> {X, Y}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:196:1 - │ -196 │ test41_pos([X | Y]) -> {X, Y}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:204:1 - │ -204 │ test43_pos([_ | Y]) when Y + 1 > 0 -> Y. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:221:17 - │ -221 │ test46_neg() -> false. - │ ^^^^^ 'false'. -Expression has type: 'false' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:224:17 - │ -224 │ test47_neg() -> []. - │ ^^ []. -Expression has type: [] -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:227:17 - │ -227 │ test48_neg() -> test47_neg(). - │ ^^^^^^^^^^^^ test47_neg(). -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:230:17 - │ -230 │ test49_neg() -> misc:test47_neg(). - │ ^^^^^^^^^^^^^^^^^ misc:test47_neg(). -Expression has type: number() -Context expected type: atom() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:337:1 - │ -337 │ test68_pos({E, _}) -> E. - │ ^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:352:22 - │ -352 │ catch test69_pos(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'. -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 - │ -404 │ after Timeout -> - │ ^^^^^^^ Timeout. -Expression has type: term() -Context expected type: timeout() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:412:11 - │ -412 │ after Timeout -> - │ ^^^^^^^ Timeout. -Expression has type: term() -Context expected type: timeout() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:424:5 - │ -424 │ {Msg}. - │ ^^^^^ {Msg}. -Expression has type: {'default' | dynamic('atom')} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:453:5 - │ -453 │ {[H1|T1], [H2|T2]}. - │ ^^^^^^^^^^^^^^^^^^ - │ │ - │ {[H1 | T1], [H2 | T2]}. -Expression has type: {[number() | atom()], [atom() | number()]} -Context expected type: {[atom()], [number()]} - │ - -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() - ] - , [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 - │ -461 │ {[H1|T1], [H2|T2]}. - │ ^^^^^^^^^^^^^^^^^^ - │ │ - │ {[H1 | T1], [H2 | T2]}. -Expression has type: {[atom() | number()], [atom() | number()]} -Context expected type: {[atom()] | [number()], [atom()] | [number()]} - │ - -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() - ] - , [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 - │ -465 │ X = [1 | 2], - │ ^^^^ 2. -Expression has type: number() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:472:21 - │ -472 │ comp01_neg(X, Y) -> X < Y. - │ ^^^^^ _ < _. -Expression has type: boolean() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:482:5 - │ -482 │ Res. - │ ^^^ Res. -Expression has type: boolean() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:497:5 - │ -497 │ Where ! What. - │ ^^^^^^^^^^^^ _ ! _. -Expression has type: term() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:507:20 - │ -507 │ #str_box{str = Str}. - │ ^^^ Str. -Expression has type: atom() -Context expected type: string() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:513:17 - │ -513 │ string_neg() -> "str". - │ ^^^^^ string_lit. -Expression has type: string() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:538:5 - │ -538 │ Atom. - │ ^^^^ Atom. -Expression has type: string() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:555:5 - │ -555 │ Atoms ++ Numbers. - │ ^^^^^^^^^^^^^^^^ - │ │ - │ _ ++ _. -Expression has type: [atom() | binary()] -Context expected type: [atom() | number()] - │ - -Because in the expression's type: - [ - Here the type is a union type with some valid candidates: atom() - However the following candidate: binary() - 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 - │ -575 │ Atoms -- Anys. - │ ^^^^ Anys. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:581:5 - │ -581 │ Anys ++ Atoms. - │ ^^^^ Anys. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:599:23 - │ -599 │ start_neg([] ++ X) -> X. - │ ^ - │ │ - │ X. -Expression has type: [A] -Context expected type: [[A]] - │ - -Because in the expression's type: - [ - Here the type is: A - 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 - │ -611 │ ss2_neg("" ++ S) -> S. - │ ^ S. -Expression has type: [atom() | number()] -Context expected type: string() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:615:1 - │ -615 │ ss3("b" ++ S) -> S. - │ ^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:632:5 - │ -632 │ X. - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: bad_map_key (See https://fb.me/eqwalizer_errors#bad_map_key) - ┌─ check/src/misc.erl:641:5 - │ -641 │ atom() := atom(), - │ ^^^^^^^^^^^^^^ Map type will be approximated to #{dynamic() => dynamic()}, suppressing potential errors. -Use => instead of := here. Required map key should always be composed of statically defined atoms or tuples. - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:644:15 - │ -644 │ badspec(_) -> ok. - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: #{dynamic() => dynamic()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:648:21 - │ -648 │ catch lists:map({}, {}). - │ ^^ {}. -Expression has type: {} -Context expected type: fun((A) -> B) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:648:21 - │ -648 │ catch lists:map({}, {}). - │ ^^ {}. -Expression has type: {} -Context expected type: fun((dynamic()) -> dynamic()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:648:25 - │ -648 │ catch lists:map({}, {}). - │ ^^ {}. -Expression has type: {} -Context expected type: [A] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:648:25 - │ -648 │ catch lists:map({}, {}). - │ ^^ {}. -Expression has type: {} -Context expected type: [dynamic()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:652:26 - │ -652 │ X = (catch lists:map({}, {})), - │ ^^ {}. -Expression has type: {} -Context expected type: fun((A) -> B) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:652:26 - │ -652 │ X = (catch lists:map({}, {})), - │ ^^ {}. -Expression has type: {} -Context expected type: fun((dynamic()) -> dynamic()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:652:30 - │ -652 │ X = (catch lists:map({}, {})), - │ ^^ {}. -Expression has type: {} -Context expected type: [A] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:652:30 - │ -652 │ X = (catch lists:map({}, {})), - │ ^^ {}. -Expression has type: {} -Context expected type: [dynamic()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:671:5 - │ -671 │ [X, 1, 2, 3 | Y]. - │ ^^^^^^^^^^^^^^^^ [X, 1, 2, 3 | Y]. -Expression has type: [number() | dynamic()] -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:671:17 - │ -671 │ [X, 1, 2, 3 | Y]. - │ ^^^^ Y. -Expression has type: number() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:676:5 - │ -676 │ [X, 1, 2, 3 | an_atom]. - │ ^^^^^^^^^^^^^^^^^^^^^^ [X, 1, 2, 3 | 'an_atom']. -Expression has type: [number() | dynamic()] -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:676:17 - │ -676 │ [X, 1, 2, 3 | an_atom]. - │ ^^^^^^^^^^ 'an_atom'. -Expression has type: 'an_atom' -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:681:23 - │ -681 │ Res = [X, 1, 2, 3 | an_atom], - │ ^^^^^^^^^^ 'an_atom'. -Expression has type: 'an_atom' -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:682:5 - │ -682 │ Res. - │ ^^^ Res. -Expression has type: [number() | dynamic()] -Context expected type: pid() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:685:1 - │ -685 │ not_list1_neg("atom" ++ A) -> A. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:689:1 - │ -689 │ ╭ not_list2_neg -690 │ │ (A, [_ | A]) -> A. - │ ╰─────────────────────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:694:1 - │ -694 │ ╭ not_list3_neg -695 │ │ (A, "atom" ++ A) -> A. - │ ╰─────────────────────────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:728:1 - │ -728 │ ╭ test91_neg(None) -> -729 │ │ Res = {None, err}, -730 │ │ Res. - │ ╰───────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:730:5 - │ -730 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: {none(), 'err'} -Context expected type: {'ok', 'ok'} - │ - -Because in the expression's type: - { none(), - Here the type is: 'err' - 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 - │ -741 │ X. - │ ^ - │ │ - │ X. -Expression has type: v2_op() -Context expected type: v1_op() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: v1_op() - However the following candidate: 'v2_op' - Differs from the expected type: 'v1_op1' | 'v1_op2' | stuff() | v0_op() - ------------------------------- 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 - │ -760 │ -opaque o_cycle() :: opaque:o_cycle(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type o_cycle/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/misc.erl:762:1 - │ -762 │ ╭ -spec use_o_cycle1(misc:o_cycle()) -> -763 │ │ opaque:o_cycle(). - │ ╰────────────────────^ use_o_cycle1/1 references types with invalid definitions: o_cycle/0, opaque:o_cycle/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/misc.erl:766:1 - │ -766 │ ╭ -spec use_o_cycle2(opaque:o_cycle()) -> -767 │ │ misc:o_cycle(). - │ ╰──────────────────^ use_o_cycle2/1 references types with invalid definitions: o_cycle/0, opaque:o_cycle/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/misc.erl:783:1 - │ -783 │ ╭ -type x_cycle() :: -784 │ │ recursive_aliases:x_cycle(). - │ ╰───────────────────────────────^ recursive type x_cycle/0 is not productive - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/misc.erl:790:21 - │ -790 │ opaque:opair(a, x:y())) -> - │ ^^^^^ Unknown id: x:y/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:797:13 - │ -797 │ names(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: misc:set() -Context expected type: sets:set() - │ - -Because in the expression's type: - Here the type is: [] - 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 - │ -850 │ {ok, lists, 1.0}. - │ ^^^^^^^^^^^^^^^^ - │ │ - │ {'ok', 'lists', float_lit}. -Expression has type: {'ok', 'lists', number()} -Context expected type: {'ok', atom(), pid()} - │ - -Because in the expression's type: - { 'ok', 'lists', - Here the type is: number() - 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 - │ -860 │ Mod. - │ ^^^ Mod. -Expression has type: atom() -Context expected type: 'wrong_ret' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:875:5 - │ -875 │ Arity. - │ ^^^^^ Arity. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:887:5 - │ -887 │ Node. - │ ^^^^ Node. -Expression has type: atom() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:929:16 - │ -929 │ iovec_neg() -> {<<>>}. - │ ^^^^^^ - │ │ - │ {<<..>>}. -Expression has type: {binary()} -Context expected type: erlang:iovec() - │ - -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 - │ -949 │ n_a_neg(N) -> N. - │ ^ N. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:965:5 - │ -965 │ MyPriorities. - │ ^^^^^^^^^^^^ - │ │ - │ MyPriorities. -Expression has type: ['MM' | 'MS' | 'EE' | 'MA' | 'GE'] -Context expected type: [erlang:priority_level()] - │ - -Because in the expression's type: - [ - Here the type is: 'MM' | 'MS' | 'EE' | 'MA' | 'GE' - Context expects type: 'low' | 'normal' | 'high' | 'max' - 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 - │ -971 │ X. - │ ^ - │ │ - │ X. -Expression has type: erlang:timestamp() -Context expected type: atom() - │ - -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 - │ -987 │ Res = (Flag orelse Pid), - │ ^^^^ Flag. -Expression has type: atom() -Context expected type: boolean() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/misc.erl:1005:20 - │ -1005 │ orelse Validator(), - │ ^^^^^^^^^ Validator. -Expected fun type with arity 0 -Got: 'undefined' - -error: non_exported_id (See https://fb.me/eqwalizer_errors#non_exported_id) - ┌─ check/src/misc.erl:1008:23 - │ -1008 │ -spec non_exported_id(any_fun_type:f1()) -> any_fun_type:f1(). - │ ^^^^^^^^^^^^^^^^^ Type exists but is not exported: any_fun_type:f1/0 - -error: non_exported_id (See https://fb.me/eqwalizer_errors#non_exported_id) - ┌─ check/src/misc.erl:1011:30 - │ -1011 │ -type non_exported_id_t() :: any_fun_type:f1(). - │ ^^^^^^^^^^^^^^^^^ Type exists but is not exported: any_fun_type:f1/0 - -93 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/misc-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/misc-OTP-28.pretty deleted file mode 100644 index 22e373f816..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/misc-OTP-28.pretty +++ /dev/null @@ -1,1011 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:46:23 - │ -46 │ test03_neg(-4 = X) -> X. - │ ^ X. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:49:26 - │ -49 │ test04_neg(6 / 3 = Y) -> Y. - │ ^ Y. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:52:20 - │ -52 │ test05_neg(X) -> + X. - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:55:36 - │ -55 │ test06_neg(X) when is_number(X) -> + X. - │ ^^^ + _. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:63:5 - │ -63 │ not X. - │ ^^^^^ not _. -Expression has type: boolean() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:73:25 - │ -73 │ is_number(X) -> X + Y. - │ ^ Y. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:77:21 - │ -77 │ test11_neg(X, Y) -> X + Y. - │ ^^^^^ _ + _. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:81:19 - │ -81 │ test12_neg(X) -> -X. - │ ^ X. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:85:21 - │ -85 │ test13_neg(X, Y) -> X or Y. - │ ^ X. -Expression has type: term() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:85:26 - │ -85 │ test13_neg(X, Y) -> X or Y. - │ ^ Y. -Expression has type: term() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:97:21 - │ -97 │ test16_neg(X, Y) -> X or Y. - │ ^^^^^^ _ or _. -Expression has type: boolean() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:101:26 - │ -101 │ test17_neg(X, Y) -> X or Y. - │ ^ Y. -Expression has type: atom() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:105:21 - │ -105 │ test18_neg(X, Y) -> X orelse Y. - │ ^^^^^^^^^^ _ orelse _. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:109:21 - │ -109 │ test19_neg(X, Y) -> X andalso Y. - │ ^^^^^^^^^^^ _ andalso _. -Expression has type: 'false' | number() -Context expected type: {number()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:112:18 - │ -112 │ test20_neg(X) -> [- X]. - │ ^^^^^ - │ │ - │ [- _]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -116 │ test21_neg(X, Y) -> [X / Y]. - │ ^^^^^^^ - │ │ - │ [_ / _]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -120 │ test22_neg(X) -> [not X]. - │ ^^^^^^^ - │ │ - │ [not _]. -Expression has type: [boolean()] -Context expected type: [number()] - │ - -Because in the expression's type: - [ - Here the type is: boolean() - Context expects type: number() - ] - ------------------------------- Detailed message ------------------------------ - - [boolean()] is not compatible with [number()] - because - boolean() is not compatible with number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:124:21 - │ -124 │ test23_neg(X, Y) -> [X or Y]. - │ ^^^^^^^^ - │ │ - │ [_ or _]. -Expression has type: [boolean()] -Context expected type: [number()] - │ - -Because in the expression's type: - [ - Here the type is: boolean() - Context expects type: number() - ] - ------------------------------- Detailed message ------------------------------ - - [boolean()] is not compatible with [number()] - because - boolean() is not compatible with number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:128:21 - │ -128 │ test24_neg(X, Y) -> [X orelse Y]. - │ ^^^^^^^^^^^^ - │ │ - │ [_ orelse _]. -Expression has type: [atom()] -Context expected type: [number()] - │ - -Because in the expression's type: - [ - Here the type is: atom() - 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 - │ -143 │ test28_neg(B) -> boolean_id(B). - │ ^ B. -Expression has type: atom() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:146:17 - │ -146 │ test29_neg() -> [true, false]. - │ ^^^^^^^^^^^^^ - │ │ - │ ['true', 'false']. -Expression has type: ['true' | 'false'] -Context expected type: [] - │ - -Because in the expression's type: - [ - Here the type is: 'true' | 'false' - Context expects type: none() - No candidate of the expression's type matches the expected type. - ] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:149:17 - │ -149 │ test30_neg() -> 1. - │ ^ 1. -Expression has type: number() -Context expected type: 'atom' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:152:17 - │ -152 │ test31_neg() -> fun test30_neg/0. - │ ^^^^^^^^^^^^^^^^ test30_neg/0. -Expression has type: fun(() -> 'atom') -Context expected type: 'atom' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:155:17 - │ -155 │ test32_neg() -> fun misc_lib:boolean_id/1. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ misc_lib:boolean_id/1. -Expression has type: fun((boolean()) -> boolean()) -Context expected type: 'atom' - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:192:1 - │ -192 │ test40_pos({X, Y}) -> {X, Y}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:196:1 - │ -196 │ test41_pos([X | Y]) -> {X, Y}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:204:1 - │ -204 │ test43_pos([_ | Y]) when Y + 1 > 0 -> Y. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:221:17 - │ -221 │ test46_neg() -> false. - │ ^^^^^ 'false'. -Expression has type: 'false' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:224:17 - │ -224 │ test47_neg() -> []. - │ ^^ []. -Expression has type: [] -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:227:17 - │ -227 │ test48_neg() -> test47_neg(). - │ ^^^^^^^^^^^^ test47_neg(). -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:230:17 - │ -230 │ test49_neg() -> misc:test47_neg(). - │ ^^^^^^^^^^^^^^^^^ misc:test47_neg(). -Expression has type: number() -Context expected type: atom() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:337:1 - │ -337 │ test68_pos({E, _}) -> E. - │ ^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:352:22 - │ -352 │ catch test69_pos(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'. -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 - │ -404 │ after Timeout -> - │ ^^^^^^^ Timeout. -Expression has type: term() -Context expected type: timeout() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:412:11 - │ -412 │ after Timeout -> - │ ^^^^^^^ Timeout. -Expression has type: term() -Context expected type: timeout() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:424:5 - │ -424 │ {Msg}. - │ ^^^^^ {Msg}. -Expression has type: {'default' | dynamic('atom')} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:453:5 - │ -453 │ {[H1|T1], [H2|T2]}. - │ ^^^^^^^^^^^^^^^^^^ - │ │ - │ {[H1 | T1], [H2 | T2]}. -Expression has type: {[number() | atom()], [atom() | number()]} -Context expected type: {[atom()], [number()]} - │ - -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() - ] - , [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 - │ -461 │ {[H1|T1], [H2|T2]}. - │ ^^^^^^^^^^^^^^^^^^ - │ │ - │ {[H1 | T1], [H2 | T2]}. -Expression has type: {[atom() | number()], [atom() | number()]} -Context expected type: {[atom()] | [number()], [atom()] | [number()]} - │ - -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() - ] - , [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 - │ -465 │ X = [1 | 2], - │ ^^^^ 2. -Expression has type: number() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:472:21 - │ -472 │ comp01_neg(X, Y) -> X < Y. - │ ^^^^^ _ < _. -Expression has type: boolean() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:482:5 - │ -482 │ Res. - │ ^^^ Res. -Expression has type: boolean() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:497:5 - │ -497 │ Where ! What. - │ ^^^^^^^^^^^^ _ ! _. -Expression has type: term() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:507:20 - │ -507 │ #str_box{str = Str}. - │ ^^^ Str. -Expression has type: atom() -Context expected type: string() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:513:17 - │ -513 │ string_neg() -> "str". - │ ^^^^^ string_lit. -Expression has type: string() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:538:5 - │ -538 │ Atom. - │ ^^^^ Atom. -Expression has type: string() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:555:5 - │ -555 │ Atoms ++ Numbers. - │ ^^^^^^^^^^^^^^^^ - │ │ - │ _ ++ _. -Expression has type: [atom() | binary()] -Context expected type: [atom() | number()] - │ - -Because in the expression's type: - [ - Here the type is a union type with some valid candidates: atom() - However the following candidate: binary() - 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 - │ -575 │ Atoms -- Anys. - │ ^^^^ Anys. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:581:5 - │ -581 │ Anys ++ Atoms. - │ ^^^^ Anys. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:599:23 - │ -599 │ start_neg([] ++ X) -> X. - │ ^ - │ │ - │ X. -Expression has type: [A] -Context expected type: [[A]] - │ - -Because in the expression's type: - [ - Here the type is: A - 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 - │ -611 │ ss2_neg("" ++ S) -> S. - │ ^ S. -Expression has type: [atom() | number()] -Context expected type: string() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:615:1 - │ -615 │ ss3("b" ++ S) -> S. - │ ^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:632:5 - │ -632 │ X. - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: bad_map_key (See https://fb.me/eqwalizer_errors#bad_map_key) - ┌─ check/src/misc.erl:641:5 - │ -641 │ atom() := atom(), - │ ^^^^^^^^^^^^^^ Map type will be approximated to #{dynamic() => dynamic()}, suppressing potential errors. -Use => instead of := here. Required map key should always be composed of statically defined atoms or tuples. - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:644:15 - │ -644 │ badspec(_) -> ok. - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: #{dynamic() => dynamic()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:648:21 - │ -648 │ catch lists:map({}, {}). - │ ^^ {}. -Expression has type: {} -Context expected type: fun((A) -> B) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:648:21 - │ -648 │ catch lists:map({}, {}). - │ ^^ {}. -Expression has type: {} -Context expected type: fun((dynamic()) -> dynamic()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:648:25 - │ -648 │ catch lists:map({}, {}). - │ ^^ {}. -Expression has type: {} -Context expected type: [A] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:648:25 - │ -648 │ catch lists:map({}, {}). - │ ^^ {}. -Expression has type: {} -Context expected type: [dynamic()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:652:26 - │ -652 │ X = (catch lists:map({}, {})), - │ ^^ {}. -Expression has type: {} -Context expected type: fun((A) -> B) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:652:26 - │ -652 │ X = (catch lists:map({}, {})), - │ ^^ {}. -Expression has type: {} -Context expected type: fun((dynamic()) -> dynamic()) - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:652:30 - │ -652 │ X = (catch lists:map({}, {})), - │ ^^ {}. -Expression has type: {} -Context expected type: [A] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:652:30 - │ -652 │ X = (catch lists:map({}, {})), - │ ^^ {}. -Expression has type: {} -Context expected type: [dynamic()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:671:5 - │ -671 │ [X, 1, 2, 3 | Y]. - │ ^^^^^^^^^^^^^^^^ [X, 1, 2, 3 | Y]. -Expression has type: [number() | dynamic()] -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:671:17 - │ -671 │ [X, 1, 2, 3 | Y]. - │ ^^^^ Y. -Expression has type: number() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:676:5 - │ -676 │ [X, 1, 2, 3 | an_atom]. - │ ^^^^^^^^^^^^^^^^^^^^^^ [X, 1, 2, 3 | 'an_atom']. -Expression has type: [number() | dynamic()] -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:676:17 - │ -676 │ [X, 1, 2, 3 | an_atom]. - │ ^^^^^^^^^^ 'an_atom'. -Expression has type: 'an_atom' -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:681:23 - │ -681 │ Res = [X, 1, 2, 3 | an_atom], - │ ^^^^^^^^^^ 'an_atom'. -Expression has type: 'an_atom' -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:682:5 - │ -682 │ Res. - │ ^^^ Res. -Expression has type: [number() | dynamic()] -Context expected type: pid() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:685:1 - │ -685 │ not_list1_neg("atom" ++ A) -> A. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:689:1 - │ -689 │ ╭ not_list2_neg -690 │ │ (A, [_ | A]) -> A. - │ ╰─────────────────────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:694:1 - │ -694 │ ╭ not_list3_neg -695 │ │ (A, "atom" ++ A) -> A. - │ ╰─────────────────────────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/misc.erl:728:1 - │ -728 │ ╭ test91_neg(None) -> -729 │ │ Res = {None, err}, -730 │ │ Res. - │ ╰───────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:730:5 - │ -730 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: {none(), 'err'} -Context expected type: {'ok', 'ok'} - │ - -Because in the expression's type: - { none(), - Here the type is: 'err' - 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 - │ -741 │ X. - │ ^ - │ │ - │ X. -Expression has type: v2_op() -Context expected type: v1_op() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: v1_op() - However the following candidate: 'v2_op' - Differs from the expected type: 'v1_op1' | 'v1_op2' | stuff() | v0_op() - ------------------------------- 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 - │ -760 │ -opaque o_cycle() :: opaque:o_cycle(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type o_cycle/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/misc.erl:762:1 - │ -762 │ ╭ -spec use_o_cycle1(misc:o_cycle()) -> -763 │ │ opaque:o_cycle(). - │ ╰────────────────────^ use_o_cycle1/1 references types with invalid definitions: o_cycle/0, opaque:o_cycle/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/misc.erl:766:1 - │ -766 │ ╭ -spec use_o_cycle2(opaque:o_cycle()) -> -767 │ │ misc:o_cycle(). - │ ╰──────────────────^ use_o_cycle2/1 references types with invalid definitions: o_cycle/0, opaque:o_cycle/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/misc.erl:783:1 - │ -783 │ ╭ -type x_cycle() :: -784 │ │ recursive_aliases:x_cycle(). - │ ╰───────────────────────────────^ recursive type x_cycle/0 is not productive - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/misc.erl:790:21 - │ -790 │ opaque:opair(a, x:y())) -> - │ ^^^^^ Unknown id: x:y/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:797:13 - │ -797 │ names(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: misc:set() -Context expected type: sets:set() - │ - -Because in the expression's type: - Here the type is: [] - 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 - │ -850 │ {ok, lists, 1.0}. - │ ^^^^^^^^^^^^^^^^ - │ │ - │ {'ok', 'lists', float_lit}. -Expression has type: {'ok', 'lists', number()} -Context expected type: {'ok', atom(), pid()} - │ - -Because in the expression's type: - { 'ok', 'lists', - Here the type is: number() - 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 - │ -860 │ Mod. - │ ^^^ Mod. -Expression has type: atom() -Context expected type: 'wrong_ret' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:875:5 - │ -875 │ Arity. - │ ^^^^^ Arity. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:887:5 - │ -887 │ Node. - │ ^^^^ Node. -Expression has type: atom() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:929:16 - │ -929 │ iovec_neg() -> {<<>>}. - │ ^^^^^^ - │ │ - │ {<<..>>}. -Expression has type: {binary()} -Context expected type: erlang:iovec() - │ - -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 - │ -949 │ n_a_neg(N) -> N. - │ ^ N. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/misc.erl:965:5 - │ -965 │ MyPriorities. - │ ^^^^^^^^^^^^ - │ │ - │ MyPriorities. -Expression has type: ['MM' | 'MS' | 'EE' | 'MA' | 'GE'] -Context expected type: [erlang:priority_level()] - │ - -Because in the expression's type: - [ - Here the type is: 'MM' | 'MS' | 'EE' | 'MA' | 'GE' - Context expects type: 'low' | 'normal' | 'high' | 'max' - 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 - │ -971 │ X. - │ ^ - │ │ - │ X. -Expression has type: erlang:timestamp() -Context expected type: atom() - │ - -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 - │ -987 │ Res = (Flag orelse Pid), - │ ^^^^ Flag. -Expression has type: atom() -Context expected type: boolean() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/misc.erl:1005:20 - │ -1005 │ orelse Validator(), - │ ^^^^^^^^^ Validator. -Expected fun type with arity 0 -Got: 'undefined' - -error: non_exported_id (See https://fb.me/eqwalizer_errors#non_exported_id) - ┌─ check/src/misc.erl:1008:23 - │ -1008 │ -spec non_exported_id(any_fun_type:f1()) -> any_fun_type:f1(). - │ ^^^^^^^^^^^^^^^^^ Type exists but is not exported: any_fun_type:f1/0 - -error: non_exported_id (See https://fb.me/eqwalizer_errors#non_exported_id) - ┌─ check/src/misc.erl:1011:30 - │ -1011 │ -type non_exported_id_t() :: any_fun_type:f1(). - │ ^^^^^^^^^^^^^^^^^ Type exists but is not exported: any_fun_type:f1/0 - -93 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/misc-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/misc.pretty similarity index 85% rename from crates/elp/src/resources/test/eqwalizer_tests/check/misc-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/misc.pretty index 22e373f816..ec963a6249 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/misc-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/misc.pretty @@ -127,12 +127,6 @@ 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 │ @@ -150,12 +144,6 @@ 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 │ @@ -163,22 +151,16 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^^^^^^^ │ │ │ [not _]. -Expression has type: [boolean()] +Expression has type: ['false'] | ['true'] Context expected type: [number()] │ Because in the expression's type: [ - Here the type is: boolean() + Here the type is: 'false' Context expects type: number() ] ------------------------------- Detailed message ------------------------------ - - [boolean()] is not compatible with [number()] - because - boolean() is not compatible with number() - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:124:21 │ @@ -186,22 +168,16 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^^^^^^^^ │ │ │ [_ or _]. -Expression has type: [boolean()] +Expression has type: ['false'] | ['true'] Context expected type: [number()] │ Because in the expression's type: [ - Here the type is: boolean() + Here the type is: 'false' Context expects type: number() ] ------------------------------- Detailed message ------------------------------ - - [boolean()] is not compatible with [number()] - because - boolean() is not compatible with number() - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/misc.erl:128:21 │ @@ -219,12 +195,6 @@ 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 │ @@ -335,31 +305,17 @@ 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 @@ -405,17 +361,6 @@ 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 │ @@ -436,17 +381,6 @@ 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 │ @@ -521,16 +455,6 @@ 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 │ @@ -564,12 +488,6 @@ 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 │ @@ -764,13 +682,6 @@ 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 │ @@ -783,19 +694,9 @@ Context expected type: v1_op() │ Because in the expression's type: - Here the type is a union type with some valid candidates: v1_op() + Here the type is a union type with some valid candidates: 'stuff1' | 'v0_op2' | 'stuff2' | 'v0_op1' | 'v1_op2' | ... However the following candidate: 'v2_op' - Differs from the expected type: 'v1_op1' | 'v1_op2' | stuff() | v0_op() - ------------------------------- 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() + Differs from the expected type: 'stuff1' | 'v0_op2' | 'stuff2' | 'v0_op1' | 'v1_op2' | ... error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) ┌─ check/src/misc.erl:760:1 @@ -846,16 +747,6 @@ 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 │ @@ -873,13 +764,6 @@ 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 │ @@ -919,12 +803,6 @@ 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 │ @@ -951,14 +829,6 @@ 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 │ @@ -974,12 +844,6 @@ 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/detached_specs2-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/misc_lib.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs2-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/misc_lib.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested1-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested1-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested1-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs2-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested1.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs2-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested1.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested2-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested2-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested2-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested2-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested2-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested2-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested2-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested2-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested2-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs2-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested2.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/detached_specs2-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested2.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/my_behaviour-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/my_behaviour-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/my_behaviour-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/my_behaviour-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/my_behaviour-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/my_behaviour-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/my_behaviour-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/my_behaviour-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/my_behaviour-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_1-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/my_behaviour.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_1-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/my_behaviour.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/my_gradual_behaviour-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/my_gradual_behaviour-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/my_gradual_behaviour-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/my_gradual_behaviour-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/my_gradual_behaviour-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/my_gradual_behaviour-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/my_gradual_behaviour-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/my_gradual_behaviour-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/my_gradual_behaviour-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_1-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/my_gradual_behaviour.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_1-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/my_gradual_behaviour.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/my_header-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/my_header-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/my_header-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/my_header-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/my_header-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/my_header-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/my_header-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/my_header-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/my_header-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_1-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/my_header.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_1-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/my_header.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/neg-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/neg-OTP-26.pretty deleted file mode 100644 index 55ce8bf6f5..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/neg-OTP-26.pretty +++ /dev/null @@ -1,73 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/neg.erl:13:11 - │ -13 │ foo(X) -> {X, X}. - │ ^^^^^^ {X, X}. -Expression has type: {A, A} -Context expected type: A - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/neg.erl:17:5 - │ -17 │ X. - │ ^ X. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/neg.erl:20:14 - │ -20 │ foo(X, _) -> X. - │ ^ X. -Expression has type: term() -Context expected type: A - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/neg.erl:24:13 - │ -24 │ {ok, _} = X. - │ ^^^ - │ │ - │ match_expr. -Expression has type: {'ok', term()} -Context expected type: {atom(), atom()} - │ - -Because in the expression's type: - { 'ok', - Here the type is: term() - 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 - │ -27 │ concat1() -> [1] ++ 1. - │ ^ 1. -Expression has type: number() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/neg.erl:30:25 - │ -30 │ concat2(X, X) -> [1] ++ X. - │ ^ X. -Expression has type: X -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/neg.erl:33:25 - │ -33 │ concat3(X, X) -> [1] ++ X. - │ ^ X. -Expression has type: X -Context expected type: [term()] - -7 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/neg-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/neg-OTP-27.pretty deleted file mode 100644 index 55ce8bf6f5..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/neg-OTP-27.pretty +++ /dev/null @@ -1,73 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/neg.erl:13:11 - │ -13 │ foo(X) -> {X, X}. - │ ^^^^^^ {X, X}. -Expression has type: {A, A} -Context expected type: A - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/neg.erl:17:5 - │ -17 │ X. - │ ^ X. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/neg.erl:20:14 - │ -20 │ foo(X, _) -> X. - │ ^ X. -Expression has type: term() -Context expected type: A - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/neg.erl:24:13 - │ -24 │ {ok, _} = X. - │ ^^^ - │ │ - │ match_expr. -Expression has type: {'ok', term()} -Context expected type: {atom(), atom()} - │ - -Because in the expression's type: - { 'ok', - Here the type is: term() - 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 - │ -27 │ concat1() -> [1] ++ 1. - │ ^ 1. -Expression has type: number() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/neg.erl:30:25 - │ -30 │ concat2(X, X) -> [1] ++ X. - │ ^ X. -Expression has type: X -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/neg.erl:33:25 - │ -33 │ concat3(X, X) -> [1] ++ X. - │ ^ X. -Expression has type: X -Context expected type: [term()] - -7 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/neg-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/neg.pretty similarity index 90% rename from crates/elp/src/resources/test/eqwalizer_tests/check/neg-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/neg.pretty index 55ce8bf6f5..585b5f8642 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/neg-OTP-28.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/neg.pretty @@ -39,13 +39,6 @@ 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/nowarn-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/nowarn-OTP-27.pretty deleted file mode 100644 index 141f9e28db..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/nowarn-OTP-27.pretty +++ /dev/null @@ -1,21 +0,0 @@ -error: redundant_nowarn_function (See https://fb.me/eqwalizer_errors#redundant_nowarn_function) - ┌─ check/src/nowarn.erl:10:1 - │ -10 │ -eqwalizer({nowarn_function, nowarn_redundant/0}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ redundant nowarn_function - -error: redundant_nowarn_function (See https://fb.me/eqwalizer_errors#redundant_nowarn_function) - ┌─ check/src/nowarn.erl:11:1 - │ -11 │ -eqwalizer({nowarn_function, nowarn_nonexist/0}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ redundant nowarn_function - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/nowarn.erl:21:3 - │ -21 │ ok. - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: number() - -3 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/nowarn-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/nowarn-OTP-28.pretty deleted file mode 100644 index 141f9e28db..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/nowarn-OTP-28.pretty +++ /dev/null @@ -1,21 +0,0 @@ -error: redundant_nowarn_function (See https://fb.me/eqwalizer_errors#redundant_nowarn_function) - ┌─ check/src/nowarn.erl:10:1 - │ -10 │ -eqwalizer({nowarn_function, nowarn_redundant/0}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ redundant nowarn_function - -error: redundant_nowarn_function (See https://fb.me/eqwalizer_errors#redundant_nowarn_function) - ┌─ check/src/nowarn.erl:11:1 - │ -11 │ -eqwalizer({nowarn_function, nowarn_nonexist/0}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ redundant nowarn_function - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/nowarn.erl:21:3 - │ -21 │ ok. - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: number() - -3 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/nowarn-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/nowarn.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/nowarn-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/nowarn.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/number_comparisons-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/number_comparisons-OTP-27.pretty deleted file mode 100644 index cec080fa3e..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/number_comparisons-OTP-27.pretty +++ /dev/null @@ -1,17 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/number_comparisons.erl:11:30 - │ -11 │ test_1_neg(X) when X >= 1 -> X. - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/number_comparisons.erl:253:3 - │ -253 │ X. - │ ^ X. -Expression has type: number() -Context expected type: none() - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/number_comparisons-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/number_comparisons-OTP-28.pretty deleted file mode 100644 index cec080fa3e..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/number_comparisons-OTP-28.pretty +++ /dev/null @@ -1,17 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/number_comparisons.erl:11:30 - │ -11 │ test_1_neg(X) when X >= 1 -> X. - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/number_comparisons.erl:253:3 - │ -253 │ X. - │ ^ X. -Expression has type: number() -Context expected type: none() - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/number_comparisons-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/number_comparisons.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/number_comparisons-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/number_comparisons.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/numbers-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/numbers-OTP-26.pretty deleted file mode 100644 index 8760657fa4..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/numbers-OTP-26.pretty +++ /dev/null @@ -1,318 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:121:3 - │ -121 │ A / 2. - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:125:7 - │ -125 │ 2 / A. - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:129:7 - │ -129 │ 2 * A. - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:133:3 - │ -133 │ A * 2. - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:137:7 - │ -137 │ X = A * 2, - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:142:9 - │ -142 │ 2 div A. - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:146:14 - │ -146 │ X = (2 div A), - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:151:3 - │ -151 │ A div 2. - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:155:7 - │ -155 │ X = A div 2, - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:160:3 - │ -160 │ 1 div 2. - │ ^^^^^^^ _ div _. -Expression has type: number() -Context expected type: 'a' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:182:3 - │ -182 │ bnot 0. - │ ^^^^^^ bnot _. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:350:5 - │ -350 │ (+X). - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:354:9 - │ -354 │ _ = (+X), - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:359:9 - │ -359 │ _ = (-X), - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:364:9 - │ -364 │ _ = (-X), - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:428:8 - │ -428 │ bnot X. - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:433:12 - │ -433 │ _ = bnot X, - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:491:3 - │ -491 │ U * N. - │ ^ - │ │ - │ U. -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' is not compatible with number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/numbers.erl:538:1 - │ -538 │ ╭ test_85(X) -> -539 │ │ X div X. - │ ╰─────────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/numbers.erl:544:1 - │ -544 │ ╭ test_86(X) -> -545 │ │ X * X. - │ ╰───────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:552:3 - │ -552 │ U1 div U2 / (U2 bsl U1). - │ ^^ U1. -Expression has type: 'a' | 'b' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:552:10 - │ -552 │ U1 div U2 / (U2 bsl U1). - │ ^^ U2. -Expression has type: 'c' | 'd' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:552:16 - │ -552 │ U1 div U2 / (U2 bsl U1). - │ ^^ U2. -Expression has type: 'c' | 'd' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:552:23 - │ -552 │ U1 div U2 / (U2 bsl U1). - │ ^^ U1. -Expression has type: 'a' | 'b' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:559:3 - │ -559 │ U1 * U2 / (U2 + U1). - │ ^^ U1. -Expression has type: 'a' | 'b' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:559:8 - │ -559 │ U1 * U2 / (U2 + U1). - │ ^^ U2. -Expression has type: 'c' | 'd' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:559:14 - │ -559 │ U1 * U2 / (U2 + U1). - │ ^^ U2. -Expression has type: 'c' | 'd' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:559:19 - │ -559 │ U1 * U2 / (U2 + U1). - │ ^^ U1. -Expression has type: 'a' | 'b' -Context expected type: number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/numbers.erl:576:1 - │ -576 │ ╭ test_91_neg(X) -> -577 │ │ -X. - │ ╰────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:577:3 - │ -577 │ -X. - │ ^^ - _. -Expression has type: number() -Context expected type: none() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/numbers.erl:582:1 - │ -582 │ ╭ test_92_neg(X) -> -583 │ │ bnot X. - │ ╰────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:583:3 - │ -583 │ bnot X. - │ ^^^^^^ bnot _. -Expression has type: number() -Context expected type: none() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/numbers.erl:588:1 - │ -588 │ ╭ test_93_neg(X) -> -589 │ │ 5 * X. - │ ╰───────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:589:3 - │ -589 │ 5 * X. - │ ^^^^^ _ * _. -Expression has type: number() -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:644:3 - │ -644 │ ╭ ╭ { -645 │ │ │ 1, -646 │ │ │ 0, -647 │ │ │ -1, -648 │ │ │ Int, -649 │ │ │ error -650 │ │ │ }. - │ ╰─│───^ {1, 0, - _, Int, 'error'}. -Expression has type: {number(), number(), number(), number(), 'error'} -Context expected type: {number(), number(), number(), number(), 'ok'} - │ ╰───' - -Because in the expression's type: - { number(), number(), number(), number(), - Here the type is: 'error' - 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 - │ -658 │ 1.0. - │ ^^^ float_lit. -Expression has type: number() -Context expected type: pid() - -36 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/numbers-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/numbers-OTP-28.pretty deleted file mode 100644 index 8760657fa4..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/numbers-OTP-28.pretty +++ /dev/null @@ -1,318 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:121:3 - │ -121 │ A / 2. - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:125:7 - │ -125 │ 2 / A. - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:129:7 - │ -129 │ 2 * A. - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:133:3 - │ -133 │ A * 2. - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:137:7 - │ -137 │ X = A * 2, - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:142:9 - │ -142 │ 2 div A. - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:146:14 - │ -146 │ X = (2 div A), - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:151:3 - │ -151 │ A div 2. - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:155:7 - │ -155 │ X = A div 2, - │ ^ A. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:160:3 - │ -160 │ 1 div 2. - │ ^^^^^^^ _ div _. -Expression has type: number() -Context expected type: 'a' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:182:3 - │ -182 │ bnot 0. - │ ^^^^^^ bnot _. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:350:5 - │ -350 │ (+X). - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:354:9 - │ -354 │ _ = (+X), - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:359:9 - │ -359 │ _ = (-X), - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:364:9 - │ -364 │ _ = (-X), - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:428:8 - │ -428 │ bnot X. - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:433:12 - │ -433 │ _ = bnot X, - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:491:3 - │ -491 │ U * N. - │ ^ - │ │ - │ U. -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' is not compatible with number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/numbers.erl:538:1 - │ -538 │ ╭ test_85(X) -> -539 │ │ X div X. - │ ╰─────────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/numbers.erl:544:1 - │ -544 │ ╭ test_86(X) -> -545 │ │ X * X. - │ ╰───────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:552:3 - │ -552 │ U1 div U2 / (U2 bsl U1). - │ ^^ U1. -Expression has type: 'a' | 'b' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:552:10 - │ -552 │ U1 div U2 / (U2 bsl U1). - │ ^^ U2. -Expression has type: 'c' | 'd' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:552:16 - │ -552 │ U1 div U2 / (U2 bsl U1). - │ ^^ U2. -Expression has type: 'c' | 'd' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:552:23 - │ -552 │ U1 div U2 / (U2 bsl U1). - │ ^^ U1. -Expression has type: 'a' | 'b' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:559:3 - │ -559 │ U1 * U2 / (U2 + U1). - │ ^^ U1. -Expression has type: 'a' | 'b' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:559:8 - │ -559 │ U1 * U2 / (U2 + U1). - │ ^^ U2. -Expression has type: 'c' | 'd' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:559:14 - │ -559 │ U1 * U2 / (U2 + U1). - │ ^^ U2. -Expression has type: 'c' | 'd' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:559:19 - │ -559 │ U1 * U2 / (U2 + U1). - │ ^^ U1. -Expression has type: 'a' | 'b' -Context expected type: number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/numbers.erl:576:1 - │ -576 │ ╭ test_91_neg(X) -> -577 │ │ -X. - │ ╰────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:577:3 - │ -577 │ -X. - │ ^^ - _. -Expression has type: number() -Context expected type: none() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/numbers.erl:582:1 - │ -582 │ ╭ test_92_neg(X) -> -583 │ │ bnot X. - │ ╰────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:583:3 - │ -583 │ bnot X. - │ ^^^^^^ bnot _. -Expression has type: number() -Context expected type: none() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/numbers.erl:588:1 - │ -588 │ ╭ test_93_neg(X) -> -589 │ │ 5 * X. - │ ╰───────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:589:3 - │ -589 │ 5 * X. - │ ^^^^^ _ * _. -Expression has type: number() -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/numbers.erl:644:3 - │ -644 │ ╭ ╭ { -645 │ │ │ 1, -646 │ │ │ 0, -647 │ │ │ -1, -648 │ │ │ Int, -649 │ │ │ error -650 │ │ │ }. - │ ╰─│───^ {1, 0, - _, Int, 'error'}. -Expression has type: {number(), number(), number(), number(), 'error'} -Context expected type: {number(), number(), number(), number(), 'ok'} - │ ╰───' - -Because in the expression's type: - { number(), number(), number(), number(), - Here the type is: 'error' - 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 - │ -658 │ 1.0. - │ ^^^ float_lit. -Expression has type: number() -Context expected type: pid() - -36 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/numbers-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/numbers.pretty similarity index 95% rename from crates/elp/src/resources/test/eqwalizer_tests/check/numbers-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/numbers.pretty index 8760657fa4..8c78c1ffbe 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/numbers-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/numbers.pretty @@ -150,12 +150,6 @@ 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 │ @@ -300,13 +294,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/opaque-OTP-26.pretty deleted file mode 100644 index eea53f78f7..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/opaque-OTP-26.pretty +++ /dev/null @@ -1,179 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/opaque.erl:23:3 - │ -23 │ X. - │ ^ - │ │ - │ X. -Expression has type: sets:set({'ok', 'error'}) -Context expected type: sets:set({'ok', 'ok'}) - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #set{} - However the following candidate: #{{ok, error} => []} - Differs from the expected type: #set{} | #{{ok, ok} => []} - ------------------------------- 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 - │ -29 │ test2_neg(X=#{a := b}) -> X. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/opaque.erl:57:11 - │ -57 │ X2 - │ ^^ - │ │ - │ X2. -Expression has type: misc:o() -Context expected type: none() - │ - -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 - │ -86 │ ╭ test10({rec_w_opaque_field, -87 │ │ {_, _}} -88 │ │ ) -> ok. - │ ╰───────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/opaque.erl:95:6 - │ -95 │ ) -> X. - │ ^ X. -Expression has type: 'ok' -Context expected type: {'ok'} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/opaque.erl:107:18 - │ -107 │ test14_neg(X) -> X =:= {ok}. - │ ^^^^^^^^^^ _ =:= _. -Expression has type: boolean() -Context expected type: 'true' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/opaque.erl:125:18 - │ -125 │ test18_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: misc:o() | 'a' -Context expected type: misc:o() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: misc:o() - 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 - │ -135 │ test20_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: misc:o() | 'a' -Context expected type: misc:o() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: misc:o() - 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 - │ -150 │ -opaque o_cycle() :: misc:o_cycle(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type o_cycle/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/opaque.erl:152:1 - │ -152 │ ╭ -spec use_o_cycle1(misc:o_cycle()) -> -153 │ │ opaque:o_cycle(). - │ ╰──────────────────^ use_o_cycle1/1 references types with invalid definitions: misc:o_cycle/0, o_cycle/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/opaque.erl:156:1 - │ -156 │ ╭ -spec use_o_cycle2(opaque:o_cycle()) -> -157 │ │ misc:o_cycle(). - │ ╰────────────────^ use_o_cycle2/1 references types with invalid definitions: misc:o_cycle/0, o_cycle/0 - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/opaque.erl:236:1 - │ -236 │ ╭ test29_neg(X) when X =:= {1.0} -> -237 │ │ ok. - │ ╰────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/opaque.erl:240:1 - │ -240 │ ╭ test30_neg(X) when X =:= "" -> -241 │ │ ok. - │ ╰────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/opaque.erl:256:1 - │ -256 │ ╭ test34_neg(X) when X =:= <<>> -> -257 │ │ ok. - │ ╰────^ Clause is not covered by spec - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ check/src/opaque.erl:288:1 - │ -288 │ -type invalid() :: _T. - │ ^^^^^^^^^^^^^^^^^^^^^ _T: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/opaque.erl:290:1 - │ -290 │ -opaque o_trans_invalid() :: invalid(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ o_trans_invalid/0 references type with invalid definition: invalid/0 - -16 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/opaque-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/opaque-OTP-28.pretty deleted file mode 100644 index eea53f78f7..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/opaque-OTP-28.pretty +++ /dev/null @@ -1,179 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/opaque.erl:23:3 - │ -23 │ X. - │ ^ - │ │ - │ X. -Expression has type: sets:set({'ok', 'error'}) -Context expected type: sets:set({'ok', 'ok'}) - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #set{} - However the following candidate: #{{ok, error} => []} - Differs from the expected type: #set{} | #{{ok, ok} => []} - ------------------------------- 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 - │ -29 │ test2_neg(X=#{a := b}) -> X. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/opaque.erl:57:11 - │ -57 │ X2 - │ ^^ - │ │ - │ X2. -Expression has type: misc:o() -Context expected type: none() - │ - -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 - │ -86 │ ╭ test10({rec_w_opaque_field, -87 │ │ {_, _}} -88 │ │ ) -> ok. - │ ╰───────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/opaque.erl:95:6 - │ -95 │ ) -> X. - │ ^ X. -Expression has type: 'ok' -Context expected type: {'ok'} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/opaque.erl:107:18 - │ -107 │ test14_neg(X) -> X =:= {ok}. - │ ^^^^^^^^^^ _ =:= _. -Expression has type: boolean() -Context expected type: 'true' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/opaque.erl:125:18 - │ -125 │ test18_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: misc:o() | 'a' -Context expected type: misc:o() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: misc:o() - 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 - │ -135 │ test20_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: misc:o() | 'a' -Context expected type: misc:o() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: misc:o() - 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 - │ -150 │ -opaque o_cycle() :: misc:o_cycle(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type o_cycle/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/opaque.erl:152:1 - │ -152 │ ╭ -spec use_o_cycle1(misc:o_cycle()) -> -153 │ │ opaque:o_cycle(). - │ ╰──────────────────^ use_o_cycle1/1 references types with invalid definitions: misc:o_cycle/0, o_cycle/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/opaque.erl:156:1 - │ -156 │ ╭ -spec use_o_cycle2(opaque:o_cycle()) -> -157 │ │ misc:o_cycle(). - │ ╰────────────────^ use_o_cycle2/1 references types with invalid definitions: misc:o_cycle/0, o_cycle/0 - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/opaque.erl:236:1 - │ -236 │ ╭ test29_neg(X) when X =:= {1.0} -> -237 │ │ ok. - │ ╰────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/opaque.erl:240:1 - │ -240 │ ╭ test30_neg(X) when X =:= "" -> -241 │ │ ok. - │ ╰────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/opaque.erl:256:1 - │ -256 │ ╭ test34_neg(X) when X =:= <<>> -> -257 │ │ ok. - │ ╰────^ Clause is not covered by spec - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ check/src/opaque.erl:288:1 - │ -288 │ -type invalid() :: _T. - │ ^^^^^^^^^^^^^^^^^^^^^ _T: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/opaque.erl:290:1 - │ -290 │ -opaque o_trans_invalid() :: invalid(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ o_trans_invalid/0 references type with invalid definition: invalid/0 - -16 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/opaque-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/opaque.pretty similarity index 80% rename from crates/elp/src/resources/test/eqwalizer_tests/check/opaque-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/opaque.pretty index eea53f78f7..5c207ff164 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/opaque-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/opaque.pretty @@ -10,19 +10,11 @@ Context expected type: sets:set({'ok', 'ok'}) │ Because in the expression's type: - Here the type is a union type with some valid candidates: #set{} - However the following candidate: #{{ok, error} => []} - Differs from the expected type: #set{} | #{{ok, ok} => []} - ------------------------------- 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} => []} + The type is a union type with some valid candidates: #set{} + However, the following candidate doesn't match: + Here the type is: #{{ok, error} => ...} + Context expects type: #{...} + The expected map has no corresponding key for: {ok, error}. error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) ┌─ check/src/opaque.erl:29:1 @@ -45,12 +37,6 @@ 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 │ @@ -91,14 +77,6 @@ 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 │ @@ -115,14 +93,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/other-OTP-26.pretty deleted file mode 100644 index 20764acf15..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/other-OTP-26.pretty +++ /dev/null @@ -1,22 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/other.erl:46:27 - │ -46 │ any_as_metadata_neg(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: term() -Context expected type: logger:metadata() - │ - -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()} - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/other-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/other-OTP-27.pretty deleted file mode 100644 index 20764acf15..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/other-OTP-27.pretty +++ /dev/null @@ -1,22 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/other.erl:46:27 - │ -46 │ any_as_metadata_neg(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: term() -Context expected type: logger:metadata() - │ - -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()} - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/other-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/other.pretty similarity index 55% rename from crates/elp/src/resources/test/eqwalizer_tests/check/other-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/other.pretty index 20764acf15..da1b4e48cb 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/other-OTP-28.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/other.pretty @@ -13,10 +13,10 @@ Because in the expression's type: Here the type is: term() Context expects type: #{...} ------------------------------- Detailed message ------------------------------ +error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) + ┌─ check/src/other.erl:59:27 + │ +59 │ eqwalizer:reveal_type(X), + │ ^ number() - 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()} - -1 ERROR +2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/otp28-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/otp28-OTP-26.pretty deleted file mode 100644 index 026d55c435..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/otp28-OTP-26.pretty +++ /dev/null @@ -1,159 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/otp28.erl:16:21 - │ -16 │ mk_nominal_neg() -> warning. - │ ^^^^^^^ - │ │ - │ 'warning'. -Expression has type: 'warning' -Context expected type: foo() - │ - -Because in the expression's type: - Here the type is: 'warning' - 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 - │ -28 │ [N || {_, N} <:- L]. - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -40 │ [Bin || _ := {error, Bin} <:- L]. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: [binary()] -Context expected type: [pid()] - │ - -Because in the expression's type: - [ - Here the type is: binary() - 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 - │ -52 │ #{K => Bin || {K, {ok, Bin}} <:- L}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{ || }. -Expression has type: #{atom() => binary()} -Context expected type: [#{atom() => pid()}] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/otp28.erl:60:5 - │ -60 │ [{A, B} || A <- As && B <- Bs]. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -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()}] - 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 - │ -68 │ #{A => B || A <- As && B <- Bs}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #{ || }. -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/otp28.erl:76:5 - │ -76 │ [{A, B, V, K} || A <- As && B <- Bs && K := V <- M]. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: [{atom(), binary(), binary(), atom()}] -Context expected type: [{atom(), binary(), atom(), binary()}] - │ - -Because in the expression's type: - [ - { atom(), binary(), - Here the type is: binary() - Context expects type: atom() - , 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/otp28-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/otp28-OTP-28.pretty deleted file mode 100644 index 026d55c435..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/otp28-OTP-28.pretty +++ /dev/null @@ -1,159 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/otp28.erl:16:21 - │ -16 │ mk_nominal_neg() -> warning. - │ ^^^^^^^ - │ │ - │ 'warning'. -Expression has type: 'warning' -Context expected type: foo() - │ - -Because in the expression's type: - Here the type is: 'warning' - 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 - │ -28 │ [N || {_, N} <:- L]. - │ ^^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: [number()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: number() - 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 - │ -40 │ [Bin || _ := {error, Bin} <:- L]. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: [binary()] -Context expected type: [pid()] - │ - -Because in the expression's type: - [ - Here the type is: binary() - 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 - │ -52 │ #{K => Bin || {K, {ok, Bin}} <:- L}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{ || }. -Expression has type: #{atom() => binary()} -Context expected type: [#{atom() => pid()}] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/otp28.erl:60:5 - │ -60 │ [{A, B} || A <- As && B <- Bs]. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -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()}] - 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 - │ -68 │ #{A => B || A <- As && B <- Bs}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #{ || }. -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/otp28.erl:76:5 - │ -76 │ [{A, B, V, K} || A <- As && B <- Bs && K := V <- M]. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ [ || ]. -Expression has type: [{atom(), binary(), binary(), atom()}] -Context expected type: [{atom(), binary(), atom(), binary()}] - │ - -Because in the expression's type: - [ - { atom(), binary(), - Here the type is: binary() - Context expects type: atom() - , 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/otp28-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/otp28.pretty similarity index 68% rename from crates/elp/src/resources/test/eqwalizer_tests/check/otp28-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/otp28.pretty index 026d55c435..5113f80c15 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/otp28-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/otp28.pretty @@ -14,14 +14,6 @@ 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 │ @@ -39,12 +31,6 @@ 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 │ @@ -62,12 +48,6 @@ 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 │ @@ -95,15 +75,6 @@ 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 │ @@ -121,13 +92,6 @@ 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 │ @@ -147,13 +111,4 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques-OTP-26.pretty deleted file mode 100644 index b41039f95b..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques-OTP-26.pretty +++ /dev/null @@ -1,126 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/otp_opaques.erl:18:5 - │ -18 │ gb_sets:from_list(Atoms). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ gb_sets:from_list(Atoms). -Expression has type: gb_sets:set(atom()) -Context expected type: gb_sets:set(number()) - │ - -Because in the expression's type: - { number(), - { - Here the type is: atom() - Context expects type: number() - , 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 - │ -42 │ List. - │ ^^^^ - │ │ - │ List. -Expression has type: [[A]] -Context expected type: [A] - │ - -Because in the expression's type: - [ - Here the type is: [A] - 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 - │ -99 │ test3_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: maps:iterator('k', 'v') -Context expected type: sets:set('a') - │ - -Because in the expression's type: - Here the type is: tuple()/3 | 'none' | [...] | [...] - 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 - │ -102 │ ts(X, X) -> X. - │ ^ X. -Expression has type: #set{} | #{a => []} -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/otp_opaques.erl:107:11 - │ -107 │ ts(X, X), - │ ^ - │ │ - │ X. -Expression has type: maps:iterator('k', 'v') -Context expected type: sets:set('a') - │ - -Because in the expression's type: - Here the type is: tuple()/3 | 'none' | [...] | [...] - 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 - │ -124 │ X(). - │ ^ X. -Expected fun type with arity 0 -Got: maps:iterator('k', 'v') | sets:set('a') - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/otp_opaques.erl:130:5 - │ -130 │ X(). - │ ^ X. -Expected fun type with arity 0 -Got: sets:set('a') - -7 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques-OTP-28.pretty deleted file mode 100644 index b41039f95b..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques-OTP-28.pretty +++ /dev/null @@ -1,126 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/otp_opaques.erl:18:5 - │ -18 │ gb_sets:from_list(Atoms). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ gb_sets:from_list(Atoms). -Expression has type: gb_sets:set(atom()) -Context expected type: gb_sets:set(number()) - │ - -Because in the expression's type: - { number(), - { - Here the type is: atom() - Context expects type: number() - , 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 - │ -42 │ List. - │ ^^^^ - │ │ - │ List. -Expression has type: [[A]] -Context expected type: [A] - │ - -Because in the expression's type: - [ - Here the type is: [A] - 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 - │ -99 │ test3_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: maps:iterator('k', 'v') -Context expected type: sets:set('a') - │ - -Because in the expression's type: - Here the type is: tuple()/3 | 'none' | [...] | [...] - 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 - │ -102 │ ts(X, X) -> X. - │ ^ X. -Expression has type: #set{} | #{a => []} -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/otp_opaques.erl:107:11 - │ -107 │ ts(X, X), - │ ^ - │ │ - │ X. -Expression has type: maps:iterator('k', 'v') -Context expected type: sets:set('a') - │ - -Because in the expression's type: - Here the type is: tuple()/3 | 'none' | [...] | [...] - 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 - │ -124 │ X(). - │ ^ X. -Expected fun type with arity 0 -Got: maps:iterator('k', 'v') | sets:set('a') - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ check/src/otp_opaques.erl:130:5 - │ -130 │ X(). - │ ^ X. -Expected fun type with arity 0 -Got: sets:set('a') - -7 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques.pretty similarity index 65% rename from crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques.pretty index b41039f95b..59bd5e6099 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/otp_opaques.pretty @@ -17,17 +17,6 @@ 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 │ @@ -45,12 +34,6 @@ 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 │ @@ -67,14 +50,6 @@ 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 │ @@ -99,14 +74,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded-OTP-26.pretty deleted file mode 100644 index 117ed8b349..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded-OTP-26.pretty +++ /dev/null @@ -1,160 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:29:5 - │ -29 │ B. - │ ^ B. -Expression has type: binary() -Context expected type: atom() - -error: ambiguous_lambda (See https://fb.me/eqwalizer_errors#ambiguous_lambda) - ┌─ check/src/overloaded.erl:102:15 - │ -102 │ Res = bar(fun(a) -> a end), - │ ^^^^^^^^^^^^^^^ fun. -Functional expression can match multiple types in fun(('a') -> 'b') | fun(('a') -> 'c') - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:117:15 - │ -117 │ Res = bar(F), - │ ^ - │ │ - │ F. -Expression has type: fun(('a') -> 'z') -Context expected type: fun(('a') -> 'b') | fun(('a') -> 'c') - │ - -Because in the expression's type: - fun(('a') -> - Here the type is: 'z' - 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}. -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 - │ -198 │ overlap_neg_1(X) when is_atom(X) -> 1; - │ ^ 1. -Expression has type: number() -Context expected type: {T} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:203:37 - │ -203 │ overlap_neg_2(X) when is_atom(X) -> 1; - │ ^ 1. -Expression has type: number() -Context expected type: {T} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:204:22 - │ -204 │ overlap_neg_2(_X) -> 1. - │ ^ 1. -Expression has type: number() -Context expected type: {T} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:246:23 - │ -246 │ take_ok_or_any(ok) -> ok; - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: 'error' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:247:22 - │ -247 │ take_ok_or_any(_) -> error. - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:259:21 - │ -259 │ use_over(X) -> over(X). - │ ^ - │ │ - │ X. -Expression has type: 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: {} - 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 - │ -261 │ -type invalid() :: _T. - │ ^^^^^^^^^^^^^^^^^^^^^ _T: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/overloaded.erl:263:1 - │ -263 │ ╭ -spec use_invalid_neg(a) -> a; -264 │ │ (err) -> invalid(). - │ ╰─────────────────────────────────^ use_invalid_neg/1 references type with invalid definition: invalid/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:269:14 - │ -269 │ _ = swap(""), - │ ^^ - │ │ - │ 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 - │ -290 │ swap(ok). - │ ^^^^^^^^ swap('ok'). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:308:19 - │ -308 │ reachable_3(_) -> b. - │ ^ 'b'. -Expression has type: 'b' -Context expected type: 'a' - -15 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded-OTP-27.pretty deleted file mode 100644 index 117ed8b349..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded-OTP-27.pretty +++ /dev/null @@ -1,160 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:29:5 - │ -29 │ B. - │ ^ B. -Expression has type: binary() -Context expected type: atom() - -error: ambiguous_lambda (See https://fb.me/eqwalizer_errors#ambiguous_lambda) - ┌─ check/src/overloaded.erl:102:15 - │ -102 │ Res = bar(fun(a) -> a end), - │ ^^^^^^^^^^^^^^^ fun. -Functional expression can match multiple types in fun(('a') -> 'b') | fun(('a') -> 'c') - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:117:15 - │ -117 │ Res = bar(F), - │ ^ - │ │ - │ F. -Expression has type: fun(('a') -> 'z') -Context expected type: fun(('a') -> 'b') | fun(('a') -> 'c') - │ - -Because in the expression's type: - fun(('a') -> - Here the type is: 'z' - 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}. -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 - │ -198 │ overlap_neg_1(X) when is_atom(X) -> 1; - │ ^ 1. -Expression has type: number() -Context expected type: {T} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:203:37 - │ -203 │ overlap_neg_2(X) when is_atom(X) -> 1; - │ ^ 1. -Expression has type: number() -Context expected type: {T} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:204:22 - │ -204 │ overlap_neg_2(_X) -> 1. - │ ^ 1. -Expression has type: number() -Context expected type: {T} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:246:23 - │ -246 │ take_ok_or_any(ok) -> ok; - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: 'error' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:247:22 - │ -247 │ take_ok_or_any(_) -> error. - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:259:21 - │ -259 │ use_over(X) -> over(X). - │ ^ - │ │ - │ X. -Expression has type: 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: {} - 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 - │ -261 │ -type invalid() :: _T. - │ ^^^^^^^^^^^^^^^^^^^^^ _T: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/overloaded.erl:263:1 - │ -263 │ ╭ -spec use_invalid_neg(a) -> a; -264 │ │ (err) -> invalid(). - │ ╰─────────────────────────────────^ use_invalid_neg/1 references type with invalid definition: invalid/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:269:14 - │ -269 │ _ = swap(""), - │ ^^ - │ │ - │ 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 - │ -290 │ swap(ok). - │ ^^^^^^^^ swap('ok'). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded.erl:308:19 - │ -308 │ reachable_3(_) -> b. - │ ^ 'b'. -Expression has type: 'b' -Context expected type: 'a' - -15 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded.pretty similarity index 84% rename from crates/elp/src/resources/test/eqwalizer_tests/check/overloaded-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/overloaded.pretty index 117ed8b349..aa87b295ad 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded-OTP-28.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded.pretty @@ -30,26 +30,13 @@ 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 @@ -107,12 +94,6 @@ 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 │ @@ -130,16 +111,9 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded_specs_union-OTP-26.pretty deleted file mode 100644 index 3483635724..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded_specs_union-OTP-26.pretty +++ /dev/null @@ -1,47 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded_specs_union.erl:16:29 - │ -16 │ use_over_neg_1(Arg) -> over(Arg). - │ ^^^ - │ │ - │ Arg. -Expression has type: atom() | pid() -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: 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 - │ -19 │ use_over_neg_2(Arg) -> over(Arg). - │ ^^^ - │ │ - │ Arg. -Expression has type: atom() | binary() | pid() -Context expected type: atom() | binary() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: atom() | binary() - 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/overloaded_specs_union-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded_specs_union-OTP-27.pretty deleted file mode 100644 index 3483635724..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded_specs_union-OTP-27.pretty +++ /dev/null @@ -1,47 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/overloaded_specs_union.erl:16:29 - │ -16 │ use_over_neg_1(Arg) -> over(Arg). - │ ^^^ - │ │ - │ Arg. -Expression has type: atom() | pid() -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: 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 - │ -19 │ use_over_neg_2(Arg) -> over(Arg). - │ ^^^ - │ │ - │ Arg. -Expression has type: atom() | binary() | pid() -Context expected type: atom() | binary() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: atom() | binary() - 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/overloaded_specs_union-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded_specs_union.pretty similarity index 74% rename from crates/elp/src/resources/test/eqwalizer_tests/check/overloaded_specs_union-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/overloaded_specs_union.pretty index 3483635724..6687ec3321 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded_specs_union-OTP-28.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/overloaded_specs_union.pretty @@ -14,12 +14,6 @@ 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 │ @@ -36,12 +30,4 @@ 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/parametricity-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/parametricity-OTP-27.pretty deleted file mode 100644 index 371fb3af3c..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/parametricity-OTP-27.pretty +++ /dev/null @@ -1,57 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:178:19 - │ -178 │ refine01(X, X) -> X. - │ ^ X. -Expression has type: _B -Context expected type: A - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:186:22 - │ -186 │ [Elem || Elem <- X]. - │ ^ X. -Expression has type: B -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:218:3 - │ -218 │ select(T, <<>>, 0). - │ ^^^^^^^^^^^^^^^^^^ select(T, <<..>>, 0). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:218:3 - │ -218 │ select(T, <<>>, 0). - │ ^^^^^^^^^^^^^^^^^^ select(T, <<..>>, 0). -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:224:3 - │ -224 │ select(T, 0, 0). - │ ^^^^^^^^^^^^^^^ select(T, 0, 0). -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:229:31 - │ -229 │ unwrap(undefined, Default) -> Default; - │ ^^^^^^^ Default. -Expression has type: term() -Context expected type: Value - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:241:22 - │ -241 │ (A) -> F(A) - │ ^ A. -Expression has type: term() -Context expected type: A - -7 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/parametricity-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/parametricity-OTP-28.pretty deleted file mode 100644 index 371fb3af3c..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/parametricity-OTP-28.pretty +++ /dev/null @@ -1,57 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:178:19 - │ -178 │ refine01(X, X) -> X. - │ ^ X. -Expression has type: _B -Context expected type: A - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:186:22 - │ -186 │ [Elem || Elem <- X]. - │ ^ X. -Expression has type: B -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:218:3 - │ -218 │ select(T, <<>>, 0). - │ ^^^^^^^^^^^^^^^^^^ select(T, <<..>>, 0). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:218:3 - │ -218 │ select(T, <<>>, 0). - │ ^^^^^^^^^^^^^^^^^^ select(T, <<..>>, 0). -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:224:3 - │ -224 │ select(T, 0, 0). - │ ^^^^^^^^^^^^^^^ select(T, 0, 0). -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:229:31 - │ -229 │ unwrap(undefined, Default) -> Default; - │ ^^^^^^^ Default. -Expression has type: term() -Context expected type: Value - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/parametricity.erl:241:22 - │ -241 │ (A) -> F(A) - │ ^ A. -Expression has type: term() -Context expected type: A - -7 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/parametricity-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/parametricity.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/parametricity-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/parametricity.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/pats.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/pats.pretty new file mode 100644 index 0000000000..171c12dc46 --- /dev/null +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/pats.pretty @@ -0,0 +1,17 @@ +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/pats.erl:26:17 + │ +26 │ maps:get(a, M). + │ ^ + │ │ + │ M. +Expression has type: #{a => 'ok'} | 'error' +Context expected type: #{term() => term()} + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: #{a => 'ok'} + However the following candidate: 'error' + Differs from the expected type: #{term() => term()} + +1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/pinned-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/pinned-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/pinned-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/pinned-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/pinned-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/pinned-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/pinned-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/pinned-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/pinned-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_2-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/pinned.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_2-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/pinned.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/pos-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/pos-OTP-27.pretty deleted file mode 100644 index 4b7dcf8b26..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/pos-OTP-27.pretty +++ /dev/null @@ -1,8 +0,0 @@ -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/pos.erl:15:1 - │ -15 │ ╭ atom_pat(1) -> -16 │ │ ok. - │ ╰──────^ Clause is not covered by spec - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/pos-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/pos-OTP-28.pretty deleted file mode 100644 index 4b7dcf8b26..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/pos-OTP-28.pretty +++ /dev/null @@ -1,8 +0,0 @@ -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/pos.erl:15:1 - │ -15 │ ╭ atom_pat(1) -> -16 │ │ ok. - │ ╰──────^ Clause is not covered by spec - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/pos-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/pos.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/pos-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/pos.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/records-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/records-OTP-26.pretty deleted file mode 100644 index 77bb4cc37d..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/records-OTP-26.pretty +++ /dev/null @@ -1,649 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:30:18 - │ -30 │ mk_rec1_neg() -> #rec2{}. - │ ^^^^^^^ #rec2{...}. -Expression has type: #rec2{} -Context expected type: #rec1{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:40:5 - │ -40 │ R. - │ ^ R. -Expression has type: #rec2{} -Context expected type: #rec1{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:50:21 - │ -50 │ mk_rec_neg(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 - │ -59 │ Foo = #foo{name = bar}, - │ ^^^^^^^^^^^^^^^^ #foo{...}: id is 'undefined' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:73:5 - │ -73 │ Foo#foo_def{name = default, id = 0}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...#foo_def{...}. -Expression has type: #foo_def{} -Context expected type: #foo{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:73:5 - │ -73 │ Foo#foo_def{name = default, id = 0}. - │ ^^^ Foo. -Expression has type: #foo{} -Context expected type: #foo_def{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:86:5 - │ -86 │ #foo.name. - │ ^^^^^^^^^ #foo.name. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:91:5 - │ -91 │ Index. - │ ^^^^^ Index. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:104:5 - │ -104 │ Foo#foo.name. - │ ^^^^^^^^^^^^ ...#foo.name. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:109:5 - │ -109 │ Id. - │ ^^ Id. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:117:35 - │ -117 │ rec_index_pat_neg(#foo.id = I) -> I. - │ ^ I. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:127:5 - │ -127 │ {N, I}. - │ ^^^^^^ - │ │ - │ {N, I}. -Expression has type: {atom(), number()} -Context expected type: {number(), atom()} - │ - -Because in the expression's type: - { - Here the type is: atom() - 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 - │ -144 │ when Foo == #foo{} -> ok. - │ ^^^^^^ #foo{...}: id is 'undefined' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:154:37 - │ -154 │ when Foo == #foo_def{id = X} -> X. - │ ^ X. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:167:5 - │ -167 │ (X#rec_b.field)#rec_a.field. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...#rec_a.field. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:174:23 - │ -174 │ #iodata_box{iod = 's'}. - │ ^^^ 's'. -Expression has type: 's' -Context expected type: iodata() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:189:35 - │ -189 │ #mrec{id1 = 1, name1 = n, _ = ok}. - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/records.erl:200:1 - │ -200 │ ╭ field_gen_pat_neg( -201 │ │ #mrec{id1 = 1, name1 = n, _ = A} -202 │ │ ) -> -203 │ │ % is both id2 (integer) -204 │ │ % and name2 (atom) -205 │ │ A. - │ ╰─────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:217:5 - │ -217 │ #any_box{inner = ok}. - │ ^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #any_box{...}. -Expression has type: #any_box{inner :: 'ok'} -Context expected type: int_box() - │ - -Because in the expression's type: - #any_box{inner :: - Here the type is: 'ok' - 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 - │ -222 │ #any_box{inner = ok}. - │ ^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #any_box{...}. -Expression has type: #any_box{inner :: 'ok'} -Context expected type: #any_box{inner :: number()} - │ - -Because in the expression's type: - #any_box{inner :: - Here the type is: 'ok' - 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 - │ -282 │ #int_bool_box{inner = a}. - │ ^ - │ │ - │ 'a'. -Expression has type: 'a' -Context expected type: number() | boolean() - │ - - '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 - │ -287 │ #int_bool_box{_ = a}. - │ ^ - │ │ - │ 'a'. -Expression has type: 'a' -Context expected type: number() | boolean() - │ - - '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 - │ -292 │ #int_bool_box{}. - │ ^^^^^^^^^^^^^^^ - │ │ - │ #int_bool_box{...}. -Expression has type: #int_bool_box{inner :: 'true'} -Context expected type: only_int_box() - │ - -Because in the expression's type: - #int_bool_box{inner :: - Here the type is: 'true' - 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 - │ -308 │ B#int_bool_box{inner = a}. - │ ^ - │ │ - │ 'a'. -Expression has type: 'a' -Context expected type: number() | boolean() - │ - - '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 - │ -314 │ B#int_bool_box{inner = 4}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ...#int_bool_box{...}. -Expression has type: #int_bool_box{inner :: number()} -Context expected type: only_bool_box() - │ - -Because in the expression's type: - #int_bool_box{inner :: - Here the type is: number() - 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 - │ -319 │ R#any_box.inner. - │ ^ - │ │ - │ R. -Expression has type: only_int_box() -Context expected type: #any_box{} - │ - -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 - │ -319 │ R#any_box.inner. - │ ^^^^^^^^^^^^^^^ ...#any_box.inner. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:324:5 - │ -324 │ R#int_bool_box.inner. - │ ^^^^^^^^^^^^^^^^^^^^ ...#int_bool_box.inner. -Expression has type: number() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:329:5 - │ -329 │ {int_bool_box, a}. - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ {'int_bool_box', 'a'}. -Expression has type: {'int_bool_box', 'a'} -Context expected type: #int_bool_box{} - │ - -Because in the expression's type: - { 'int_bool_box', - Here the type is: 'a' - Context expects type: number() | boolean() - 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 - │ -334 │ {int_bool_box, a}. - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ {'int_bool_box', 'a'}. -Expression has type: {'int_bool_box', 'a'} -Context expected type: only_int_box() - │ - -Because in the expression's type: - { 'int_bool_box', - Here the type is: 'a' - 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 - │ -352 │ R#int_bool_box.inner. - │ ^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ...#int_bool_box.inner. -Expression has type: boolean() | 'true' -Context expected type: 'true' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'true' - However the following candidate: boolean() - Differs from the expected type: 'true' - ------------------------------- Detailed message ------------------------------ - - boolean() | 'true' is not compatible with 'true' - because - boolean() is not compatible with 'true' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:355:13 - │ -355 │ inner = true :: integer() - │ ^^^^ 'true'. -Expression has type: 'true' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:366:5 - │ -366 │ #bad_default{inner = 42}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #bad_default{...}. -Expression has type: #bad_default{} -Context expected type: only_int_box() - │ - -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 - │ -372 │ R#bad_default.inner. - │ ^ - │ │ - │ R. -Expression has type: {'int_bool_box', number()} -Context expected type: #bad_default{} - │ - -Because in the expression's type: - { - Here the type is: 'int_bool_box' - 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 - │ -388 │ test_subtype_refine_neg(R) -> R. - │ ^ - │ │ - │ R. -Expression has type: #refined_two_fields{} -Context expected type: #refined_two_fields{inner :: number()} - │ - -Because in the expression's type: - #refined_two_fields{inner :: - Here the type is: term() - 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 - │ -402 │ lists:nth(1, L) * 3. - │ ^^^^^^^^^^^^^^^ lists:nth(1, L). -Expression has type: atom() -Context expected type: number() - -error: type_var_in_record_field (See https://fb.me/eqwalizer_errors#type_var_in_record_field) - ┌─ check/src/records.erl:412:14 - │ -412 │ field :: _T - │ ^^ _T: Type variables are meaningless in record fields. Did you mean to use an alias? - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/records.erl:415:1 - │ -415 │ ╭ -spec test_recurd2_neg(#recurd2{}) -> -416 │ │ #recurd2{}. - │ ╰──────────────^ test_recurd2_neg/1 references type with invalid definition: #recurd2{} - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/records.erl:420:1 - │ -420 │ -type loop() :: loop(). - │ ^^^^^^^^^^^^^^^^^^^^ recursive type loop/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/records.erl:421:1 - │ -421 │ -record(invalid, {field :: loop()}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid references type with invalid definition: loop/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:425:5 - │ -425 │ X#invalid.field. - │ ^ X. -Expression has type: term() -Context expected type: #invalid{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:429:9 - │ -429 │ _ = X#invalid.field, - │ ^ X. -Expression has type: term() -Context expected type: #invalid{} - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/records.erl:433:1 - │ -433 │ ╭ unbound_update_neg(X) -> -434 │ │ X#invalid{field = 2}. - │ ╰────────────────────────^ Clause is not covered by spec - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/records.erl:445:27 - │ -445 │ eqwalizer:reveal_type(Field2), - │ ^^^^^^ dynamic() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:473:20 - │ -473 │ binary_to_atom(B); - │ ^ - │ │ - │ B. -Expression has type: 'my_record' | binary() -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: '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 - │ -517 │ narrow3({X, X}) -> X. - │ ^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:523:24 - │ -523 │ narrow5_neg({X, X}) -> X. - │ ^ X. -Expression has type: #two_ref{b :: boolean(), a :: atom()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:536:5 - │ -536 │ Id. - │ ^^ - │ │ - │ Id. -Expression has type: number() | none() -Context expected type: atom() - │ - -Because in the expression's type: - Here the type is: number() - Context expects type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:545:5 - │ -545 │ Rec#two_ref.a. - │ ^^^^^^^^^^^^^ - │ │ - │ ...#two_ref.a. -Expression has type: term() | none() -Context expected type: atom() - │ - -Because in the expression's type: - Here the type is: term() - Context expects type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:551:5 - │ -551 │ A. - │ ^ - │ │ - │ A. -Expression has type: term() | none() -Context expected type: atom() - │ - -Because in the expression's type: - Here the type is: term() - Context expects type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:557:5 - │ -557 │ I#{a => b}. - │ ^^^^^^^^^^ ..#{..}. -Expression has type: #{a := 'b', dynamic() => dynamic()} -Context expected type: 'ok' - -51 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/records-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/records-OTP-28.pretty deleted file mode 100644 index 77bb4cc37d..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/records-OTP-28.pretty +++ /dev/null @@ -1,649 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:30:18 - │ -30 │ mk_rec1_neg() -> #rec2{}. - │ ^^^^^^^ #rec2{...}. -Expression has type: #rec2{} -Context expected type: #rec1{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:40:5 - │ -40 │ R. - │ ^ R. -Expression has type: #rec2{} -Context expected type: #rec1{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:50:21 - │ -50 │ mk_rec_neg(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 - │ -59 │ Foo = #foo{name = bar}, - │ ^^^^^^^^^^^^^^^^ #foo{...}: id is 'undefined' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:73:5 - │ -73 │ Foo#foo_def{name = default, id = 0}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...#foo_def{...}. -Expression has type: #foo_def{} -Context expected type: #foo{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:73:5 - │ -73 │ Foo#foo_def{name = default, id = 0}. - │ ^^^ Foo. -Expression has type: #foo{} -Context expected type: #foo_def{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:86:5 - │ -86 │ #foo.name. - │ ^^^^^^^^^ #foo.name. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:91:5 - │ -91 │ Index. - │ ^^^^^ Index. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:104:5 - │ -104 │ Foo#foo.name. - │ ^^^^^^^^^^^^ ...#foo.name. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:109:5 - │ -109 │ Id. - │ ^^ Id. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:117:35 - │ -117 │ rec_index_pat_neg(#foo.id = I) -> I. - │ ^ I. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:127:5 - │ -127 │ {N, I}. - │ ^^^^^^ - │ │ - │ {N, I}. -Expression has type: {atom(), number()} -Context expected type: {number(), atom()} - │ - -Because in the expression's type: - { - Here the type is: atom() - 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 - │ -144 │ when Foo == #foo{} -> ok. - │ ^^^^^^ #foo{...}: id is 'undefined' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:154:37 - │ -154 │ when Foo == #foo_def{id = X} -> X. - │ ^ X. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:167:5 - │ -167 │ (X#rec_b.field)#rec_a.field. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...#rec_a.field. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:174:23 - │ -174 │ #iodata_box{iod = 's'}. - │ ^^^ 's'. -Expression has type: 's' -Context expected type: iodata() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:189:35 - │ -189 │ #mrec{id1 = 1, name1 = n, _ = ok}. - │ ^^ 'ok'. -Expression has type: 'ok' -Context expected type: number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/records.erl:200:1 - │ -200 │ ╭ field_gen_pat_neg( -201 │ │ #mrec{id1 = 1, name1 = n, _ = A} -202 │ │ ) -> -203 │ │ % is both id2 (integer) -204 │ │ % and name2 (atom) -205 │ │ A. - │ ╰─────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:217:5 - │ -217 │ #any_box{inner = ok}. - │ ^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #any_box{...}. -Expression has type: #any_box{inner :: 'ok'} -Context expected type: int_box() - │ - -Because in the expression's type: - #any_box{inner :: - Here the type is: 'ok' - 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 - │ -222 │ #any_box{inner = ok}. - │ ^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #any_box{...}. -Expression has type: #any_box{inner :: 'ok'} -Context expected type: #any_box{inner :: number()} - │ - -Because in the expression's type: - #any_box{inner :: - Here the type is: 'ok' - 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 - │ -282 │ #int_bool_box{inner = a}. - │ ^ - │ │ - │ 'a'. -Expression has type: 'a' -Context expected type: number() | boolean() - │ - - '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 - │ -287 │ #int_bool_box{_ = a}. - │ ^ - │ │ - │ 'a'. -Expression has type: 'a' -Context expected type: number() | boolean() - │ - - '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 - │ -292 │ #int_bool_box{}. - │ ^^^^^^^^^^^^^^^ - │ │ - │ #int_bool_box{...}. -Expression has type: #int_bool_box{inner :: 'true'} -Context expected type: only_int_box() - │ - -Because in the expression's type: - #int_bool_box{inner :: - Here the type is: 'true' - 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 - │ -308 │ B#int_bool_box{inner = a}. - │ ^ - │ │ - │ 'a'. -Expression has type: 'a' -Context expected type: number() | boolean() - │ - - '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 - │ -314 │ B#int_bool_box{inner = 4}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ...#int_bool_box{...}. -Expression has type: #int_bool_box{inner :: number()} -Context expected type: only_bool_box() - │ - -Because in the expression's type: - #int_bool_box{inner :: - Here the type is: number() - 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 - │ -319 │ R#any_box.inner. - │ ^ - │ │ - │ R. -Expression has type: only_int_box() -Context expected type: #any_box{} - │ - -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 - │ -319 │ R#any_box.inner. - │ ^^^^^^^^^^^^^^^ ...#any_box.inner. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:324:5 - │ -324 │ R#int_bool_box.inner. - │ ^^^^^^^^^^^^^^^^^^^^ ...#int_bool_box.inner. -Expression has type: number() -Context expected type: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:329:5 - │ -329 │ {int_bool_box, a}. - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ {'int_bool_box', 'a'}. -Expression has type: {'int_bool_box', 'a'} -Context expected type: #int_bool_box{} - │ - -Because in the expression's type: - { 'int_bool_box', - Here the type is: 'a' - Context expects type: number() | boolean() - 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 - │ -334 │ {int_bool_box, a}. - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ {'int_bool_box', 'a'}. -Expression has type: {'int_bool_box', 'a'} -Context expected type: only_int_box() - │ - -Because in the expression's type: - { 'int_bool_box', - Here the type is: 'a' - 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 - │ -352 │ R#int_bool_box.inner. - │ ^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ...#int_bool_box.inner. -Expression has type: boolean() | 'true' -Context expected type: 'true' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'true' - However the following candidate: boolean() - Differs from the expected type: 'true' - ------------------------------- Detailed message ------------------------------ - - boolean() | 'true' is not compatible with 'true' - because - boolean() is not compatible with 'true' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:355:13 - │ -355 │ inner = true :: integer() - │ ^^^^ 'true'. -Expression has type: 'true' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:366:5 - │ -366 │ #bad_default{inner = 42}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #bad_default{...}. -Expression has type: #bad_default{} -Context expected type: only_int_box() - │ - -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 - │ -372 │ R#bad_default.inner. - │ ^ - │ │ - │ R. -Expression has type: {'int_bool_box', number()} -Context expected type: #bad_default{} - │ - -Because in the expression's type: - { - Here the type is: 'int_bool_box' - 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 - │ -388 │ test_subtype_refine_neg(R) -> R. - │ ^ - │ │ - │ R. -Expression has type: #refined_two_fields{} -Context expected type: #refined_two_fields{inner :: number()} - │ - -Because in the expression's type: - #refined_two_fields{inner :: - Here the type is: term() - 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 - │ -402 │ lists:nth(1, L) * 3. - │ ^^^^^^^^^^^^^^^ lists:nth(1, L). -Expression has type: atom() -Context expected type: number() - -error: type_var_in_record_field (See https://fb.me/eqwalizer_errors#type_var_in_record_field) - ┌─ check/src/records.erl:412:14 - │ -412 │ field :: _T - │ ^^ _T: Type variables are meaningless in record fields. Did you mean to use an alias? - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/records.erl:415:1 - │ -415 │ ╭ -spec test_recurd2_neg(#recurd2{}) -> -416 │ │ #recurd2{}. - │ ╰──────────────^ test_recurd2_neg/1 references type with invalid definition: #recurd2{} - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/records.erl:420:1 - │ -420 │ -type loop() :: loop(). - │ ^^^^^^^^^^^^^^^^^^^^ recursive type loop/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/records.erl:421:1 - │ -421 │ -record(invalid, {field :: loop()}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid references type with invalid definition: loop/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:425:5 - │ -425 │ X#invalid.field. - │ ^ X. -Expression has type: term() -Context expected type: #invalid{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:429:9 - │ -429 │ _ = X#invalid.field, - │ ^ X. -Expression has type: term() -Context expected type: #invalid{} - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/records.erl:433:1 - │ -433 │ ╭ unbound_update_neg(X) -> -434 │ │ X#invalid{field = 2}. - │ ╰────────────────────────^ Clause is not covered by spec - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/records.erl:445:27 - │ -445 │ eqwalizer:reveal_type(Field2), - │ ^^^^^^ dynamic() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:473:20 - │ -473 │ binary_to_atom(B); - │ ^ - │ │ - │ B. -Expression has type: 'my_record' | binary() -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: '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 - │ -517 │ narrow3({X, X}) -> X. - │ ^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:523:24 - │ -523 │ narrow5_neg({X, X}) -> X. - │ ^ X. -Expression has type: #two_ref{b :: boolean(), a :: atom()} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:536:5 - │ -536 │ Id. - │ ^^ - │ │ - │ Id. -Expression has type: number() | none() -Context expected type: atom() - │ - -Because in the expression's type: - Here the type is: number() - Context expects type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:545:5 - │ -545 │ Rec#two_ref.a. - │ ^^^^^^^^^^^^^ - │ │ - │ ...#two_ref.a. -Expression has type: term() | none() -Context expected type: atom() - │ - -Because in the expression's type: - Here the type is: term() - Context expects type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:551:5 - │ -551 │ A. - │ ^ - │ │ - │ A. -Expression has type: term() | none() -Context expected type: atom() - │ - -Because in the expression's type: - Here the type is: term() - Context expects type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/records.erl:557:5 - │ -557 │ I#{a => b}. - │ ^^^^^^^^^^ ..#{..}. -Expression has type: #{a := 'b', dynamic() => dynamic()} -Context expected type: 'ok' - -51 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/records-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/records.pretty similarity index 79% rename from crates/elp/src/resources/test/eqwalizer_tests/check/records-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/records.pretty index 77bb4cc37d..f59eda6cd2 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/records-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/records.pretty @@ -18,16 +18,9 @@ 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 @@ -108,13 +101,6 @@ 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 │ @@ -181,14 +167,6 @@ 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 │ @@ -206,12 +184,6 @@ 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 │ @@ -223,9 +195,10 @@ Expression has type: 'a' Context expected type: number() | boolean() │ - 'a' is not compatible with number() | boolean() - because - 'a' is not compatible with number() +Because in the expression's type: + Here the type is: 'a' + Context expects type: number() | 'false' | 'true' + No candidate matches in the expected union. error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:287:23 @@ -238,9 +211,10 @@ Expression has type: 'a' Context expected type: number() | boolean() │ - 'a' is not compatible with number() | boolean() - because - 'a' is not compatible with number() +Because in the expression's type: + Here the type is: 'a' + Context expects type: number() | 'false' | 'true' + No candidate matches in the expected union. error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:292:5 @@ -259,14 +233,6 @@ 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 │ @@ -278,9 +244,10 @@ Expression has type: 'a' Context expected type: number() | boolean() │ - 'a' is not compatible with number() | boolean() - because - 'a' is not compatible with number() +Because in the expression's type: + Here the type is: 'a' + Context expects type: number() | 'false' | 'true' + No candidate matches in the expected union. error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:314:5 @@ -299,14 +266,6 @@ 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 │ @@ -322,12 +281,6 @@ 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 │ @@ -358,19 +311,10 @@ Context expected type: #int_bool_box{} Because in the expression's type: { 'int_bool_box', Here the type is: 'a' - Context expects type: number() | boolean() + Context expects type: number() | 'false' | 'true' 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 │ @@ -388,15 +332,6 @@ 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 │ @@ -410,15 +345,9 @@ Context expected type: 'true' Because in the expression's type: Here the type is a union type with some valid candidates: 'true' - However the following candidate: boolean() + However the following candidate: 'false' Differs from the expected type: 'true' ------------------------------- Detailed message ------------------------------ - - boolean() | 'true' is not compatible with 'true' - because - boolean() is not compatible with 'true' - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:355:13 │ @@ -442,12 +371,6 @@ 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 │ @@ -465,13 +388,6 @@ 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 │ @@ -489,12 +405,6 @@ 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 │ @@ -573,12 +483,6 @@ 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 │ @@ -597,46 +501,25 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ check/src/records.erl:536:5 │ 536 │ Id. - │ ^^ - │ │ - │ Id. -Expression has type: number() | none() + │ ^^ Id. +Expression has type: number() Context expected type: atom() - │ - -Because in the expression's type: - Here the type is: number() - Context expects type: atom() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:545:5 │ 545 │ Rec#two_ref.a. - │ ^^^^^^^^^^^^^ - │ │ - │ ...#two_ref.a. -Expression has type: term() | none() + │ ^^^^^^^^^^^^^ ...#two_ref.a. +Expression has type: term() Context expected type: atom() - │ - -Because in the expression's type: - Here the type is: term() - Context expects type: atom() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:551:5 │ 551 │ A. - │ ^ - │ │ - │ A. -Expression has type: term() | none() + │ ^ A. +Expression has type: term() Context expected type: atom() - │ - -Because in the expression's type: - Here the type is: term() - Context expects type: atom() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ check/src/records.erl:557:5 diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases-OTP-26.pretty deleted file mode 100644 index 87d235e56c..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases-OTP-26.pretty +++ /dev/null @@ -1,441 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/recursive_aliases.erl:59:20 - │ -59 │ subtype3_neg(C) -> C. - │ ^ - │ │ - │ C. -Expression has type: chainA() -Context expected type: chainB() - │ - -Because in the expression's type: - The type is a union type with some valid candidates: 'nil' - However, the following candidate doesn't match: - { - Here the type is: 'a' - 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 - │ -62 │ subtype4_neg(C) -> C. - │ ^ - │ │ - │ C. -Expression has type: chainB() -Context expected type: chainA() - │ - -Because in the expression's type: - The type is a union type with some valid candidates: 'nil' - However, the following candidate doesn't match: - { - Here the type is: 'b' - 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 - │ -65 │ subtype5_neg(C) -> C. - │ ^ - │ │ - │ C. -Expression has type: chainAB() -Context expected type: chainA() - │ - -Because in the expression's type: - The type is a union type with some valid candidates: 'nil' | {'a', chainAB()} - However, the following candidate doesn't match: - { - Here the type is: 'b' - 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 - │ -68 │ subtype6_neg(C) -> C. - │ ^ - │ │ - │ C. -Expression has type: chainAB() -Context expected type: chainB() - │ - -Because in the expression's type: - The type is a union type with some valid candidates: 'nil' | {'b', chainAB()} - However, the following candidate doesn't match: - { - Here the type is: 'a' - 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 - │ -70 │ -type non_prod() :: non_prod(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type non_prod/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:72:1 - │ -72 │ ╭ -spec non_prod_id(non_prod()) -> -73 │ │ non_prod() | number(). - │ ╰───────────────────────^ non_prod_id/1 references type with invalid definition: non_prod/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/recursive_aliases.erl:81:22 - │ -81 │ subtype_p1_neg(C) -> C. - │ ^ - │ │ - │ C. -Expression has type: pchainA(atom()) -Context expected type: pchainAB(atom()) - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'nil' - 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 - │ -113 │ 1 + m_chainA_size(Chain). - │ ^^^^^ - │ │ - │ Chain. -Expression has type: mChainB() -Context expected type: mChainA() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'nil' - However the following candidate: #{b := mChainB()} - Differs from the expected type: 'nil' | #{a := mChainA()} - ------------------------------- 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 - │ -138 │ fun_fan(F) -> F(). - │ ^ F. -Expected fun type with arity 0 -Got: fan() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/recursive_aliases.erl:187:21 - │ -187 │ subtype_6_neg(C) -> C. - │ ^ - │ │ - │ C. -Expression has type: pchainA('a') -Context expected type: pchainA('b' | 'c') - │ - -Because in the expression's type: - The type is a union type with some valid candidates: 'nil' - However, the following candidate doesn't match: - { 'a', - Here the type is: 'a' - Context expects type: 'b' | 'c' - 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 - │ -202 │ -type mu_bad() :: mu_bad() | {a}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type mu_bad/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:204:1 - │ -204 │ ╭ -spec to_mu_bad_neg() -> -205 │ │ mu_bad(). - │ ╰────────^ to_mu_bad_neg/0 references type with invalid definition: mu_bad/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:208:1 - │ -208 │ ╭ -spec test_mu_bad_neg(mu_bad()) -> -209 │ │ pid(). - │ ╰─────^ test_mu_bad_neg/1 references type with invalid definition: mu_bad/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:212:1 - │ -212 │ -type mu(A) :: {mu, mu(mu(A))}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type mu/1 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:214:1 - │ -214 │ -spec test2_neg(mu(A)) -> mu(mu(A)). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ test2_neg/1 references type with invalid definition: mu/1 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/recursive_aliases.erl:223:23 - │ -223 │ test4_neg({mu, M}) -> M. - │ ^ M. -Expression has type: atom() | mu2() -Context expected type: pid() - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:296:1 - │ -296 │ -type mu_bad2() :: id(mu_bad2()). - │ ^^^^^^^^^^^^^^^^^^^^^ recursive type mu_bad2/0 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:297:1 - │ -297 │ -type mu_bad2b() :: id(mu_bad2()). - │ ^^^^^^^^^^^^^^^^^^^^^^ recursive type mu_bad2b/0 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:299:1 - │ -299 │ -type mu_bad3() :: id(mu_bad3()). - │ ^^^^^^^^^^^^^^^^^^^^^ recursive type mu_bad3/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:301:1 - │ -301 │ ╭ -spec to_mu_bad3_neg(mu_bad2()) -> -302 │ │ mu_bad3(). - │ ╰───────────^ to_mu_bad3_neg/1 references types with invalid definitions: mu_bad2/0, mu_bad3/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:305:1 - │ -305 │ ╭ -spec to_mu_bad2b_neg(mu_bad2()) -> -306 │ │ mu_bad2b(). - │ ╰──────────^ to_mu_bad2b_neg/1 references types with invalid definitions: mu_bad2/0, mu_bad2b/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:309:1 - │ -309 │ -type indirect2() :: mutual2(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type indirect2/0 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:310:1 - │ -310 │ -type indirect1() :: mutual1(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type indirect1/0 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:312:1 - │ -312 │ ╭ -type mutual1() :: indirect1() -313 │ │ | indirect2(). - │ ╰─────────────^ recursive type mutual1/0 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:314:1 - │ -314 │ ╭ -type mutual2() :: indirect1() -315 │ │ | indirect2(). - │ ╰─────────────^ recursive type mutual2/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:317:1 - │ -317 │ ╭ -spec test_mutual_neg(mutual1()) -> -318 │ │ mutual2(). - │ ╰───────────^ test_mutual_neg/1 references types with invalid definitions: mutual1/0, mutual2/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:342:1 - │ -342 │ -type mu_bad5() :: opaque_id(mu_bad5()). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type mu_bad5/0 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:343:1 - │ -343 │ -type mu_bad5b() :: opaque_id(mu_bad5()). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type mu_bad5b/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:345:1 - │ -345 │ ╭ -spec test_mu_bad5( -346 │ │ mu_bad5() -347 │ │ ) -> mu_bad5b(). - │ ╰─────────────^ test_mu_bad5/1 references types with invalid definitions: mu_bad5/0, mu_bad5b/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:392:1 - │ -392 │ -type recur() :: foo(recur()) | a. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type recur/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:395:1 - │ -395 │ -spec un_recur_neg(recur()) -> ok. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ un_recur_neg/1 references type with invalid definition: recur/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:399:1 - │ -399 │ ╭ -spec term_to_recur_neg(term()) -> -400 │ │ recur(). - │ ╰───────^ term_to_recur_neg/1 references type with invalid definition: recur/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:409:1 - │ -409 │ ╭ -type foo7_neg(T) :: -410 │ │ {unit, foo7_neg(foo7_neg(T))}. - │ ╰───────────────────────────────^ recursive type foo7_neg/1 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:441:1 - │ -441 │ -type x_cycle() :: misc:x_cycle(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type x_cycle/0 is not productive - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/recursive_aliases.erl:460:1 - │ -460 │ trick_me(X, X) -> X. - │ ^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:477:1 - │ -477 │ ╭ -type t_tree2(Z) :: -478 │ │ {leaf, Z} | -479 │ │ {node, t_tree2(simple_id(Z))}. - │ ╰───────────────────────────────^ recursive type t_tree2/1 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:481:1 - │ -481 │ ╭ -type t_tree3(Z) :: -482 │ │ {leaf, Z} | -483 │ │ {node, t_tree3(t_tree3(Z))}. - │ ╰─────────────────────────────^ recursive type t_tree3/1 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:493:1 - │ -493 │ ╭ -type stream2(Z) :: -494 │ │ {chunk, stream2(simple_id(Z))}. - │ ╰────────────────────────────────^ recursive type stream2/1 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:505:1 - │ -505 │ ╭ -type d_stream(Z) :: -506 │ │ {chunk, d_stream([Z])}. - │ ╰────────────────────────^ recursive type d_stream/1 is not productive - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/recursive_aliases.erl:508:23 - │ -508 │ -type invalid_ty() :: non_exist:invalid(). - │ ^^^^^^^^^^^^^^^^^^^ Unknown id: non_exist:invalid/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:510:1 - │ -510 │ ╭ -type invalid_rec() :: -511 │ │ invalid_ty() | invalid_transitive(). - │ ╰───────────────────────────────────^ invalid_rec/0 references type with invalid definition: invalid_ty/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:513:1 - │ -513 │ ╭ -type invalid_transitive() :: -514 │ │ {a, invalid_rec()}. - │ ╰────────────────────^ invalid_transitive/0 references type with invalid definition: invalid_rec/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:516:1 - │ -516 │ ╭ -spec use_invalid -517 │ │ (invalid_transitive()) -> a. - │ ╰─────────────────────────────^ use_invalid/1 references type with invalid definition: invalid_transitive/0 - -43 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases-OTP-28.pretty deleted file mode 100644 index 87d235e56c..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases-OTP-28.pretty +++ /dev/null @@ -1,441 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/recursive_aliases.erl:59:20 - │ -59 │ subtype3_neg(C) -> C. - │ ^ - │ │ - │ C. -Expression has type: chainA() -Context expected type: chainB() - │ - -Because in the expression's type: - The type is a union type with some valid candidates: 'nil' - However, the following candidate doesn't match: - { - Here the type is: 'a' - 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 - │ -62 │ subtype4_neg(C) -> C. - │ ^ - │ │ - │ C. -Expression has type: chainB() -Context expected type: chainA() - │ - -Because in the expression's type: - The type is a union type with some valid candidates: 'nil' - However, the following candidate doesn't match: - { - Here the type is: 'b' - 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 - │ -65 │ subtype5_neg(C) -> C. - │ ^ - │ │ - │ C. -Expression has type: chainAB() -Context expected type: chainA() - │ - -Because in the expression's type: - The type is a union type with some valid candidates: 'nil' | {'a', chainAB()} - However, the following candidate doesn't match: - { - Here the type is: 'b' - 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 - │ -68 │ subtype6_neg(C) -> C. - │ ^ - │ │ - │ C. -Expression has type: chainAB() -Context expected type: chainB() - │ - -Because in the expression's type: - The type is a union type with some valid candidates: 'nil' | {'b', chainAB()} - However, the following candidate doesn't match: - { - Here the type is: 'a' - 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 - │ -70 │ -type non_prod() :: non_prod(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type non_prod/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:72:1 - │ -72 │ ╭ -spec non_prod_id(non_prod()) -> -73 │ │ non_prod() | number(). - │ ╰───────────────────────^ non_prod_id/1 references type with invalid definition: non_prod/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/recursive_aliases.erl:81:22 - │ -81 │ subtype_p1_neg(C) -> C. - │ ^ - │ │ - │ C. -Expression has type: pchainA(atom()) -Context expected type: pchainAB(atom()) - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'nil' - 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 - │ -113 │ 1 + m_chainA_size(Chain). - │ ^^^^^ - │ │ - │ Chain. -Expression has type: mChainB() -Context expected type: mChainA() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'nil' - However the following candidate: #{b := mChainB()} - Differs from the expected type: 'nil' | #{a := mChainA()} - ------------------------------- 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 - │ -138 │ fun_fan(F) -> F(). - │ ^ F. -Expected fun type with arity 0 -Got: fan() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/recursive_aliases.erl:187:21 - │ -187 │ subtype_6_neg(C) -> C. - │ ^ - │ │ - │ C. -Expression has type: pchainA('a') -Context expected type: pchainA('b' | 'c') - │ - -Because in the expression's type: - The type is a union type with some valid candidates: 'nil' - However, the following candidate doesn't match: - { 'a', - Here the type is: 'a' - Context expects type: 'b' | 'c' - 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 - │ -202 │ -type mu_bad() :: mu_bad() | {a}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type mu_bad/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:204:1 - │ -204 │ ╭ -spec to_mu_bad_neg() -> -205 │ │ mu_bad(). - │ ╰────────^ to_mu_bad_neg/0 references type with invalid definition: mu_bad/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:208:1 - │ -208 │ ╭ -spec test_mu_bad_neg(mu_bad()) -> -209 │ │ pid(). - │ ╰─────^ test_mu_bad_neg/1 references type with invalid definition: mu_bad/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:212:1 - │ -212 │ -type mu(A) :: {mu, mu(mu(A))}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type mu/1 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:214:1 - │ -214 │ -spec test2_neg(mu(A)) -> mu(mu(A)). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ test2_neg/1 references type with invalid definition: mu/1 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/recursive_aliases.erl:223:23 - │ -223 │ test4_neg({mu, M}) -> M. - │ ^ M. -Expression has type: atom() | mu2() -Context expected type: pid() - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:296:1 - │ -296 │ -type mu_bad2() :: id(mu_bad2()). - │ ^^^^^^^^^^^^^^^^^^^^^ recursive type mu_bad2/0 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:297:1 - │ -297 │ -type mu_bad2b() :: id(mu_bad2()). - │ ^^^^^^^^^^^^^^^^^^^^^^ recursive type mu_bad2b/0 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:299:1 - │ -299 │ -type mu_bad3() :: id(mu_bad3()). - │ ^^^^^^^^^^^^^^^^^^^^^ recursive type mu_bad3/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:301:1 - │ -301 │ ╭ -spec to_mu_bad3_neg(mu_bad2()) -> -302 │ │ mu_bad3(). - │ ╰───────────^ to_mu_bad3_neg/1 references types with invalid definitions: mu_bad2/0, mu_bad3/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:305:1 - │ -305 │ ╭ -spec to_mu_bad2b_neg(mu_bad2()) -> -306 │ │ mu_bad2b(). - │ ╰──────────^ to_mu_bad2b_neg/1 references types with invalid definitions: mu_bad2/0, mu_bad2b/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:309:1 - │ -309 │ -type indirect2() :: mutual2(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type indirect2/0 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:310:1 - │ -310 │ -type indirect1() :: mutual1(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type indirect1/0 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:312:1 - │ -312 │ ╭ -type mutual1() :: indirect1() -313 │ │ | indirect2(). - │ ╰─────────────^ recursive type mutual1/0 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:314:1 - │ -314 │ ╭ -type mutual2() :: indirect1() -315 │ │ | indirect2(). - │ ╰─────────────^ recursive type mutual2/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:317:1 - │ -317 │ ╭ -spec test_mutual_neg(mutual1()) -> -318 │ │ mutual2(). - │ ╰───────────^ test_mutual_neg/1 references types with invalid definitions: mutual1/0, mutual2/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:342:1 - │ -342 │ -type mu_bad5() :: opaque_id(mu_bad5()). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type mu_bad5/0 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:343:1 - │ -343 │ -type mu_bad5b() :: opaque_id(mu_bad5()). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type mu_bad5b/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:345:1 - │ -345 │ ╭ -spec test_mu_bad5( -346 │ │ mu_bad5() -347 │ │ ) -> mu_bad5b(). - │ ╰─────────────^ test_mu_bad5/1 references types with invalid definitions: mu_bad5/0, mu_bad5b/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:392:1 - │ -392 │ -type recur() :: foo(recur()) | a. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type recur/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:395:1 - │ -395 │ -spec un_recur_neg(recur()) -> ok. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ un_recur_neg/1 references type with invalid definition: recur/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:399:1 - │ -399 │ ╭ -spec term_to_recur_neg(term()) -> -400 │ │ recur(). - │ ╰───────^ term_to_recur_neg/1 references type with invalid definition: recur/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:409:1 - │ -409 │ ╭ -type foo7_neg(T) :: -410 │ │ {unit, foo7_neg(foo7_neg(T))}. - │ ╰───────────────────────────────^ recursive type foo7_neg/1 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:441:1 - │ -441 │ -type x_cycle() :: misc:x_cycle(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type x_cycle/0 is not productive - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/recursive_aliases.erl:460:1 - │ -460 │ trick_me(X, X) -> X. - │ ^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:477:1 - │ -477 │ ╭ -type t_tree2(Z) :: -478 │ │ {leaf, Z} | -479 │ │ {node, t_tree2(simple_id(Z))}. - │ ╰───────────────────────────────^ recursive type t_tree2/1 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:481:1 - │ -481 │ ╭ -type t_tree3(Z) :: -482 │ │ {leaf, Z} | -483 │ │ {node, t_tree3(t_tree3(Z))}. - │ ╰─────────────────────────────^ recursive type t_tree3/1 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:493:1 - │ -493 │ ╭ -type stream2(Z) :: -494 │ │ {chunk, stream2(simple_id(Z))}. - │ ╰────────────────────────────────^ recursive type stream2/1 is not productive - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/recursive_aliases.erl:505:1 - │ -505 │ ╭ -type d_stream(Z) :: -506 │ │ {chunk, d_stream([Z])}. - │ ╰────────────────────────^ recursive type d_stream/1 is not productive - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/recursive_aliases.erl:508:23 - │ -508 │ -type invalid_ty() :: non_exist:invalid(). - │ ^^^^^^^^^^^^^^^^^^^ Unknown id: non_exist:invalid/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:510:1 - │ -510 │ ╭ -type invalid_rec() :: -511 │ │ invalid_ty() | invalid_transitive(). - │ ╰───────────────────────────────────^ invalid_rec/0 references type with invalid definition: invalid_ty/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:513:1 - │ -513 │ ╭ -type invalid_transitive() :: -514 │ │ {a, invalid_rec()}. - │ ╰────────────────────^ invalid_transitive/0 references type with invalid definition: invalid_rec/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/recursive_aliases.erl:516:1 - │ -516 │ ╭ -spec use_invalid -517 │ │ (invalid_transitive()) -> a. - │ ╰─────────────────────────────^ use_invalid/1 references type with invalid definition: invalid_transitive/0 - -43 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases.pretty similarity index 83% rename from crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases.pretty index 87d235e56c..ffd83bc179 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/recursive_aliases.pretty @@ -17,16 +17,6 @@ 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 │ @@ -46,16 +36,6 @@ 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 │ @@ -75,16 +55,6 @@ 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 │ @@ -104,16 +74,6 @@ 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 │ @@ -143,17 +103,6 @@ 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 │ @@ -166,19 +115,11 @@ Context expected type: mChainA() │ Because in the expression's type: - Here the type is a union type with some valid candidates: 'nil' - However the following candidate: #{b := mChainB()} - Differs from the expected type: 'nil' | #{a := mChainA()} - ------------------------------- 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()} + The type is a union type with some valid candidates: 'nil' + However, the following candidate doesn't match: + Here the type is: #{...} + Context expects type: #{a := ..., ...} + The type of the expression is missing the following required keys: a. error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) ┌─ check/src/recursive_aliases.erl:138:15 @@ -208,16 +149,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/refine-OTP-26.pretty deleted file mode 100644 index 20a5b05732..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/refine-OTP-26.pretty +++ /dev/null @@ -1,623 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:12:17 - │ -12 │ param1(X, X) -> X. - │ ^ X. -Expression has type: _B -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:16:17 - │ -16 │ param2(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: {B, A} -Context expected type: {none(), none()} - │ - -Because in the expression's type: - { - Here the type is: B - 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 - │ -22 │ maps(M, M) -> M. - │ ^ M. -Expression has type: #{a := atom()} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:28:16 - │ -28 │ funs1(F, F) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun((B | A) -> A) -Context expected type: fun((A | B) -> none()) - │ - -Because in the expression's type: - fun((B | A) -> - Here the type is: A - 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 - │ -34 │ funs2(F, F) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun((atom() | A) -> A) -Context expected type: fun((A | atom()) -> none()) - │ - -Because in the expression's type: - fun((atom() | A) -> - Here the type is: A - 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 - │ -84 │ list_trick_neg([X], _) -> X. - │ ^ X. -Expression has type: term() -Context expected type: U - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:92:28 - │ -92 │ tuple_trick_neg({X}, _) -> X. - │ ^ X. -Expression has type: term() -Context expected type: U - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:101:8 - │ -101 │ -> X. - │ ^ X. -Expression has type: _T -Context expected type: U - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:112:24 - │ -112 │ (#{key := Val}) -> Val. - │ ^^^ Val. -Expression has type: term() -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:117:26 - │ -117 │ (<>) -> {X, Y}. - │ ^^^^^^ - │ │ - │ {X, Y}. -Expression has type: {number(), binary()} -Context expected type: {none(), none()} - │ - -Because in the expression's type: - { - Here the type is: number() - 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 - │ -126 │ (#my_rec{n = N, a = A}) -> {N, A}. - │ ^^^^^^ - │ │ - │ {N, A}. -Expression has type: {number(), atom()} -Context expected type: {none(), none()} - │ - -Because in the expression's type: - { - Here the type is: number() - 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 - │ -139 │ refine_alist1_neg(X, X) -> X. - │ ^ X. -Expression has type: ['a' | 'b'] -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:144:24 - │ -144 │ refine_alist2(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: ['a' | 'b'] -Context expected type: ['a'] - │ - -Because in the expression's type: - [ - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -151 │ refine_tlist1_neg(X, X) -> X. - │ ^ X. -Expression has type: ['a' | 'b'] -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:156:24 - │ -156 │ refine_tlist2(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: ['a' | 'b'] -Context expected type: ['a'] - │ - -Because in the expression's type: - [ - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -166 │ Res. - │ ^^^ Res. -Expression has type: {'cons', 'nil' | my_list()} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:177:24 - │ -177 │ opaque1_neg({X, _}) -> X. - │ ^ X. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:183:24 - │ -183 │ opaque2_neg([X, _]) -> X. - │ ^ - │ │ - │ X. -Expression has type: erl_anno:annotation() -Context expected type: pid() - │ - -Because in the expression's type: - Here the type is: tuple()/2 | tuple()/2 | tuple()/2 | tuple()/2 | tuple()/2 - Context expects type: pid() - No candidate of the expression's type matches the expected type. - ------------------------------- Detailed message ------------------------------ - - erl_anno:annotation() is not compatible with pid() - because - {'file', erl_anno:filename()} | {'generated', erl_anno:generated()} | {'record', erl_anno:record()} | {'text', string()} | {'location', erl_anno:location()} is not compatible with pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:191:7 - │ -191 │ }) -> X. - │ ^ X. -Expression has type: 'set' -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:198:23 - │ -198 │ opaque_4_neg(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: gb_sets:set(atom()) -Context expected type: pid() - │ - -Because in the expression's type: - Here the type is: {number(), gb_sets:gb_set_node(atom())} - Context expects type: pid() - ------------------------------- Detailed message ------------------------------ - - gb_sets:set(atom()) is not compatible with pid() - because - {number(), gb_sets:gb_set_node(atom())} is not compatible with pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:202:31 - │ -202 │ record_as_tuple1_neg(R, R) -> R. - │ ^ R. -Expression has type: #my_rec{} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:206:31 - │ -206 │ record_as_tuple2_neg(R, R) -> R. - │ ^ R. -Expression has type: #my_rec{} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:222:28 - │ -222 │ record_as_tuple6_neg(R) -> R. - │ ^ - │ │ - │ R. -Expression has type: #my_rec{} -Context expected type: {'not_my_rec', term(), term()} - │ - -Because in the expression's type: - { - Here the type is: 'my_rec' - 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:226:10 - │ -226 │ i :: unknown:unknown() - │ ^^^^^^^^^^^^^^^^^ Unknown id: unknown:unknown/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/refine.erl:228:1 - │ -228 │ ╭ -spec record_as_tuple7_neg -229 │ │ (#bad_rec{}) -> {bad_rec, atom()}. - │ ╰─────────────────────────────────^ record_as_tuple7_neg/1 references type with invalid definition: #bad_rec{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:240:28 - │ -240 │ tuple_as_record2_neg(R) -> R. - │ ^ - │ │ - │ R. -Expression has type: {'my_rec', atom(), number()} -Context expected type: #my_rec{} - │ - -Because in the expression's type: - { 'my_rec', - Here the type is: atom() - 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:245:1 - │ -245 │ ╭ tup_guard_record1(X) -246 │ │ when is_record(X, my_rec) -> -247 │ │ X * 2. - │ ╰─────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:253:5 - │ -253 │ X * 2. - │ ^ X. -Expression has type: #my_rec{} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:259:5 - │ -259 │ X * 2. - │ ^ X. -Expression has type: #my_rec{} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:262:14 - │ -262 │ ftt(X, _) -> X. - │ ^ X. -Expression has type: fun((T) -> 'ok') -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:265:20 - │ -265 │ my_rec_to_ok(X) -> X. - │ ^ X. -Expression has type: #my_rec{} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:277:26 - │ -277 │ use2_neg(F, X) -> ftt(F, X). - │ ^ - │ │ - │ X. -Expression has type: {'my_rec', atom(), number()} -Context expected type: #my_rec{} - │ - -Because in the expression's type: - { 'my_rec', - Here the type is: atom() - 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:277:26 - │ -277 │ use2_neg(F, X) -> ftt(F, X). - │ ^ - │ │ - │ X. -Expression has type: {'my_rec', atom(), number()} -Context expected type: dynamic(#my_rec{}) - │ - -Because in the expression's type: - { 'my_rec', - Here the type is: atom() - 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:289:26 - │ -289 │ use4_neg(F, X) -> ftt(F, X). - │ ^ - │ │ - │ X. -Expression has type: #my_rec{} -Context expected type: {'my_rec', atom(), number()} - │ - -Because in the expression's type: - { 'my_rec', - Here the type is: number() - 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:289:26 - │ -289 │ use4_neg(F, X) -> ftt(F, X). - │ ^ - │ │ - │ X. -Expression has type: #my_rec{} -Context expected type: dynamic({'my_rec', atom(), number()}) - │ - -Because in the expression's type: - { 'my_rec', - Here the type is: number() - 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:305:21 - │ -305 │ use6_neg(X) -> ttt2(X, x). - │ ^ - │ │ - │ X. -Expression has type: #my_rec{} -Context expected type: {'my_rec', atom(), atom()} - │ - -Because in the expression's type: - { 'my_rec', - Here the type is: number() - 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:309:16 - │ -309 │ use7_neg(X) -> ttt1(X, 1). - │ ^^^^^^^^^^ - │ │ - │ ttt1(X, 1). -Expression has type: atom() | 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: 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:313:13 - │ -313 │ deets(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #my_rec{} | 'a' -Context expected type: {'my_rec', term(), term()} - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #my_rec{} - 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:323:5 - │ -323 │ B. - │ ^ - │ │ - │ B. -Expression has type: 'undefined' | binary() -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: '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:405:27 - │ -405 │ eqwalizer:reveal_type(Name), - │ ^^^^ atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:406:5 - │ -406 │ Name. - │ ^^^^ Name. -Expression has type: atom() -Context expected type: 'ok' - -41 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/refine-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/refine-OTP-28.pretty deleted file mode 100644 index ded381093a..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/refine-OTP-28.pretty +++ /dev/null @@ -1,623 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:12:17 - │ -12 │ param1(X, X) -> X. - │ ^ X. -Expression has type: _B -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:16:17 - │ -16 │ param2(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: {B, A} -Context expected type: {none(), none()} - │ - -Because in the expression's type: - { - Here the type is: B - 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 - │ -22 │ maps(M, M) -> M. - │ ^ M. -Expression has type: #{a := atom()} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:28:16 - │ -28 │ funs1(F, F) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun((B | A) -> A) -Context expected type: fun((A | B) -> none()) - │ - -Because in the expression's type: - fun((B | A) -> - Here the type is: A - 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 - │ -34 │ funs2(F, F) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun((atom() | A) -> A) -Context expected type: fun((A | atom()) -> none()) - │ - -Because in the expression's type: - fun((atom() | A) -> - Here the type is: A - 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 - │ -84 │ list_trick_neg([X], _) -> X. - │ ^ X. -Expression has type: term() -Context expected type: U - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:92:28 - │ -92 │ tuple_trick_neg({X}, _) -> X. - │ ^ X. -Expression has type: term() -Context expected type: U - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:101:8 - │ -101 │ -> X. - │ ^ X. -Expression has type: _T -Context expected type: U - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:112:24 - │ -112 │ (#{key := Val}) -> Val. - │ ^^^ Val. -Expression has type: term() -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:117:26 - │ -117 │ (<>) -> {X, Y}. - │ ^^^^^^ - │ │ - │ {X, Y}. -Expression has type: {number(), binary()} -Context expected type: {none(), none()} - │ - -Because in the expression's type: - { - Here the type is: number() - 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 - │ -126 │ (#my_rec{n = N, a = A}) -> {N, A}. - │ ^^^^^^ - │ │ - │ {N, A}. -Expression has type: {number(), atom()} -Context expected type: {none(), none()} - │ - -Because in the expression's type: - { - Here the type is: number() - 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 - │ -139 │ refine_alist1_neg(X, X) -> X. - │ ^ X. -Expression has type: ['a' | 'b'] -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:144:24 - │ -144 │ refine_alist2(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: ['a' | 'b'] -Context expected type: ['a'] - │ - -Because in the expression's type: - [ - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -151 │ refine_tlist1_neg(X, X) -> X. - │ ^ X. -Expression has type: ['a' | 'b'] -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:156:24 - │ -156 │ refine_tlist2(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: ['a' | 'b'] -Context expected type: ['a'] - │ - -Because in the expression's type: - [ - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -166 │ Res. - │ ^^^ Res. -Expression has type: {'cons', 'nil' | my_list()} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:177:24 - │ -177 │ opaque1_neg({X, _}) -> X. - │ ^ X. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:183:24 - │ -183 │ opaque2_neg([X, _]) -> X. - │ ^ - │ │ - │ X. -Expression has type: erl_anno:annotation() -Context expected type: pid() - │ - -Because in the expression's type: - Here the type is: tuple()/2 | tuple()/2 | tuple()/2 | tuple()/2 | tuple()/2 | ... - Context expects type: pid() - No candidate of the expression's type matches the expected type. - ------------------------------- Detailed message ------------------------------ - - erl_anno:annotation() is not compatible with pid() - because - {'file', erl_anno:filename()} | {'end_location', erl_anno:location()} | {'generated', erl_anno:generated()} | {'record', erl_anno:record()} | {'text', string()} | {'location', erl_anno:location()} is not compatible with pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:191:7 - │ -191 │ }) -> X. - │ ^ X. -Expression has type: 'set' -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:198:23 - │ -198 │ opaque_4_neg(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: gb_sets:set(atom()) -Context expected type: pid() - │ - -Because in the expression's type: - Here the type is: {number(), gb_sets:gb_set_node(atom())} - Context expects type: pid() - ------------------------------- Detailed message ------------------------------ - - gb_sets:set(atom()) is not compatible with pid() - because - {number(), gb_sets:gb_set_node(atom())} is not compatible with pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:202:31 - │ -202 │ record_as_tuple1_neg(R, R) -> R. - │ ^ R. -Expression has type: #my_rec{} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:206:31 - │ -206 │ record_as_tuple2_neg(R, R) -> R. - │ ^ R. -Expression has type: #my_rec{} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:222:28 - │ -222 │ record_as_tuple6_neg(R) -> R. - │ ^ - │ │ - │ R. -Expression has type: #my_rec{} -Context expected type: {'not_my_rec', term(), term()} - │ - -Because in the expression's type: - { - Here the type is: 'my_rec' - 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:226:10 - │ -226 │ i :: unknown:unknown() - │ ^^^^^^^^^^^^^^^^^ Unknown id: unknown:unknown/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/refine.erl:228:1 - │ -228 │ ╭ -spec record_as_tuple7_neg -229 │ │ (#bad_rec{}) -> {bad_rec, atom()}. - │ ╰─────────────────────────────────^ record_as_tuple7_neg/1 references type with invalid definition: #bad_rec{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:240:28 - │ -240 │ tuple_as_record2_neg(R) -> R. - │ ^ - │ │ - │ R. -Expression has type: {'my_rec', atom(), number()} -Context expected type: #my_rec{} - │ - -Because in the expression's type: - { 'my_rec', - Here the type is: atom() - 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:245:1 - │ -245 │ ╭ tup_guard_record1(X) -246 │ │ when is_record(X, my_rec) -> -247 │ │ X * 2. - │ ╰─────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:253:5 - │ -253 │ X * 2. - │ ^ X. -Expression has type: #my_rec{} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:259:5 - │ -259 │ X * 2. - │ ^ X. -Expression has type: #my_rec{} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:262:14 - │ -262 │ ftt(X, _) -> X. - │ ^ X. -Expression has type: fun((T) -> 'ok') -Context expected type: T - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:265:20 - │ -265 │ my_rec_to_ok(X) -> X. - │ ^ X. -Expression has type: #my_rec{} -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:277:26 - │ -277 │ use2_neg(F, X) -> ftt(F, X). - │ ^ - │ │ - │ X. -Expression has type: {'my_rec', atom(), number()} -Context expected type: #my_rec{} - │ - -Because in the expression's type: - { 'my_rec', - Here the type is: atom() - 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:277:26 - │ -277 │ use2_neg(F, X) -> ftt(F, X). - │ ^ - │ │ - │ X. -Expression has type: {'my_rec', atom(), number()} -Context expected type: dynamic(#my_rec{}) - │ - -Because in the expression's type: - { 'my_rec', - Here the type is: atom() - 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:289:26 - │ -289 │ use4_neg(F, X) -> ftt(F, X). - │ ^ - │ │ - │ X. -Expression has type: #my_rec{} -Context expected type: {'my_rec', atom(), number()} - │ - -Because in the expression's type: - { 'my_rec', - Here the type is: number() - 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:289:26 - │ -289 │ use4_neg(F, X) -> ftt(F, X). - │ ^ - │ │ - │ X. -Expression has type: #my_rec{} -Context expected type: dynamic({'my_rec', atom(), number()}) - │ - -Because in the expression's type: - { 'my_rec', - Here the type is: number() - 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:305:21 - │ -305 │ use6_neg(X) -> ttt2(X, x). - │ ^ - │ │ - │ X. -Expression has type: #my_rec{} -Context expected type: {'my_rec', atom(), atom()} - │ - -Because in the expression's type: - { 'my_rec', - Here the type is: number() - 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:309:16 - │ -309 │ use7_neg(X) -> ttt1(X, 1). - │ ^^^^^^^^^^ - │ │ - │ ttt1(X, 1). -Expression has type: atom() | 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: 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:313:13 - │ -313 │ deets(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: #my_rec{} | 'a' -Context expected type: {'my_rec', term(), term()} - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #my_rec{} - 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:323:5 - │ -323 │ B. - │ ^ - │ │ - │ B. -Expression has type: 'undefined' | binary() -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: '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:405:27 - │ -405 │ eqwalizer:reveal_type(Name), - │ ^^^^ atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:406:5 - │ -406 │ Name. - │ ^^^^ Name. -Expression has type: atom() -Context expected type: 'ok' - -41 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/refine-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/refine.pretty similarity index 61% rename from crates/elp/src/resources/test/eqwalizer_tests/check/refine-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/refine.pretty index 20a5b05732..711e1dc2e9 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/refine-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/refine.pretty @@ -23,13 +23,6 @@ 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 │ @@ -55,12 +48,6 @@ 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 │ @@ -78,12 +65,6 @@ 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 │ @@ -133,13 +114,6 @@ 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 │ @@ -157,13 +131,6 @@ 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 │ @@ -190,14 +157,6 @@ 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 │ @@ -224,14 +183,6 @@ 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 │ @@ -241,84 +192,25 @@ Expression has type: {'cons', 'nil' | my_list()} Context expected type: number() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:177:24 + ┌─ check/src/refine.erl:175:31 │ -177 │ opaque1_neg({X, _}) -> X. - │ ^ X. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:183:24 - │ -183 │ opaque2_neg([X, _]) -> X. - │ ^ - │ │ - │ X. -Expression has type: erl_anno:annotation() -Context expected type: pid() - │ - -Because in the expression's type: - Here the type is: tuple()/2 | tuple()/2 | tuple()/2 | tuple()/2 | tuple()/2 - Context expects type: pid() - No candidate of the expression's type matches the expected type. - ------------------------------- Detailed message ------------------------------ - - erl_anno:annotation() is not compatible with pid() - because - {'file', erl_anno:filename()} | {'generated', erl_anno:generated()} | {'record', erl_anno:record()} | {'text', string()} | {'location', erl_anno:location()} is not compatible with pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:191:7 - │ -191 │ }) -> X. - │ ^ X. -Expression has type: 'set' -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:198:23 - │ -198 │ opaque_4_neg(X, X) -> X. - │ ^ - │ │ - │ X. -Expression has type: gb_sets:set(atom()) -Context expected type: pid() - │ - -Because in the expression's type: - Here the type is: {number(), gb_sets:gb_set_node(atom())} - Context expects type: pid() - ------------------------------- Detailed message ------------------------------ - - gb_sets:set(atom()) is not compatible with pid() - because - {number(), gb_sets:gb_set_node(atom())} is not compatible with pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:202:31 - │ -202 │ record_as_tuple1_neg(R, R) -> R. +175 │ record_as_tuple1_neg(R, R) -> R. │ ^ R. Expression has type: #my_rec{} Context expected type: none() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:206:31 + ┌─ check/src/refine.erl:179:31 │ -206 │ record_as_tuple2_neg(R, R) -> R. +179 │ record_as_tuple2_neg(R, R) -> R. │ ^ R. Expression has type: #my_rec{} Context expected type: none() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:222:28 + ┌─ check/src/refine.erl:195:28 │ -222 │ record_as_tuple6_neg(R) -> R. +195 │ record_as_tuple6_neg(R) -> R. │ ^ │ │ │ R. @@ -332,30 +224,23 @@ 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:226:10 + ┌─ check/src/refine.erl:199:10 │ -226 │ i :: unknown:unknown() +199 │ i :: unknown:unknown() │ ^^^^^^^^^^^^^^^^^ Unknown id: unknown:unknown/0 error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/refine.erl:228:1 + ┌─ check/src/refine.erl:201:1 │ -228 │ ╭ -spec record_as_tuple7_neg -229 │ │ (#bad_rec{}) -> {bad_rec, atom()}. +201 │ ╭ -spec record_as_tuple7_neg +202 │ │ (#bad_rec{}) -> {bad_rec, atom()}. │ ╰─────────────────────────────────^ record_as_tuple7_neg/1 references type with invalid definition: #bad_rec{} error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:240:28 + ┌─ check/src/refine.erl:213:28 │ -240 │ tuple_as_record2_neg(R) -> R. +213 │ tuple_as_record2_neg(R) -> R. │ ^ │ │ │ R. @@ -369,57 +254,50 @@ 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:245:1 + ┌─ check/src/refine.erl:218:1 │ -245 │ ╭ tup_guard_record1(X) -246 │ │ when is_record(X, my_rec) -> -247 │ │ X * 2. +218 │ ╭ tup_guard_record1(X) +219 │ │ when is_record(X, my_rec) -> +220 │ │ X * 2. │ ╰─────────^ Clause is not covered by spec error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:253:5 + ┌─ check/src/refine.erl:226:5 │ -253 │ X * 2. +226 │ X * 2. │ ^ X. Expression has type: #my_rec{} Context expected type: number() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:259:5 + ┌─ check/src/refine.erl:232:5 │ -259 │ X * 2. +232 │ X * 2. │ ^ X. Expression has type: #my_rec{} Context expected type: number() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:262:14 + ┌─ check/src/refine.erl:235:14 │ -262 │ ftt(X, _) -> X. +235 │ ftt(X, _) -> X. │ ^ X. Expression has type: fun((T) -> 'ok') Context expected type: T error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:265:20 + ┌─ check/src/refine.erl:238:20 │ -265 │ my_rec_to_ok(X) -> X. +238 │ my_rec_to_ok(X) -> X. │ ^ X. Expression has type: #my_rec{} Context expected type: 'ok' error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:277:26 + ┌─ check/src/refine.erl:250:26 │ -277 │ use2_neg(F, X) -> ftt(F, X). +250 │ use2_neg(F, X) -> ftt(F, X). │ ^ │ │ │ X. @@ -433,17 +311,10 @@ 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:277:26 + ┌─ check/src/refine.erl:250:26 │ -277 │ use2_neg(F, X) -> ftt(F, X). +250 │ use2_neg(F, X) -> ftt(F, X). │ ^ │ │ │ X. @@ -457,19 +328,10 @@ 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:289:26 + ┌─ check/src/refine.erl:262:26 │ -289 │ use4_neg(F, X) -> ftt(F, X). +262 │ use4_neg(F, X) -> ftt(F, X). │ ^ │ │ │ X. @@ -483,17 +345,10 @@ 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:289:26 + ┌─ check/src/refine.erl:262:26 │ -289 │ use4_neg(F, X) -> ftt(F, X). +262 │ use4_neg(F, X) -> ftt(F, X). │ ^ │ │ │ X. @@ -507,19 +362,10 @@ 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:305:21 + ┌─ check/src/refine.erl:278:21 │ -305 │ use6_neg(X) -> ttt2(X, x). +278 │ use6_neg(X) -> ttt2(X, x). │ ^ │ │ │ X. @@ -533,17 +379,10 @@ 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:309:16 + ┌─ check/src/refine.erl:282:16 │ -309 │ use7_neg(X) -> ttt1(X, 1). +282 │ use7_neg(X) -> ttt1(X, 1). │ ^^^^^^^^^^ │ │ │ ttt1(X, 1). @@ -556,16 +395,10 @@ 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:313:13 + ┌─ check/src/refine.erl:286:13 │ -313 │ deets(X) -> X. +286 │ deets(X) -> X. │ ^ │ │ │ X. @@ -578,16 +411,10 @@ 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:323:5 + ┌─ check/src/refine.erl:296:5 │ -323 │ B. +296 │ B. │ ^ │ │ │ B. @@ -600,24 +427,18 @@ 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:405:27 + ┌─ check/src/refine.erl:378:27 │ -405 │ eqwalizer:reveal_type(Name), +378 │ eqwalizer:reveal_type(Name), │ ^^^^ atom() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/refine.erl:406:5 + ┌─ check/src/refine.erl:379:5 │ -406 │ Name. +379 │ Name. │ ^^^^ Name. Expression has type: atom() Context expected type: 'ok' -41 ERRORS +37 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/scoping-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/scoping-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/scoping-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/scoping-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/scoping-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/scoping-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/scoping-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/scoping-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/scoping-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_2-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/scoping.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_2-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/scoping.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/skip-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/skip-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/skip-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/skip-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/skip-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/skip-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/skip-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/skip-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/skip-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_2-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/skip.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_callbacks_2-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/skip.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/static_maybe-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/static_maybe-OTP-27.pretty deleted file mode 100644 index 534ecac9b6..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/static_maybe-OTP-27.pretty +++ /dev/null @@ -1,17 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/static_maybe.erl:26:9 - │ -26 │ A - │ ^ A. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/static_maybe.erl:50:14 - │ -50 │ _ -> 3 - │ ^ 3. -Expression has type: number() -Context expected type: atom() - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/static_maybe-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/static_maybe-OTP-28.pretty deleted file mode 100644 index 534ecac9b6..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/static_maybe-OTP-28.pretty +++ /dev/null @@ -1,17 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/static_maybe.erl:26:9 - │ -26 │ A - │ ^ A. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/static_maybe.erl:50:14 - │ -50 │ _ -> 3 - │ ^ 3. -Expression has type: number() -Context expected type: atom() - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/static_maybe-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/static_maybe.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/static_maybe-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/static_maybe.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types-OTP-26.pretty deleted file mode 100644 index cc9f9d0634..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types-OTP-26.pretty +++ /dev/null @@ -1,76 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/strict_complex_types.erl:24:3 - │ -24 │ undefined. - │ ^^^^^^^^^ - │ │ - │ 'undefined'. -Expression has type: 'undefined' -Context expected type: complex_map() - │ - -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 - │ -29 │ eqwalizer:reveal_type(Map), - │ ^^^ complex_map() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/strict_complex_types.erl:35:25 - │ -35 │ eqwalizer:reveal_type(List), - │ ^^^^ [complex_map()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/strict_complex_types.erl:48:16 - │ -48 │ lists:nth(7, Map). - │ ^^^ - │ │ - │ Map. -Expression has type: complex_map() -Context expected type: [T] - │ - -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 - │ -48 │ lists:nth(7, Map). - │ ^^^ - │ │ - │ Map. -Expression has type: complex_map() -Context expected type: [dynamic()] - │ - -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/strict_complex_types-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types-OTP-28.pretty deleted file mode 100644 index cc9f9d0634..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types-OTP-28.pretty +++ /dev/null @@ -1,76 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/strict_complex_types.erl:24:3 - │ -24 │ undefined. - │ ^^^^^^^^^ - │ │ - │ 'undefined'. -Expression has type: 'undefined' -Context expected type: complex_map() - │ - -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 - │ -29 │ eqwalizer:reveal_type(Map), - │ ^^^ complex_map() - -error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type) - ┌─ check/src/strict_complex_types.erl:35:25 - │ -35 │ eqwalizer:reveal_type(List), - │ ^^^^ [complex_map()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/strict_complex_types.erl:48:16 - │ -48 │ lists:nth(7, Map). - │ ^^^ - │ │ - │ Map. -Expression has type: complex_map() -Context expected type: [T] - │ - -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 - │ -48 │ lists:nth(7, Map). - │ ^^^ - │ │ - │ Map. -Expression has type: complex_map() -Context expected type: [dynamic()] - │ - -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/strict_complex_types-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types.pretty similarity index 70% rename from crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types.pretty index cc9f9d0634..8943deb90a 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/strict_complex_types.pretty @@ -13,12 +13,6 @@ 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 │ @@ -46,12 +40,6 @@ 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 │ @@ -67,10 +55,4 @@ 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/strict_fun-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/strict_fun-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_fun-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_fun-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/strict_fun-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_fun-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_fun-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/strict_fun-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_fun-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_receive-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/strict_fun.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_receive-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/strict_fun.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_receive-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/strict_receive-OTP-27.pretty deleted file mode 100644 index 9bff7ab9cc..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_receive-OTP-27.pretty +++ /dev/null @@ -1,9 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/strict_receive.erl:71:9 - │ -71 │ after T -> ok - │ ^ T. -Expression has type: atom() -Context expected type: timeout() - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_receive-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/strict_receive-OTP-28.pretty deleted file mode 100644 index 9bff7ab9cc..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_receive-OTP-28.pretty +++ /dev/null @@ -1,9 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/strict_receive.erl:71:9 - │ -71 │ after T -> ok - │ ^ T. -Expression has type: atom() -Context expected type: timeout() - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/strict_receive-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/strict_receive.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/strict_receive-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/strict_receive.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg-OTP-26.pretty deleted file mode 100644 index 1ee53764d2..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg-OTP-26.pretty +++ /dev/null @@ -1,391 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:17:11 - │ -17 │ f01(X) -> X. - │ ^ X. -Expression has type: term() -Context expected type: {A, A} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:20:11 - │ -20 │ f02(X) -> X. - │ ^ X. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:24:11 - │ -24 │ f03(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun((atom()) -> term()) -Context expected type: fun((term()) -> atom()) - │ - -Because in the expression's type: - fun((atom()) -> - Here the type is: term() - 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 - │ -27 │ f04(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: 'a' | 'b' | 'c' -Context expected type: 'a' | 'b' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'a' | 'b' - 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 - │ -30 │ f05(X) -> X. - │ ^ X. -Expression has type: 'a' | 'b' -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:34:11 - │ -34 │ f06(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: {'a' | 'b', 'a' | 'b'} -Context expected type: {'a', 'b'} | {'b', 'a'} - │ - -Because in the expression's type: - { - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -38 │ f07(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: pair_ab() -Context expected type: pair_diff_elems() - │ - -Because in the expression's type: - { - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -41 │ f08(X) -> X. - │ ^ X. -Expression has type: {none(), none()} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:48:13 - │ -48 │ map02(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{a => atom()} -Context expected type: #{a := atom()} - │ - -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/subtype_neg.erl:52:13 - │ -52 │ map03(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{a := atom(), b := atom()} -Context expected type: #{a => atom()} - │ - -Because in the expression's type: - Here the type is: #{b := ...} - 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 - │ -60 │ map05(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{'a' | 'b' => 'a' | 'b' | 'c'} -Context expected type: #{a := 'a' | 'b', b => 'a' | 'b'} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -64 │ map06(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{term() => number()} -Context expected type: #{atom() => number()} - │ - -Because in the expression's type: - #{ map domains are incompatible: - Here the type is: term() - 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 - │ -68 │ map07(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{atom() => term()} -Context expected type: #{atom() => number()} - │ - -Because in the expression's type: - #{ atom() => - Here the type is: term() - 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 - │ -72 │ map08(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{atom() => term()} -Context expected type: #{} - │ - -Because in the expression's type: - Here the type is: #{atom() => term()} - 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 - │ -79 │ any_fun(F) -> F. - │ ^ F. -Expression has type: term() -Context expected type: fun() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:83:5 - │ -83 │ {{}, error}. - │ ^^^^^^^^^^^ - │ │ - │ {{}, 'error'}. -Expression has type: {{}, 'error'} -Context expected type: {tuple(), 'ok'} - │ - -Because in the expression's type: - { {}, - Here the type is: 'error' - 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 - │ -87 │ {[], error}. - │ ^^^^^^^^^^^ - │ │ - │ {[], 'error'}. -Expression has type: {[], 'error'} -Context expected type: {[pid()], 'ok'} - │ - -Because in the expression's type: - { [], - Here the type is: 'error' - 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 - │ -91 │ {[], error}. - │ ^^^^^^^^^^^ - │ │ - │ {[], 'error'}. -Expression has type: {[], 'error'} -Context expected type: {iolist(), 'ok'} - │ - -Because in the expression's type: - { [], - Here the type is: 'error' - 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 - │ -94 │ nil_1(L) -> L. - │ ^ - │ │ - │ L. -Expression has type: ['a'] -Context expected type: [] - │ - -Because in the expression's type: - [ - Here the type is: 'a' - Context expects type: none() - ] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:97:13 - │ -97 │ nil_2(L) -> L. - │ ^ - │ │ - │ L. -Expression has type: ['a'] | [none()] -Context expected type: [] - │ - -Because in the expression's type: - The type is a union type with some valid candidates: [none()] - However, the following candidate doesn't match: - [ - Here the type is: 'a' - 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/subtype_neg-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg-OTP-28.pretty deleted file mode 100644 index 1ee53764d2..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg-OTP-28.pretty +++ /dev/null @@ -1,391 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:17:11 - │ -17 │ f01(X) -> X. - │ ^ X. -Expression has type: term() -Context expected type: {A, A} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:20:11 - │ -20 │ f02(X) -> X. - │ ^ X. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:24:11 - │ -24 │ f03(F) -> F. - │ ^ - │ │ - │ F. -Expression has type: fun((atom()) -> term()) -Context expected type: fun((term()) -> atom()) - │ - -Because in the expression's type: - fun((atom()) -> - Here the type is: term() - 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 - │ -27 │ f04(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: 'a' | 'b' | 'c' -Context expected type: 'a' | 'b' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'a' | 'b' - 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 - │ -30 │ f05(X) -> X. - │ ^ X. -Expression has type: 'a' | 'b' -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:34:11 - │ -34 │ f06(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: {'a' | 'b', 'a' | 'b'} -Context expected type: {'a', 'b'} | {'b', 'a'} - │ - -Because in the expression's type: - { - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -38 │ f07(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: pair_ab() -Context expected type: pair_diff_elems() - │ - -Because in the expression's type: - { - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -41 │ f08(X) -> X. - │ ^ X. -Expression has type: {none(), none()} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:48:13 - │ -48 │ map02(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{a => atom()} -Context expected type: #{a := atom()} - │ - -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/subtype_neg.erl:52:13 - │ -52 │ map03(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{a := atom(), b := atom()} -Context expected type: #{a => atom()} - │ - -Because in the expression's type: - Here the type is: #{b := ...} - 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 - │ -60 │ map05(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{'a' | 'b' => 'a' | 'b' | 'c'} -Context expected type: #{a := 'a' | 'b', b => 'a' | 'b'} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -64 │ map06(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{term() => number()} -Context expected type: #{atom() => number()} - │ - -Because in the expression's type: - #{ map domains are incompatible: - Here the type is: term() - 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 - │ -68 │ map07(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{atom() => term()} -Context expected type: #{atom() => number()} - │ - -Because in the expression's type: - #{ atom() => - Here the type is: term() - 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 - │ -72 │ map08(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{atom() => term()} -Context expected type: #{} - │ - -Because in the expression's type: - Here the type is: #{atom() => term()} - 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 - │ -79 │ any_fun(F) -> F. - │ ^ F. -Expression has type: term() -Context expected type: fun() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:83:5 - │ -83 │ {{}, error}. - │ ^^^^^^^^^^^ - │ │ - │ {{}, 'error'}. -Expression has type: {{}, 'error'} -Context expected type: {tuple(), 'ok'} - │ - -Because in the expression's type: - { {}, - Here the type is: 'error' - 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 - │ -87 │ {[], error}. - │ ^^^^^^^^^^^ - │ │ - │ {[], 'error'}. -Expression has type: {[], 'error'} -Context expected type: {[pid()], 'ok'} - │ - -Because in the expression's type: - { [], - Here the type is: 'error' - 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 - │ -91 │ {[], error}. - │ ^^^^^^^^^^^ - │ │ - │ {[], 'error'}. -Expression has type: {[], 'error'} -Context expected type: {iolist(), 'ok'} - │ - -Because in the expression's type: - { [], - Here the type is: 'error' - 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 - │ -94 │ nil_1(L) -> L. - │ ^ - │ │ - │ L. -Expression has type: ['a'] -Context expected type: [] - │ - -Because in the expression's type: - [ - Here the type is: 'a' - Context expects type: none() - ] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/subtype_neg.erl:97:13 - │ -97 │ nil_2(L) -> L. - │ ^ - │ │ - │ L. -Expression has type: ['a'] | [none()] -Context expected type: [] - │ - -Because in the expression's type: - The type is a union type with some valid candidates: [none()] - However, the following candidate doesn't match: - [ - Here the type is: 'a' - 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/subtype_neg-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg.pretty similarity index 72% rename from crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg.pretty index 1ee53764d2..4413a8fee8 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_neg.pretty @@ -31,12 +31,6 @@ 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 │ @@ -53,14 +47,6 @@ 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 │ @@ -87,17 +73,6 @@ 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 │ @@ -116,17 +91,6 @@ 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 │ @@ -151,10 +115,6 @@ 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 │ @@ -171,10 +131,6 @@ 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 │ @@ -191,10 +147,6 @@ 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 │ @@ -212,13 +164,6 @@ 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 │ @@ -236,13 +181,6 @@ 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 │ @@ -259,13 +197,6 @@ 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 │ @@ -291,13 +222,6 @@ 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 │ @@ -315,13 +239,6 @@ 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 │ @@ -339,13 +256,6 @@ 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 │ @@ -382,10 +292,4 @@ 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/subtype_pos-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_pos-OTP-27.pretty deleted file mode 100644 index 20634a306c..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_pos-OTP-27.pretty +++ /dev/null @@ -1,13 +0,0 @@ -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/subtype_pos.erl:30:1 - │ -30 │ f05(X) -> X. - │ ^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/subtype_pos.erl:41:1 - │ -41 │ f08(X) -> X. - │ ^^^^^^^^^^^ Clause is not covered by spec - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_pos-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_pos-OTP-28.pretty deleted file mode 100644 index 20634a306c..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_pos-OTP-28.pretty +++ /dev/null @@ -1,13 +0,0 @@ -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/subtype_pos.erl:30:1 - │ -30 │ f05(X) -> X. - │ ^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/subtype_pos.erl:41:1 - │ -41 │ f08(X) -> X. - │ ^^^^^^^^^^^ Clause is not covered by spec - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_pos-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/subtype_pos.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/subtype_pos-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/subtype_pos.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/t_maps-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/t_maps-OTP-26.pretty deleted file mode 100644 index d0e08f9ac4..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/t_maps-OTP-26.pretty +++ /dev/null @@ -1,915 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/t_maps.erl:36:5 - │ -36 │ #{0 => 1, 1 => 2}. - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ #{..}. -Expression has type: #{number() => number()} -Context expected type: #{number() => atom()} - │ - -Because in the expression's type: - #{ number() => - Here the type is: number() - 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 - │ -41 │ #{0 => zero, 1 => 2}. - │ ^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #{..}. -Expression has type: #{number() => 'zero' | number()} -Context expected type: #{number() => atom()} - │ - -Because in the expression's type: - #{ number() => - Here the type is a union type with some valid candidates: 'zero' - However the following candidate: number() - 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 - │ -56 │ #{zero => 0, one => one}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #{..}. -Expression has type: #{one := 'one', zero := number()} -Context expected type: #{one => number(), zero := number()} - │ - -Because in the expression's type: - #{ one => - Here the type is: 'one' - 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 - │ -80 │ M#{}. - │ ^ M. -Expression has type: term() -Context expected type: #{term() => term()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/t_maps.erl:120:5 - │ -120 │ S#{bar := true}. - │ ^ S. -Expression has type: term() -Context expected type: #{term() => term()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/t_maps.erl:130:25 - │ -130 │ meet_dict2_neg(D, D) -> D. - │ ^ - │ │ - │ D. -Expression has type: #{b() => term()} -Context expected type: #{n() => term()} - │ - -Because in the expression's type: - #{ map domains are incompatible: - Here the type is: boolean() - 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 - │ -140 │ meet_shape2_neg(S, S) -> S. - │ ^ - │ │ - │ S. -Expression has type: #{a := b()} -Context expected type: #{a := n()} - │ - -Because in the expression's type: - #{ a => - Here the type is: boolean() - 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 - │ -145 │ meet_shape3_neg(S, S) -> S. - │ ^ - │ │ - │ S. -Expression has type: #{a := b()} -Context expected type: #{a => n()} - │ - -Because in the expression's type: - #{ a => - Here the type is: boolean() - 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 - │ -155 │ meet_shape5_neg(S, S) -> S. - │ ^ - │ │ - │ S. -Expression has type: #{a => b()} -Context expected type: #{a := b()} - │ - -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: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/t_maps.erl:165:1 - │ -165 │ meet_shape7(S, S) -> S. - │ ^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/t_maps.erl:202:5 - │ -202 │ S#{K => V}. - │ ^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{a := a(), n() => a()} -Context expected type: #{a() => a()} - │ - -Because in the expression's type: - #{ map domains are incompatible: - Here the type is: number() - 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 - │ -208 │ S#{K => V}. - │ ^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{a := a(), n() => a()} -Context expected type: #{n() => a()} - │ - -Because in the expression's type: - #{ incompatible map key a: - Here the type is: 'a' - 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 - │ -216 │ S#{K => V}. - │ ^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{a := a(), n() => a()} -Context expected type: #{n() => a()} - │ - -Because in the expression's type: - #{ incompatible map key a: - Here the type is: 'a' - 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 - │ -224 │ S#{K => V}. - │ ^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{a => a(), n() => a()} -Context expected type: #{n() => a()} - │ - -Because in the expression's type: - #{ incompatible map key a: - Here the type is: 'a' - 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 - │ -242 │ FB#{foo := F1, bar := B1}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{bar := B1, foo := F1} -Context expected type: foo_bar(B1, F1) - │ - -Because in the expression's type: - #{ bar => - Here the type is: B1 - 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 - │ -254 │ FB#{foo => F1, bar => B1}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{bar := B1, foo := F1} -Context expected type: foo_bar_opt(B1, F1) - │ - -Because in the expression's type: - #{ bar => - Here the type is: B1 - 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 - │ -266 │ Dict#{V2 => K2}. - │ ^^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{K1 | V2 => V1 | K2} -Context expected type: kv(K1 | K2, V1 | V2) - │ - -Because in the expression's type: - #{ map domains are incompatible: - Here the type is a union type with some valid candidates: K1 - However the following candidate: V2 - 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 - │ -283 │ needs_shape_a(X#{b => hello}). - │ ^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{a := number(), b := 'hello'} -Context expected type: #{a := term()} - │ - -Because in the expression's type: - Here the type is: #{b := ...} - 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 - │ -307 │ #{K := V} -> {K, V}; - │ ^^^^^^ - │ │ - │ {K, V}. -Expression has type: {a(), n()} -Context expected type: {n(), a()} - │ - -Because in the expression's type: - { - Here the type is: atom() - 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 - │ -321 │ {A, N}. - │ ^^^^^^ - │ │ - │ {A, N}. -Expression has type: {a(), n()} -Context expected type: {n(), a()} - │ - -Because in the expression's type: - { - Here the type is: atom() - 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 - │ -334 │ to_map3_neg(#{} = M) -> M; - │ ^ - │ │ - │ M. -Expression has type: #{V => K} -Context expected type: #{K => V} - │ - -Because in the expression's type: - #{ map domains are incompatible: - Here the type is: V - 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 - │ -351 │ to_map5_neg(#{} = M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{a() => n()} | #{n() => a()} | #{id => 'id' | 'no_id'} -Context expected type: #{a() | n() => a()} - │ - -Because in the expression's type: - The type is a union type with some valid candidates: #{n() => a()} | #{id => 'id' | 'no_id'} - However, the following candidate doesn't match: - #{ a() => - Here the type is: number() - 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 - │ -356 │ no_map(#{} = M) -> M. - │ ^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/t_maps.erl:361:1 - │ -361 │ no_prop(#{foo := V}) -> V. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/t_maps.erl:377:22 - │ -377 │ #{K := V} -> {K, V}; - │ ^^^^^^ - │ │ - │ {K, V}. -Expression has type: {'a' | 'b', a()} -Context expected type: {n(), a()} - │ - -Because in the expression's type: - { - Here the type is: 'a' | 'b' - Context expects type: number() - 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 - │ -429 │ val3(#{a := V}) -> V. - │ ^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/t_maps.erl:434:1 - │ -434 │ val4(#{a := V}) -> V. - │ ^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/t_maps.erl:451:1 - │ -451 │ guard2(M) when is_map(M) -> M. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/t_maps.erl:493:1 - │ -493 │ update_none1(N) -> N#{a := 1}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/t_maps.erl:496:1 - │ -496 │ update_none2(N) -> N#{a => 1}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/t_maps.erl:508:17 - │ -508 │ sub_3_neg(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{a := atom()} -Context expected type: #{a => atom(), n := number()} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -536 │ maps:update_with(a, F, a, Map). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ maps:update_with('a', F, 'a', Map). -Expression has type: #{a => 'b' | 'c' | 'a'} -Context expected type: #{a => 'b' | 'c'} - │ - -Because in the expression's type: - #{ a => - Here the type is a union type with some valid candidates: 'b' | 'c' - However the following candidate: 'a' - 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 - │ -571 │ X. - │ ^ - │ │ - │ X. -Expression has type: rec_shape() -Context expected type: rec_shape_v2() - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -629 │ X. - │ ^ - │ │ - │ X. -Expression has type: gen_shape('a' | 'b') -Context expected type: 'a' | #{item := 'a' | #{item := 'a' | gen_shape('a')}} - │ - -Because in the expression's type: - #{ item => - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -641 │ X. - │ ^ - │ │ - │ X. -Expression has type: gen_shape_v2('a') -Context expected type: gen_shape('a') - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -648 │ X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'va', b => 'vb', c => 'vc', d => 'vd'} -Context expected type: #{a => 'va', b => 'vb', c => 'vc'} - │ - -Because in the expression's type: - Here the type is: #{d => ...} - 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 - │ -661 │ X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'va', b => 'vb', c => 'vc', d => 'vd', e => 've'} -Context expected type: #{a => 'ka', b => 'kb', c => 'kc'} - │ - -Because in the expression's type: - #{ a => - Here the type is: 'va' - 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 - │ -675 │ X. - │ ^ - │ │ - │ X. -Expression has type: #{} -Context expected type: #{a => 'va', b => 'vb', c := 'vc'} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -682 │ X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'ka', b => 'kb', c => 'kc'} -Context expected type: #{a => 'ka', b := 'kb', c => 'kc'} - │ - -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/t_maps.erl:689:5 - │ -689 │ X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'ka', b => 'kb', c => 'kc'} -Context expected type: #{a => 'ka', b := 'kb', c => 'kc'} - │ - -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/t_maps.erl:710:5 - │ -710 │ X. - │ ^ - │ │ - │ X. -Expression has type: #{k_extra => term(), k_ok => term(), k_req1 => term(), k_req2 => term(), k_wrong1 => pid(), k_wrong2 => pid()} -Context expected type: #{k_ok => term(), k_req1 := atom(), k_req2 := atom(), k_req3 := atom(), k_wrong1 => atom(), k_wrong2 => atom()} - │ - -Because in the expression's type: - Here the type is: #{k_req2 => ..., k_req1 => ..., ...} - 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 - │ -732 │ dict_to_shape_neg_1(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{'a' | 'b' => boolean()} -Context expected type: #{a => 'true', b => boolean()} - │ - -Because in the expression's type: - Here the type is: #{'a' | 'b' => boolean()} - 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 - │ -737 │ dict_to_shape_neg_2(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{'a' | 'b' => boolean()} -Context expected type: #{a => boolean(), b := term()} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -742 │ dict_to_shape_neg_3(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{'a' | 'b' => boolean()} -Context expected type: #{a => boolean()} - │ - -Because in the expression's type: - Here the type is: #{'a' | 'b' => boolean()} - 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/t_maps-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/t_maps-OTP-28.pretty deleted file mode 100644 index d0e08f9ac4..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/t_maps-OTP-28.pretty +++ /dev/null @@ -1,915 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/t_maps.erl:36:5 - │ -36 │ #{0 => 1, 1 => 2}. - │ ^^^^^^^^^^^^^^^^^ - │ │ - │ #{..}. -Expression has type: #{number() => number()} -Context expected type: #{number() => atom()} - │ - -Because in the expression's type: - #{ number() => - Here the type is: number() - 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 - │ -41 │ #{0 => zero, 1 => 2}. - │ ^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #{..}. -Expression has type: #{number() => 'zero' | number()} -Context expected type: #{number() => atom()} - │ - -Because in the expression's type: - #{ number() => - Here the type is a union type with some valid candidates: 'zero' - However the following candidate: number() - 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 - │ -56 │ #{zero => 0, one => one}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ #{..}. -Expression has type: #{one := 'one', zero := number()} -Context expected type: #{one => number(), zero := number()} - │ - -Because in the expression's type: - #{ one => - Here the type is: 'one' - 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 - │ -80 │ M#{}. - │ ^ M. -Expression has type: term() -Context expected type: #{term() => term()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/t_maps.erl:120:5 - │ -120 │ S#{bar := true}. - │ ^ S. -Expression has type: term() -Context expected type: #{term() => term()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/t_maps.erl:130:25 - │ -130 │ meet_dict2_neg(D, D) -> D. - │ ^ - │ │ - │ D. -Expression has type: #{b() => term()} -Context expected type: #{n() => term()} - │ - -Because in the expression's type: - #{ map domains are incompatible: - Here the type is: boolean() - 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 - │ -140 │ meet_shape2_neg(S, S) -> S. - │ ^ - │ │ - │ S. -Expression has type: #{a := b()} -Context expected type: #{a := n()} - │ - -Because in the expression's type: - #{ a => - Here the type is: boolean() - 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 - │ -145 │ meet_shape3_neg(S, S) -> S. - │ ^ - │ │ - │ S. -Expression has type: #{a := b()} -Context expected type: #{a => n()} - │ - -Because in the expression's type: - #{ a => - Here the type is: boolean() - 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 - │ -155 │ meet_shape5_neg(S, S) -> S. - │ ^ - │ │ - │ S. -Expression has type: #{a => b()} -Context expected type: #{a := b()} - │ - -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: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/t_maps.erl:165:1 - │ -165 │ meet_shape7(S, S) -> S. - │ ^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/t_maps.erl:202:5 - │ -202 │ S#{K => V}. - │ ^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{a := a(), n() => a()} -Context expected type: #{a() => a()} - │ - -Because in the expression's type: - #{ map domains are incompatible: - Here the type is: number() - 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 - │ -208 │ S#{K => V}. - │ ^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{a := a(), n() => a()} -Context expected type: #{n() => a()} - │ - -Because in the expression's type: - #{ incompatible map key a: - Here the type is: 'a' - 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 - │ -216 │ S#{K => V}. - │ ^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{a := a(), n() => a()} -Context expected type: #{n() => a()} - │ - -Because in the expression's type: - #{ incompatible map key a: - Here the type is: 'a' - 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 - │ -224 │ S#{K => V}. - │ ^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{a => a(), n() => a()} -Context expected type: #{n() => a()} - │ - -Because in the expression's type: - #{ incompatible map key a: - Here the type is: 'a' - 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 - │ -242 │ FB#{foo := F1, bar := B1}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{bar := B1, foo := F1} -Context expected type: foo_bar(B1, F1) - │ - -Because in the expression's type: - #{ bar => - Here the type is: B1 - 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 - │ -254 │ FB#{foo => F1, bar => B1}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{bar := B1, foo := F1} -Context expected type: foo_bar_opt(B1, F1) - │ - -Because in the expression's type: - #{ bar => - Here the type is: B1 - 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 - │ -266 │ Dict#{V2 => K2}. - │ ^^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{K1 | V2 => V1 | K2} -Context expected type: kv(K1 | K2, V1 | V2) - │ - -Because in the expression's type: - #{ map domains are incompatible: - Here the type is a union type with some valid candidates: K1 - However the following candidate: V2 - 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 - │ -283 │ needs_shape_a(X#{b => hello}). - │ ^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{a := number(), b := 'hello'} -Context expected type: #{a := term()} - │ - -Because in the expression's type: - Here the type is: #{b := ...} - 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 - │ -307 │ #{K := V} -> {K, V}; - │ ^^^^^^ - │ │ - │ {K, V}. -Expression has type: {a(), n()} -Context expected type: {n(), a()} - │ - -Because in the expression's type: - { - Here the type is: atom() - 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 - │ -321 │ {A, N}. - │ ^^^^^^ - │ │ - │ {A, N}. -Expression has type: {a(), n()} -Context expected type: {n(), a()} - │ - -Because in the expression's type: - { - Here the type is: atom() - 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 - │ -334 │ to_map3_neg(#{} = M) -> M; - │ ^ - │ │ - │ M. -Expression has type: #{V => K} -Context expected type: #{K => V} - │ - -Because in the expression's type: - #{ map domains are incompatible: - Here the type is: V - 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 - │ -351 │ to_map5_neg(#{} = M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{a() => n()} | #{n() => a()} | #{id => 'id' | 'no_id'} -Context expected type: #{a() | n() => a()} - │ - -Because in the expression's type: - The type is a union type with some valid candidates: #{n() => a()} | #{id => 'id' | 'no_id'} - However, the following candidate doesn't match: - #{ a() => - Here the type is: number() - 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 - │ -356 │ no_map(#{} = M) -> M. - │ ^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/t_maps.erl:361:1 - │ -361 │ no_prop(#{foo := V}) -> V. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/t_maps.erl:377:22 - │ -377 │ #{K := V} -> {K, V}; - │ ^^^^^^ - │ │ - │ {K, V}. -Expression has type: {'a' | 'b', a()} -Context expected type: {n(), a()} - │ - -Because in the expression's type: - { - Here the type is: 'a' | 'b' - Context expects type: number() - 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 - │ -429 │ val3(#{a := V}) -> V. - │ ^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/t_maps.erl:434:1 - │ -434 │ val4(#{a := V}) -> V. - │ ^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/t_maps.erl:451:1 - │ -451 │ guard2(M) when is_map(M) -> M. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/t_maps.erl:493:1 - │ -493 │ update_none1(N) -> N#{a := 1}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/t_maps.erl:496:1 - │ -496 │ update_none2(N) -> N#{a => 1}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/t_maps.erl:508:17 - │ -508 │ sub_3_neg(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{a := atom()} -Context expected type: #{a => atom(), n := number()} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -536 │ maps:update_with(a, F, a, Map). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ maps:update_with('a', F, 'a', Map). -Expression has type: #{a => 'b' | 'c' | 'a'} -Context expected type: #{a => 'b' | 'c'} - │ - -Because in the expression's type: - #{ a => - Here the type is a union type with some valid candidates: 'b' | 'c' - However the following candidate: 'a' - 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 - │ -571 │ X. - │ ^ - │ │ - │ X. -Expression has type: rec_shape() -Context expected type: rec_shape_v2() - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -629 │ X. - │ ^ - │ │ - │ X. -Expression has type: gen_shape('a' | 'b') -Context expected type: 'a' | #{item := 'a' | #{item := 'a' | gen_shape('a')}} - │ - -Because in the expression's type: - #{ item => - Here the type is a union type with some valid candidates: 'a' - However the following candidate: 'b' - 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 - │ -641 │ X. - │ ^ - │ │ - │ X. -Expression has type: gen_shape_v2('a') -Context expected type: gen_shape('a') - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -648 │ X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'va', b => 'vb', c => 'vc', d => 'vd'} -Context expected type: #{a => 'va', b => 'vb', c => 'vc'} - │ - -Because in the expression's type: - Here the type is: #{d => ...} - 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 - │ -661 │ X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'va', b => 'vb', c => 'vc', d => 'vd', e => 've'} -Context expected type: #{a => 'ka', b => 'kb', c => 'kc'} - │ - -Because in the expression's type: - #{ a => - Here the type is: 'va' - 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 - │ -675 │ X. - │ ^ - │ │ - │ X. -Expression has type: #{} -Context expected type: #{a => 'va', b => 'vb', c := 'vc'} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -682 │ X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'ka', b => 'kb', c => 'kc'} -Context expected type: #{a => 'ka', b := 'kb', c => 'kc'} - │ - -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/t_maps.erl:689:5 - │ -689 │ X. - │ ^ - │ │ - │ X. -Expression has type: #{a => 'ka', b => 'kb', c => 'kc'} -Context expected type: #{a => 'ka', b := 'kb', c => 'kc'} - │ - -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/t_maps.erl:710:5 - │ -710 │ X. - │ ^ - │ │ - │ X. -Expression has type: #{k_extra => term(), k_ok => term(), k_req1 => term(), k_req2 => term(), k_wrong1 => pid(), k_wrong2 => pid()} -Context expected type: #{k_ok => term(), k_req1 := atom(), k_req2 := atom(), k_req3 := atom(), k_wrong1 => atom(), k_wrong2 => atom()} - │ - -Because in the expression's type: - Here the type is: #{k_req2 => ..., k_req1 => ..., ...} - 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 - │ -732 │ dict_to_shape_neg_1(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{'a' | 'b' => boolean()} -Context expected type: #{a => 'true', b => boolean()} - │ - -Because in the expression's type: - Here the type is: #{'a' | 'b' => boolean()} - 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 - │ -737 │ dict_to_shape_neg_2(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{'a' | 'b' => boolean()} -Context expected type: #{a => boolean(), b := term()} - │ - -Because in the expression's type: - Here the type is: #{...} - 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 - │ -742 │ dict_to_shape_neg_3(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: #{'a' | 'b' => boolean()} -Context expected type: #{a => boolean()} - │ - -Because in the expression's type: - Here the type is: #{'a' | 'b' => boolean()} - 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/t_maps-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/t_maps.pretty similarity index 66% rename from crates/elp/src/resources/test/eqwalizer_tests/check/t_maps-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/t_maps.pretty index d0e08f9ac4..5c2b07ae96 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/t_maps-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/t_maps.pretty @@ -15,13 +15,6 @@ 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 │ @@ -40,15 +33,6 @@ 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 │ @@ -66,15 +50,6 @@ 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 │ @@ -108,15 +83,6 @@ 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 │ @@ -134,17 +100,6 @@ 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 │ @@ -162,17 +117,6 @@ 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 │ @@ -189,10 +133,6 @@ 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 │ @@ -216,17 +156,6 @@ 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 │ @@ -244,17 +173,6 @@ 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 │ @@ -272,17 +190,6 @@ 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 │ @@ -300,17 +207,6 @@ 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 │ @@ -328,17 +224,6 @@ 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 │ @@ -356,17 +241,6 @@ 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 │ @@ -385,17 +259,6 @@ 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 │ @@ -412,10 +275,6 @@ 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 │ @@ -433,17 +292,6 @@ 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 │ @@ -461,17 +309,6 @@ 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 │ @@ -489,13 +326,6 @@ 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 │ @@ -515,17 +345,6 @@ 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 │ @@ -556,15 +375,6 @@ 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 │ @@ -611,10 +421,6 @@ 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 │ @@ -633,17 +439,6 @@ 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 │ @@ -660,15 +455,6 @@ 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 │ @@ -687,14 +473,6 @@ 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 │ @@ -711,15 +489,6 @@ 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 │ @@ -736,10 +505,6 @@ 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 │ @@ -757,15 +522,6 @@ 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 │ @@ -782,10 +538,6 @@ 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 │ @@ -802,10 +554,6 @@ 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 │ @@ -822,10 +570,6 @@ 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 │ @@ -842,10 +586,6 @@ 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 │ @@ -862,13 +602,6 @@ 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 │ @@ -885,10 +618,6 @@ 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 │ @@ -905,11 +634,4 @@ 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/tagged_tuples-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/tagged_tuples-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/tagged_tuples-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/tagged_tuples-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/tagged_tuples-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/tagged_tuples-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/tagged_tuples-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/tagged_tuples-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/tagged_tuples-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_receive-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/tagged_tuples.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_receive-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/tagged_tuples.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/test-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/test-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/test-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/test-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/test-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/test-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/test-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/test-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/test-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_receive-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/test.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_receive-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/test.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/tries-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/tries-OTP-26.pretty deleted file mode 100644 index 471b5c8ebe..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/tries-OTP-26.pretty +++ /dev/null @@ -1,79 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:30:19 - │ -30 │ {_, Y} -> Y - │ ^ Y. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:42:5 - │ -42 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: [] | 'error' -Context expected type: atom() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'error' - 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 - │ -75 │ catch _ -> error - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:80:9 - │ -80 │ try ok() - │ ^^^^ ok(). -Expression has type: 'ok' -Context expected type: 'error' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:88:19 - │ -88 │ only_atom(1) - │ ^ 1. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:130:17 - │ -130 │ true -> Y - │ ^ Y. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:136:19 - │ -136 │ {X, X} -> X - │ ^ X. -Expression has type: term() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:148:5 - │ -148 │ Res. - │ ^^^ Res. -Expression has type: term() -Context expected type: 'ok' - -8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/tries-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/tries-OTP-27.pretty deleted file mode 100644 index 471b5c8ebe..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/tries-OTP-27.pretty +++ /dev/null @@ -1,79 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:30:19 - │ -30 │ {_, Y} -> Y - │ ^ Y. -Expression has type: term() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:42:5 - │ -42 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: [] | 'error' -Context expected type: atom() - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'error' - 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 - │ -75 │ catch _ -> error - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:80:9 - │ -80 │ try ok() - │ ^^^^ ok(). -Expression has type: 'ok' -Context expected type: 'error' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:88:19 - │ -88 │ only_atom(1) - │ ^ 1. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:130:17 - │ -130 │ true -> Y - │ ^ Y. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:136:19 - │ -136 │ {X, X} -> X - │ ^ X. -Expression has type: term() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tries.erl:148:5 - │ -148 │ Res. - │ ^^^ Res. -Expression has type: term() -Context expected type: 'ok' - -8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/tries-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/tries.pretty similarity index 92% rename from crates/elp/src/resources/test/eqwalizer_tests/check/tries-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/tries.pretty index 471b5c8ebe..5f9c8914f4 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/tries-OTP-28.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/tries.pretty @@ -22,12 +22,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/tuple_union-OTP-26.pretty deleted file mode 100644 index e02af30869..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/tuple_union-OTP-26.pretty +++ /dev/null @@ -1,60 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tuple_union.erl:27:19 - │ -27 │ test_03_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: t4() -Context expected type: t5() - │ - -Because in the expression's type: - { 'msg', - Here the type is a union type with some valid candidates: 'ok' - However the following candidate: 'err' - 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 - │ -66 │ tree3_as_tree1_neg(T) -> T. - │ ^ - │ │ - │ T. -Expression has type: tree3() -Context expected type: tree1() - │ - -Because in the expression's type: - The type is a union type with some valid candidates: {'leaf', atom()} - However, the following candidate doesn't match: - { - Here the type is: 'b1' | 'b2' | 'b3' - Context expects type: 'leaf' - 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/tuple_union-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/tuple_union-OTP-27.pretty deleted file mode 100644 index e02af30869..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/tuple_union-OTP-27.pretty +++ /dev/null @@ -1,60 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/tuple_union.erl:27:19 - │ -27 │ test_03_neg(X) -> X. - │ ^ - │ │ - │ X. -Expression has type: t4() -Context expected type: t5() - │ - -Because in the expression's type: - { 'msg', - Here the type is a union type with some valid candidates: 'ok' - However the following candidate: 'err' - 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 - │ -66 │ tree3_as_tree1_neg(T) -> T. - │ ^ - │ │ - │ T. -Expression has type: tree3() -Context expected type: tree1() - │ - -Because in the expression's type: - The type is a union type with some valid candidates: {'leaf', atom()} - However, the following candidate doesn't match: - { - Here the type is: 'b1' | 'b2' | 'b3' - Context expects type: 'leaf' - 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/tuple_union-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/tuple_union.pretty similarity index 56% rename from crates/elp/src/resources/test/eqwalizer_tests/check/tuple_union-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/tuple_union.pretty index e02af30869..5b2cca1631 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/tuple_union-OTP-28.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/tuple_union.pretty @@ -16,17 +16,6 @@ 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 │ @@ -47,14 +36,4 @@ 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_aliases-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/type_aliases-OTP-27.pretty deleted file mode 100644 index 0518a9a064..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/type_aliases-OTP-27.pretty +++ /dev/null @@ -1,157 +0,0 @@ -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ check/src/type_aliases.erl:9:1 - │ -9 │ -type w_unbound_var() :: {_A, _B}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _A: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:10:1 - │ -10 │ ╭ -type trans_unbound_var() -11 │ │ :: w_unbound_var(). - │ ╰────────────────────^ trans_unbound_var/0 references type with invalid definition: w_unbound_var/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:13:1 - │ -13 │ ╭ -spec uses_ty_w_unbound_var(_A, _B) -> -14 │ │ w_unbound_var(). - │ ╰─────────────────^ uses_ty_w_unbound_var/2 references type with invalid definition: w_unbound_var/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:17:1 - │ -17 │ ╭ -spec uses_trans_unbound_var(_A, _B) -> -18 │ │ trans_unbound_var(). - │ ╰─────────────────────^ uses_trans_unbound_var/2 references type with invalid definition: trans_unbound_var/0 - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ check/src/type_aliases.erl:21:1 - │ -21 │ ╭ -type w_unbound_var2() -22 │ │ :: _A. - │ ╰─────────^ _A: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:24:1 - │ -24 │ ╭ -spec uses_ty_w_unbound_var2() -> -25 │ │ w_unbound_var2(). - │ ╰──────────────────^ uses_ty_w_unbound_var2/0 references type with invalid definition: w_unbound_var2/0 - -error: repated_type_var_in_type_decl (See https://fb.me/eqwalizer_errors#repated_type_var_in_type_decl) - ┌─ check/src/type_aliases.erl:28:1 - │ -28 │ -type repeated(T, T) :: T. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ T. Type vars in type declarations must be distinct - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:30:1 - │ -30 │ ╭ -spec test_repeated1_neg(a, b) -> -31 │ │ repeated(a, b). - │ ╰────────────^ test_repeated1_neg/2 references type with invalid definition: repeated/2 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:34:1 - │ -34 │ ╭ -spec test_repeated2_neg(a, b) -> -35 │ │ repeated(a, b). - │ ╰────────────^ test_repeated2_neg/2 references type with invalid definition: repeated/2 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:39:1 - │ -39 │ ╭ -spec test_use_bad_type -40 │ │ (undefined | w_unbound_var()) -> -41 │ │ w_unbound_var() | undefined. - │ ╰───────────────────────────────^ test_use_bad_type/1 references type with invalid definition: w_unbound_var/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:48:1 - │ -48 │ ╭ -spec test_use_bad_type_gen( -49 │ │ w_unbound_var(), -50 │ │ undefined | w_unbound_var()) -> -51 │ │ term(). - │ ╰────────────^ test_use_bad_type_gen/2 references type with invalid definition: w_unbound_var/0 - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ check/src/type_aliases.erl:55:1 - │ -55 │ ╭ -type tup_w_unbound(T) -56 │ │ :: {T, _A}. - │ ╰──────────^ _A: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:58:1 - │ -58 │ ╭ -spec unpack_tup_w_unbound( -59 │ │ tup_w_unbound(T) -60 │ │ ) -> T. - │ ╰──────^ unpack_tup_w_unbound/1 references type with invalid definition: tup_w_unbound/1 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:64:1 - │ -64 │ ╭ -spec test_use_unpack_tup_w_unbound( -65 │ │ tup_w_unbound(a)) -> a. - │ ╰──────────────────────────^ test_use_unpack_tup_w_unbound/1 references type with invalid definition: tup_w_unbound/1 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:69:1 - │ -69 │ ╭ -spec test_use_tup_w_unbound_cov( -70 │ │ tup_w_unbound(a)) -> -71 │ │ tup_w_unbound(a | b) . - │ ╰─────────────────^ test_use_tup_w_unbound_cov/1 references type with invalid definition: tup_w_unbound/1 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:75:1 - │ -75 │ ╭ -spec test_use_tup_w_unbound_contra_neg( -76 │ │ tup_w_unbound(a | b)) -> -77 │ │ tup_w_unbound(a) . - │ ╰─────────────────^ test_use_tup_w_unbound_contra_neg/1 references type with invalid definition: tup_w_unbound/1 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:81:1 - │ -81 │ ╭ -spec test_use_tup_w_unbound_contra_neg2( -82 │ │ tup_w_unbound(a | b)) -> -83 │ │ tup_w_unbound(a) | w_unbound_var(). - │ ╰────────────────────────────────────^ test_use_tup_w_unbound_contra_neg2/1 references types with invalid definitions: tup_w_unbound/1, w_unbound_var/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/type_aliases.erl:87:1 - │ -87 │ -type loop() :: loop(). - │ ^^^^^^^^^^^^^^^^^^^^ recursive type loop/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:89:1 - │ -89 │ -record(rec1, {l :: loop() | undefined}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rec1 references type with invalid definition: loop/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:90:1 - │ -90 │ -record(rec2, {l :: undefined | loop()}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rec2 references type with invalid definition: loop/0 - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/type_aliases.erl:104:21 - │ -104 │ opaque:opair(a, x:y()). - │ ^^^^^ Unknown id: x:y/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:106:1 - │ -106 │ ╭ -spec use_bad_inside_neg( -107 │ │ bad_inside() -108 │ │ ) -> bad_inside(). - │ ╰───────────────^ use_bad_inside_neg/1 references type with invalid definition: bad_inside/0 - -22 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/type_aliases-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/type_aliases-OTP-28.pretty deleted file mode 100644 index 0518a9a064..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/type_aliases-OTP-28.pretty +++ /dev/null @@ -1,157 +0,0 @@ -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ check/src/type_aliases.erl:9:1 - │ -9 │ -type w_unbound_var() :: {_A, _B}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _A: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:10:1 - │ -10 │ ╭ -type trans_unbound_var() -11 │ │ :: w_unbound_var(). - │ ╰────────────────────^ trans_unbound_var/0 references type with invalid definition: w_unbound_var/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:13:1 - │ -13 │ ╭ -spec uses_ty_w_unbound_var(_A, _B) -> -14 │ │ w_unbound_var(). - │ ╰─────────────────^ uses_ty_w_unbound_var/2 references type with invalid definition: w_unbound_var/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:17:1 - │ -17 │ ╭ -spec uses_trans_unbound_var(_A, _B) -> -18 │ │ trans_unbound_var(). - │ ╰─────────────────────^ uses_trans_unbound_var/2 references type with invalid definition: trans_unbound_var/0 - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ check/src/type_aliases.erl:21:1 - │ -21 │ ╭ -type w_unbound_var2() -22 │ │ :: _A. - │ ╰─────────^ _A: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:24:1 - │ -24 │ ╭ -spec uses_ty_w_unbound_var2() -> -25 │ │ w_unbound_var2(). - │ ╰──────────────────^ uses_ty_w_unbound_var2/0 references type with invalid definition: w_unbound_var2/0 - -error: repated_type_var_in_type_decl (See https://fb.me/eqwalizer_errors#repated_type_var_in_type_decl) - ┌─ check/src/type_aliases.erl:28:1 - │ -28 │ -type repeated(T, T) :: T. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ T. Type vars in type declarations must be distinct - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:30:1 - │ -30 │ ╭ -spec test_repeated1_neg(a, b) -> -31 │ │ repeated(a, b). - │ ╰────────────^ test_repeated1_neg/2 references type with invalid definition: repeated/2 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:34:1 - │ -34 │ ╭ -spec test_repeated2_neg(a, b) -> -35 │ │ repeated(a, b). - │ ╰────────────^ test_repeated2_neg/2 references type with invalid definition: repeated/2 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:39:1 - │ -39 │ ╭ -spec test_use_bad_type -40 │ │ (undefined | w_unbound_var()) -> -41 │ │ w_unbound_var() | undefined. - │ ╰───────────────────────────────^ test_use_bad_type/1 references type with invalid definition: w_unbound_var/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:48:1 - │ -48 │ ╭ -spec test_use_bad_type_gen( -49 │ │ w_unbound_var(), -50 │ │ undefined | w_unbound_var()) -> -51 │ │ term(). - │ ╰────────────^ test_use_bad_type_gen/2 references type with invalid definition: w_unbound_var/0 - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ check/src/type_aliases.erl:55:1 - │ -55 │ ╭ -type tup_w_unbound(T) -56 │ │ :: {T, _A}. - │ ╰──────────^ _A: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:58:1 - │ -58 │ ╭ -spec unpack_tup_w_unbound( -59 │ │ tup_w_unbound(T) -60 │ │ ) -> T. - │ ╰──────^ unpack_tup_w_unbound/1 references type with invalid definition: tup_w_unbound/1 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:64:1 - │ -64 │ ╭ -spec test_use_unpack_tup_w_unbound( -65 │ │ tup_w_unbound(a)) -> a. - │ ╰──────────────────────────^ test_use_unpack_tup_w_unbound/1 references type with invalid definition: tup_w_unbound/1 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:69:1 - │ -69 │ ╭ -spec test_use_tup_w_unbound_cov( -70 │ │ tup_w_unbound(a)) -> -71 │ │ tup_w_unbound(a | b) . - │ ╰─────────────────^ test_use_tup_w_unbound_cov/1 references type with invalid definition: tup_w_unbound/1 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:75:1 - │ -75 │ ╭ -spec test_use_tup_w_unbound_contra_neg( -76 │ │ tup_w_unbound(a | b)) -> -77 │ │ tup_w_unbound(a) . - │ ╰─────────────────^ test_use_tup_w_unbound_contra_neg/1 references type with invalid definition: tup_w_unbound/1 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:81:1 - │ -81 │ ╭ -spec test_use_tup_w_unbound_contra_neg2( -82 │ │ tup_w_unbound(a | b)) -> -83 │ │ tup_w_unbound(a) | w_unbound_var(). - │ ╰────────────────────────────────────^ test_use_tup_w_unbound_contra_neg2/1 references types with invalid definitions: tup_w_unbound/1, w_unbound_var/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ check/src/type_aliases.erl:87:1 - │ -87 │ -type loop() :: loop(). - │ ^^^^^^^^^^^^^^^^^^^^ recursive type loop/0 is not productive - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:89:1 - │ -89 │ -record(rec1, {l :: loop() | undefined}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rec1 references type with invalid definition: loop/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:90:1 - │ -90 │ -record(rec2, {l :: undefined | loop()}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rec2 references type with invalid definition: loop/0 - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/type_aliases.erl:104:21 - │ -104 │ opaque:opair(a, x:y()). - │ ^^^^^ Unknown id: x:y/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ check/src/type_aliases.erl:106:1 - │ -106 │ ╭ -spec use_bad_inside_neg( -107 │ │ bad_inside() -108 │ │ ) -> bad_inside(). - │ ╰───────────────^ use_bad_inside_neg/1 references type with invalid definition: bad_inside/0 - -22 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/type_aliases-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/type_aliases.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/type_aliases-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/type_aliases.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts-OTP-26.pretty deleted file mode 100644 index c5fb63ed41..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts-OTP-26.pretty +++ /dev/null @@ -1,256 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:39:3 - │ -39 │ Arg. - │ ^^^ Arg. -Expression has type: string() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:48:3 - │ -48 │ Arg. - │ ^^^ - │ │ - │ Arg. -Expression has type: string() | binary() -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 ------------------------------ - - 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 - │ -63 │ andalso list_to_atom(A). - │ ^ A. -Expression has type: binary() -Context expected type: string() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:70:26 - │ -70 │ andalso list_to_atom(A). - │ ^ A. -Expression has type: binary() -Context expected type: string() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:84:3 - │ -84 │ ╭ ╭ is_number(N) -85 │ │ │ andalso is_atom(A) -86 │ │ │ andalso {N, A}. - │ ╰─│──────────────────^ _ andalso _. -Expression has type: 'false' | {number(), atom()} -Context expected type: 'false' | {atom(), number()} - │ ╰──────────────────' - -Because in the expression's type: - The type is a union type with some valid candidates: 'false' - However, the following candidate doesn't match: - { - Here the type is: number() - 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 - │ -92 │ {X, A}. - │ ^^^^^^ - │ │ - │ {X, A}. -Expression has type: {'false' | number(), term()} -Context expected type: {'false' | number(), number()} - │ - -Because in the expression's type: - { 'false' | number(), - Here the type is: term() - 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 - │ -105 │ checked_cast1_neg(A) -> ?checked_cast(A, ok). - │ ^ A. -Expression has type: atom() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:108:25 - │ -108 │ checked_cast2_neg(A) -> ?checked_cast(A, atom()). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ .. :: ... -Expression has type: atom() -Context expected type: 'ok' - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/type_asserts.erl:110:20 - │ -110 │ -type invalid() :: foo:non_exist(). - │ ^^^^^^^^^^^^^^^ Unknown id: foo:non_exist/0 - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/type_asserts.erl:113:42 - │ -113 │ checked_cast3_neg(A) -> ?checked_cast(A, foo:non_exist()). - │ ^^^^^^^^^^^^^^^ Unknown id: foo:non_exist/0 - -error: invalid_ref_in_type_cast (See https://fb.me/eqwalizer_errors#invalid_ref_in_type_cast) - ┌─ check/src/type_asserts.erl:116:42 - │ -116 │ checked_cast4_neg(A) -> ?checked_cast(A, {ok, invalid()}). - │ ^^^^^^^^^^^^^^^ type cast references type with invalid definition: invalid/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:126:9 - │ -126 │ Acc#{K => V#{ka => va}}; - │ ^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{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'}} -Context expected type: #{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 in the expression's type: - #{ dynamic() => - Here the type is: #{kb := ...} - Context expects 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 - │ -129 │ Acc#{K => V#{kb => vb}}; - │ ^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{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'}} -Context expected type: #{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 in the expression's type: - #{ dynamic() => - Here the type is: #{kb := ...} - Context expects 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 - │ -132 │ Acc#{K => V#{kc => vc}} - │ ^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{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'}} -Context expected type: #{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 in the expression's type: - #{ dynamic() => - Here the type is: #{kb := ...} - Context expects 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 - │ -156 │ unsafe_cast1_neg(A) -> ?unchecked_cast(A, err). - │ ^^^^^^^^^^^^^^^^^^^^^^^ .. :: ... -Expression has type: 'err' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:159:40 - │ -159 │ unsafe_cast2_neg(D) -> ?unchecked_cast(a + D, ok). - │ ^ 'a'. -Expression has type: 'a' -Context expected type: number() - -error: variables_in_type_cast (See https://fb.me/eqwalizer_errors#variables_in_type_cast) - ┌─ check/src/type_asserts.erl:163:21 - │ -163 │ ?checked_cast(ok, A). - │ ^ type variables are not allowed in type casts, found: A - -error: variables_in_type_cast (See https://fb.me/eqwalizer_errors#variables_in_type_cast) - ┌─ check/src/type_asserts.erl:167:23 - │ -167 │ ?unchecked_cast(ok, A | B). - │ ^^^^^ type variables are not allowed in type casts, found: A, B - -error: refined_record_in_type_cast (See https://fb.me/eqwalizer_errors#refined_record_in_type_cast) - ┌─ check/src/type_asserts.erl:173:22 - │ -173 │ ?unchecked_cast(1, #rec{bad_field :: atom()}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ refined records are not allowed in type casts, found: rec - -19 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts-OTP-28.pretty deleted file mode 100644 index c5fb63ed41..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts-OTP-28.pretty +++ /dev/null @@ -1,256 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:39:3 - │ -39 │ Arg. - │ ^^^ Arg. -Expression has type: string() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:48:3 - │ -48 │ Arg. - │ ^^^ - │ │ - │ Arg. -Expression has type: string() | binary() -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 ------------------------------ - - 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 - │ -63 │ andalso list_to_atom(A). - │ ^ A. -Expression has type: binary() -Context expected type: string() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:70:26 - │ -70 │ andalso list_to_atom(A). - │ ^ A. -Expression has type: binary() -Context expected type: string() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:84:3 - │ -84 │ ╭ ╭ is_number(N) -85 │ │ │ andalso is_atom(A) -86 │ │ │ andalso {N, A}. - │ ╰─│──────────────────^ _ andalso _. -Expression has type: 'false' | {number(), atom()} -Context expected type: 'false' | {atom(), number()} - │ ╰──────────────────' - -Because in the expression's type: - The type is a union type with some valid candidates: 'false' - However, the following candidate doesn't match: - { - Here the type is: number() - 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 - │ -92 │ {X, A}. - │ ^^^^^^ - │ │ - │ {X, A}. -Expression has type: {'false' | number(), term()} -Context expected type: {'false' | number(), number()} - │ - -Because in the expression's type: - { 'false' | number(), - Here the type is: term() - 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 - │ -105 │ checked_cast1_neg(A) -> ?checked_cast(A, ok). - │ ^ A. -Expression has type: atom() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:108:25 - │ -108 │ checked_cast2_neg(A) -> ?checked_cast(A, atom()). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ .. :: ... -Expression has type: atom() -Context expected type: 'ok' - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/type_asserts.erl:110:20 - │ -110 │ -type invalid() :: foo:non_exist(). - │ ^^^^^^^^^^^^^^^ Unknown id: foo:non_exist/0 - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ check/src/type_asserts.erl:113:42 - │ -113 │ checked_cast3_neg(A) -> ?checked_cast(A, foo:non_exist()). - │ ^^^^^^^^^^^^^^^ Unknown id: foo:non_exist/0 - -error: invalid_ref_in_type_cast (See https://fb.me/eqwalizer_errors#invalid_ref_in_type_cast) - ┌─ check/src/type_asserts.erl:116:42 - │ -116 │ checked_cast4_neg(A) -> ?checked_cast(A, {ok, invalid()}). - │ ^^^^^^^^^^^^^^^ type cast references type with invalid definition: invalid/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:126:9 - │ -126 │ Acc#{K => V#{ka => va}}; - │ ^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{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'}} -Context expected type: #{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 in the expression's type: - #{ dynamic() => - Here the type is: #{kb := ...} - Context expects 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 - │ -129 │ Acc#{K => V#{kb => vb}}; - │ ^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{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'}} -Context expected type: #{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 in the expression's type: - #{ dynamic() => - Here the type is: #{kb := ...} - Context expects 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 - │ -132 │ Acc#{K => V#{kc => vc}} - │ ^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{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'}} -Context expected type: #{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 in the expression's type: - #{ dynamic() => - Here the type is: #{kb := ...} - Context expects 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 - │ -156 │ unsafe_cast1_neg(A) -> ?unchecked_cast(A, err). - │ ^^^^^^^^^^^^^^^^^^^^^^^ .. :: ... -Expression has type: 'err' -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_asserts.erl:159:40 - │ -159 │ unsafe_cast2_neg(D) -> ?unchecked_cast(a + D, ok). - │ ^ 'a'. -Expression has type: 'a' -Context expected type: number() - -error: variables_in_type_cast (See https://fb.me/eqwalizer_errors#variables_in_type_cast) - ┌─ check/src/type_asserts.erl:163:21 - │ -163 │ ?checked_cast(ok, A). - │ ^ type variables are not allowed in type casts, found: A - -error: variables_in_type_cast (See https://fb.me/eqwalizer_errors#variables_in_type_cast) - ┌─ check/src/type_asserts.erl:167:23 - │ -167 │ ?unchecked_cast(ok, A | B). - │ ^^^^^ type variables are not allowed in type casts, found: A, B - -error: refined_record_in_type_cast (See https://fb.me/eqwalizer_errors#refined_record_in_type_cast) - ┌─ check/src/type_asserts.erl:173:22 - │ -173 │ ?unchecked_cast(1, #rec{bad_field :: atom()}). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ refined records are not allowed in type casts, found: rec - -19 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts.pretty similarity index 61% rename from crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts.pretty index c5fb63ed41..069950f003 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/type_asserts.pretty @@ -22,12 +22,6 @@ 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 │ @@ -63,17 +57,6 @@ 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 │ @@ -91,13 +74,6 @@ 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 │ @@ -150,17 +126,6 @@ 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 │ @@ -179,17 +144,6 @@ 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 │ @@ -208,17 +162,6 @@ 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/type_predicates-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/type_predicates-OTP-27.pretty deleted file mode 100644 index 2725e97755..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/type_predicates-OTP-27.pretty +++ /dev/null @@ -1,25 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_predicates.erl:102:32 - │ -102 │ when is_record(R, rec2) -> R. - │ ^ R. -Expression has type: #rec2{} -Context expected type: #rec1{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_predicates.erl:107:35 - │ -107 │ when is_record(R, rec2, 1) -> R. - │ ^ R. -Expression has type: #rec2{} -Context expected type: #rec1{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_predicates.erl:149:39 - │ -149 │ when is_function(F, 2) -> #f1{f = F}. - │ ^ F. -Expression has type: fun((term(), term()) -> term()) -Context expected type: fun((term()) -> term()) - -3 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/type_predicates-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/type_predicates-OTP-28.pretty deleted file mode 100644 index 2725e97755..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/type_predicates-OTP-28.pretty +++ /dev/null @@ -1,25 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_predicates.erl:102:32 - │ -102 │ when is_record(R, rec2) -> R. - │ ^ R. -Expression has type: #rec2{} -Context expected type: #rec1{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_predicates.erl:107:35 - │ -107 │ when is_record(R, rec2, 1) -> R. - │ ^ R. -Expression has type: #rec2{} -Context expected type: #rec1{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/type_predicates.erl:149:39 - │ -149 │ when is_function(F, 2) -> #f1{f = F}. - │ ^ F. -Expression has type: fun((term(), term()) -> term()) -Context expected type: fun((term()) -> term()) - -3 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/type_predicates-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/type_predicates.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/type_predicates-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/type_predicates.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/united_fun-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/united_fun-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/united_fun-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/united_fun-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/united_fun-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/united_fun-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/united_fun-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/united_fun-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/united_fun-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_try_catch-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/united_fun.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_try_catch-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/united_fun.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/unspecced-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/unspecced-OTP-27.pretty deleted file mode 100644 index b3a6323374..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/unspecced-OTP-27.pretty +++ /dev/null @@ -1,63 +0,0 @@ -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/unspecced.erl:11:1 - │ -11 │ expect_none(None) -> None. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:14:15 - │ -14 │ expect_none({Id}). - │ ^^^^ {Id}. -Expression has type: {dynamic()} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:20:15 - │ -20 │ expect_none(Res). - │ ^^^ Res. -Expression has type: #{dynamic() => {dynamic()}} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:24:15 - │ -24 │ expect_none({Id}). - │ ^^^^ {Id}. -Expression has type: {dynamic()} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:28:15 - │ -28 │ expect_none({Res}). - │ ^^^^^ {Res}. -Expression has type: {#{id := number(), dynamic() => dynamic()}} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:32:15 - │ -32 │ expect_none(Res). - │ ^^^ Res. -Expression has type: {dynamic(), dynamic([term()])} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:36:15 - │ -36 │ expect_none(Res). - │ ^^^ Res. -Expression has type: {dynamic()} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:41:18 - │ -41 │ atom_to_binary(Rec#rec.id). - │ ^^^^^^^^^^ ...#rec.id. -Expression has type: number() -Context expected type: atom() - -8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/unspecced-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/unspecced-OTP-28.pretty deleted file mode 100644 index b3a6323374..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/unspecced-OTP-28.pretty +++ /dev/null @@ -1,63 +0,0 @@ -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ check/src/unspecced.erl:11:1 - │ -11 │ expect_none(None) -> None. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:14:15 - │ -14 │ expect_none({Id}). - │ ^^^^ {Id}. -Expression has type: {dynamic()} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:20:15 - │ -20 │ expect_none(Res). - │ ^^^ Res. -Expression has type: #{dynamic() => {dynamic()}} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:24:15 - │ -24 │ expect_none({Id}). - │ ^^^^ {Id}. -Expression has type: {dynamic()} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:28:15 - │ -28 │ expect_none({Res}). - │ ^^^^^ {Res}. -Expression has type: {#{id := number(), dynamic() => dynamic()}} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:32:15 - │ -32 │ expect_none(Res). - │ ^^^ Res. -Expression has type: {dynamic(), dynamic([term()])} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:36:15 - │ -36 │ expect_none(Res). - │ ^^^ Res. -Expression has type: {dynamic()} -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/unspecced.erl:41:18 - │ -41 │ atom_to_binary(Rec#rec.id). - │ ^^^^^^^^^^ ...#rec.id. -Expression has type: number() -Context expected type: atom() - -8 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/unspecced-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/unspecced.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/unspecced-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/unspecced.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual-OTP-26.pretty deleted file mode 100644 index d03afc8cf8..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual-OTP-26.pretty +++ /dev/null @@ -1,25 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/use_dynamic_gradual.erl:19:3 - │ -19 │ {erlang:atom_to_binary(Dyn)}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ {erlang:atom_to_binary(Dyn)}. -Expression has type: {binary()} -Context expected type: {atom()} - │ - -Because in the expression's type: - { - Here the type is: binary() - 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_gradual-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual-OTP-28.pretty deleted file mode 100644 index d03afc8cf8..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual-OTP-28.pretty +++ /dev/null @@ -1,25 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/use_dynamic_gradual.erl:19:3 - │ -19 │ {erlang:atom_to_binary(Dyn)}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ {erlang:atom_to_binary(Dyn)}. -Expression has type: {binary()} -Context expected type: {atom()} - │ - -Because in the expression's type: - { - Here the type is: binary() - 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_gradual-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual.pretty similarity index 70% rename from crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual.pretty index d03afc8cf8..b0892292bd 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_gradual.pretty @@ -15,11 +15,4 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_strict-OTP-26.pretty deleted file mode 100644 index 12f1d81948..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_strict-OTP-26.pretty +++ /dev/null @@ -1,25 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/use_dynamic_strict.erl:17:3 - │ -17 │ {erlang:atom_to_binary(Dyn)}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ {erlang:atom_to_binary(Dyn)}. -Expression has type: {binary()} -Context expected type: {atom()} - │ - -Because in the expression's type: - { - Here the type is: binary() - 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-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_strict-OTP-28.pretty deleted file mode 100644 index 12f1d81948..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_strict-OTP-28.pretty +++ /dev/null @@ -1,25 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ check/src/use_dynamic_strict.erl:17:3 - │ -17 │ {erlang:atom_to_binary(Dyn)}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ {erlang:atom_to_binary(Dyn)}. -Expression has type: {binary()} -Context expected type: {atom()} - │ - -Because in the expression's type: - { - Here the type is: binary() - 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-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_strict.pretty similarity index 70% rename from crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_strict-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_strict.pretty index 12f1d81948..034dbd779d 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_strict-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/use_dynamic_strict.pretty @@ -15,11 +15,4 @@ 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/vars1-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/vars1-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/vars1-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/vars1-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/vars1-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/vars1-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/vars1-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/vars1-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/vars1-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_try_catch-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/vars1.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_try_catch-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/vars1.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/vars2-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/vars2-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/vars2-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/vars2-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/vars2-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/vars2-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/vars2-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/vars2-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/vars2-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_try_catch-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/vars2.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/dynamic_try_catch-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/vars2.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/attributes-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/attributes-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/attributes-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/attributes-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/attributes-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/attributes-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/attributes-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/attributes-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/attributes-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/fancy_generics-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/attributes.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/fancy_generics-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/debug/attributes.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/debug_header-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/debug_header-OTP-27.pretty deleted file mode 100644 index 558b077666..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/debug_header-OTP-27.pretty +++ /dev/null @@ -1,7 +0,0 @@ -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/debug_header.erl:14:1 - │ -14 │ -type t() :: has_unbound(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ t/0 references type with invalid definition: has_unbound/0 - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/debug_header-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/debug_header-OTP-28.pretty deleted file mode 100644 index 558b077666..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/debug_header-OTP-28.pretty +++ /dev/null @@ -1,7 +0,0 @@ -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/debug_header.erl:14:1 - │ -14 │ -type t() :: has_unbound(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^ t/0 references type with invalid definition: has_unbound/0 - -1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/debug_header-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/debug_header.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/debug/debug_header-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/debug/debug_header.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/expand-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/expand-OTP-27.pretty deleted file mode 100644 index 7082351ffd..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/expand-OTP-27.pretty +++ /dev/null @@ -1,98 +0,0 @@ -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ debug/src/expand.erl:27:8 - │ -27 │ -> types1:bin_tree_typo(). - │ ^^^^^^^^^^^^^^^^^^^^^^ Unknown id: types1:bin_tree_typo/0 - -error: recursive_constraint (See https://fb.me/eqwalizer_errors#recursive_constraint) - ┌─ debug/src/expand.erl:35:27 - │ -35 │ Rec when Rec :: {rec, Rec}. - │ ^^^ Recursive constraint: Rec - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ debug/src/expand.erl:42:1 - │ -42 │ -type w_unbound_var() :: {_A, _B}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _A: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/expand.erl:43:1 - │ -43 │ ╭ -type trans_unbound_var() -44 │ │ :: w_unbound_var(). - │ ╰────────────────────^ trans_unbound_var/0 references type with invalid definition: w_unbound_var/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/expand.erl:46:1 - │ -46 │ ╭ -spec uses_ty_w_unbound_var(_A, _B) -> -47 │ │ w_unbound_var(). - │ ╰─────────────────^ uses_ty_w_unbound_var/2 references type with invalid definition: w_unbound_var/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/expand.erl:50:1 - │ -50 │ ╭ -spec uses_trans_unbound_var(_A, _B) -> -51 │ │ trans_unbound_var(). - │ ╰─────────────────────^ uses_trans_unbound_var/2 references type with invalid definition: trans_unbound_var/0 - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ debug/src/expand.erl:54:1 - │ -54 │ ╭ -type w_unbound_var2() -55 │ │ :: _A. - │ ╰─────────^ _A: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/expand.erl:57:1 - │ -57 │ ╭ -spec uses_ty_w_unbound_var2() -> -58 │ │ w_unbound_var2(). - │ ╰──────────────────^ uses_ty_w_unbound_var2/0 references type with invalid definition: w_unbound_var2/0 - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ debug/src/expand.erl:62:12 - │ -62 │ ref :: undefined_mod:ref() - │ ^^^^^^^^^^^^^^^^^^^ Unknown id: undefined_mod:ref/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/expand.erl:64:1 - │ -64 │ -type bad_ref() :: #bad_ref{}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad_ref/0 references type with invalid definition: #bad_ref{} - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ debug/src/expand.erl:66:1 - │ -66 │ -opaque bad_opaque() :: bad_opaque(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type bad_opaque/0 is not productive - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ debug/src/expand.erl:68:25 - │ -68 │ -record(bad_rec, {id :: unknown:id()}). - │ ^^^^^^^^^^^^ Unknown id: unknown:id/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/expand.erl:69:1 - │ -69 │ -spec mk_bad_rec() -> #bad_rec{}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mk_bad_rec/0 references type with invalid definition: #bad_rec{} - -error: unbound_record (See https://fb.me/eqwalizer_errors#unbound_record) - ┌─ debug/src/expand.erl:70:17 - │ -70 │ mk_bad_rec() -> #bad_rec{}. - │ ^^^^^^^^^^ Unbound rec: bad_rec - -error: ty_var_with_multiple_constraints (See https://fb.me/eqwalizer_errors#ty_var_with_multiple_constraints) - ┌─ debug/src/expand.erl:72:23 - │ -72 │ -spec double_constrain(Thing) -> Thing - │ ╭───────────────────────^ -73 │ │ when Thing :: pid(), Thing :: atom(). - │ ╰────────────────────────────────────^ Type variable 'Thing' is constrained multiple times, please remove the extra constraints - -15 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/expand-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/expand-OTP-28.pretty deleted file mode 100644 index 7082351ffd..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/expand-OTP-28.pretty +++ /dev/null @@ -1,98 +0,0 @@ -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ debug/src/expand.erl:27:8 - │ -27 │ -> types1:bin_tree_typo(). - │ ^^^^^^^^^^^^^^^^^^^^^^ Unknown id: types1:bin_tree_typo/0 - -error: recursive_constraint (See https://fb.me/eqwalizer_errors#recursive_constraint) - ┌─ debug/src/expand.erl:35:27 - │ -35 │ Rec when Rec :: {rec, Rec}. - │ ^^^ Recursive constraint: Rec - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ debug/src/expand.erl:42:1 - │ -42 │ -type w_unbound_var() :: {_A, _B}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _A: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/expand.erl:43:1 - │ -43 │ ╭ -type trans_unbound_var() -44 │ │ :: w_unbound_var(). - │ ╰────────────────────^ trans_unbound_var/0 references type with invalid definition: w_unbound_var/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/expand.erl:46:1 - │ -46 │ ╭ -spec uses_ty_w_unbound_var(_A, _B) -> -47 │ │ w_unbound_var(). - │ ╰─────────────────^ uses_ty_w_unbound_var/2 references type with invalid definition: w_unbound_var/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/expand.erl:50:1 - │ -50 │ ╭ -spec uses_trans_unbound_var(_A, _B) -> -51 │ │ trans_unbound_var(). - │ ╰─────────────────────^ uses_trans_unbound_var/2 references type with invalid definition: trans_unbound_var/0 - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ debug/src/expand.erl:54:1 - │ -54 │ ╭ -type w_unbound_var2() -55 │ │ :: _A. - │ ╰─────────^ _A: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/expand.erl:57:1 - │ -57 │ ╭ -spec uses_ty_w_unbound_var2() -> -58 │ │ w_unbound_var2(). - │ ╰──────────────────^ uses_ty_w_unbound_var2/0 references type with invalid definition: w_unbound_var2/0 - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ debug/src/expand.erl:62:12 - │ -62 │ ref :: undefined_mod:ref() - │ ^^^^^^^^^^^^^^^^^^^ Unknown id: undefined_mod:ref/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/expand.erl:64:1 - │ -64 │ -type bad_ref() :: #bad_ref{}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad_ref/0 references type with invalid definition: #bad_ref{} - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ debug/src/expand.erl:66:1 - │ -66 │ -opaque bad_opaque() :: bad_opaque(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type bad_opaque/0 is not productive - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ debug/src/expand.erl:68:25 - │ -68 │ -record(bad_rec, {id :: unknown:id()}). - │ ^^^^^^^^^^^^ Unknown id: unknown:id/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/expand.erl:69:1 - │ -69 │ -spec mk_bad_rec() -> #bad_rec{}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mk_bad_rec/0 references type with invalid definition: #bad_rec{} - -error: unbound_record (See https://fb.me/eqwalizer_errors#unbound_record) - ┌─ debug/src/expand.erl:70:17 - │ -70 │ mk_bad_rec() -> #bad_rec{}. - │ ^^^^^^^^^^ Unbound rec: bad_rec - -error: ty_var_with_multiple_constraints (See https://fb.me/eqwalizer_errors#ty_var_with_multiple_constraints) - ┌─ debug/src/expand.erl:72:23 - │ -72 │ -spec double_constrain(Thing) -> Thing - │ ╭───────────────────────^ -73 │ │ when Thing :: pid(), Thing :: atom(). - │ ╰────────────────────────────────────^ Type variable 'Thing' is constrained multiple times, please remove the extra constraints - -15 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/expand-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/expand.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/debug/expand-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/debug/expand.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/expr1-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/expr1-OTP-27.pretty deleted file mode 100644 index 85e1a2782c..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/expr1-OTP-27.pretty +++ /dev/null @@ -1,17 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ debug/src/expr1.erl:83:8 - │ -83 │ << X || X <- [1, 2, 3] >>. - │ ^ X. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ debug/src/expr1.erl:86:8 - │ -86 │ << X || <> <= <<1, 2, 3>> >>. - │ ^ X. -Expression has type: number() -Context expected type: binary() - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/expr1-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/expr1-OTP-28.pretty deleted file mode 100644 index 85e1a2782c..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/expr1-OTP-28.pretty +++ /dev/null @@ -1,17 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ debug/src/expr1.erl:83:8 - │ -83 │ << X || X <- [1, 2, 3] >>. - │ ^ X. -Expression has type: number() -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ debug/src/expr1.erl:86:8 - │ -86 │ << X || <> <= <<1, 2, 3>> >>. - │ ^ X. -Expression has type: number() -Context expected type: binary() - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/expr1-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/expr1.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/debug/expr1-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/debug/expr1.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/expr2-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/expr2-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/expr2-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/expr2-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/expr2-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/expr2-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/expr2-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/expr2-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/expr2-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/fancy_generics-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/expr2.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/fancy_generics-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/debug/expr2.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/records_wip-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/records_wip-OTP-27.pretty deleted file mode 100644 index 6ce3d4eb83..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/records_wip-OTP-27.pretty +++ /dev/null @@ -1,46 +0,0 @@ -error: type_var_in_record_field (See https://fb.me/eqwalizer_errors#type_var_in_record_field) - ┌─ debug/src/records_wip.erl:60:14 - │ -60 │ field :: _TyVar - │ ^^^^^^ _TyVar: Type variables are meaningless in record fields. Did you mean to use an alias? - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/records_wip.erl:62:1 - │ -62 │ -type ty_var_in_field() :: #ty_var_in_field{}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ty_var_in_field/0 references type with invalid definition: #ty_var_in_field{} - -error: type_var_in_record_field (See https://fb.me/eqwalizer_errors#type_var_in_record_field) - ┌─ debug/src/records_wip.erl:66:9 - │ -66 │ _TyVar - │ ^^^^^^ _TyVar: Type variables are meaningless in record fields. Did you mean to use an alias? - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/records_wip.erl:68:1 - │ -68 │ -type ty_var_in_field2() :: #ty_var_in_field2{}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ty_var_in_field2/0 references type with invalid definition: #ty_var_in_field2{} - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ debug/src/records_wip.erl:70:1 - │ -70 │ -type var_from_nowhere() :: _T. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _T: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/records_wip.erl:72:1 - │ -72 │ ╭ -record(ty_var_in_field3, { -73 │ │ field :: -74 │ │ var_from_nowhere() -75 │ │ }). - │ ╰──^ ty_var_in_field3 references type with invalid definition: var_from_nowhere/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/records_wip.erl:76:1 - │ -76 │ -type ty_var_in_field3() :: #ty_var_in_field3{}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ty_var_in_field3/0 references type with invalid definition: #ty_var_in_field3{} - -7 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/records_wip-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/records_wip-OTP-28.pretty deleted file mode 100644 index 6ce3d4eb83..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/records_wip-OTP-28.pretty +++ /dev/null @@ -1,46 +0,0 @@ -error: type_var_in_record_field (See https://fb.me/eqwalizer_errors#type_var_in_record_field) - ┌─ debug/src/records_wip.erl:60:14 - │ -60 │ field :: _TyVar - │ ^^^^^^ _TyVar: Type variables are meaningless in record fields. Did you mean to use an alias? - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/records_wip.erl:62:1 - │ -62 │ -type ty_var_in_field() :: #ty_var_in_field{}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ty_var_in_field/0 references type with invalid definition: #ty_var_in_field{} - -error: type_var_in_record_field (See https://fb.me/eqwalizer_errors#type_var_in_record_field) - ┌─ debug/src/records_wip.erl:66:9 - │ -66 │ _TyVar - │ ^^^^^^ _TyVar: Type variables are meaningless in record fields. Did you mean to use an alias? - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/records_wip.erl:68:1 - │ -68 │ -type ty_var_in_field2() :: #ty_var_in_field2{}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ty_var_in_field2/0 references type with invalid definition: #ty_var_in_field2{} - -error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var) - ┌─ debug/src/records_wip.erl:70:1 - │ -70 │ -type var_from_nowhere() :: _T. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _T: Type variable is unbound. - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/records_wip.erl:72:1 - │ -72 │ ╭ -record(ty_var_in_field3, { -73 │ │ field :: -74 │ │ var_from_nowhere() -75 │ │ }). - │ ╰──^ ty_var_in_field3 references type with invalid definition: var_from_nowhere/0 - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ debug/src/records_wip.erl:76:1 - │ -76 │ -type ty_var_in_field3() :: #ty_var_in_field3{}. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ty_var_in_field3/0 references type with invalid definition: #ty_var_in_field3{} - -7 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/records_wip-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/records_wip.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/debug/records_wip-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/debug/records_wip.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/types1-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/types1-OTP-27.pretty deleted file mode 100644 index d20e8068bd..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/types1-OTP-27.pretty +++ /dev/null @@ -1,15 +0,0 @@ -error: bad_map_key (See https://fb.me/eqwalizer_errors#bad_map_key) - ┌─ debug/src/types1.erl:311:5 - │ -311 │ integer() => integer() - │ ^^^^^^^^^^^^^^^^^^^^ Map type will be approximated to #{dynamic() => dynamic()}, suppressing potential errors. -Only one default association per map is allowed, all other keys should be composed of statically defined atoms or tuples. - -error: bad_map_key (See https://fb.me/eqwalizer_errors#bad_map_key) - ┌─ debug/src/types1.erl:315:5 - │ -315 │ atom() := atom(), - │ ^^^^^^^^^^^^^^ Map type will be approximated to #{dynamic() => dynamic()}, suppressing potential errors. -Use => instead of := here. Required map key should always be composed of statically defined atoms or tuples. - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/types1-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/types1-OTP-28.pretty deleted file mode 100644 index d20e8068bd..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/types1-OTP-28.pretty +++ /dev/null @@ -1,15 +0,0 @@ -error: bad_map_key (See https://fb.me/eqwalizer_errors#bad_map_key) - ┌─ debug/src/types1.erl:311:5 - │ -311 │ integer() => integer() - │ ^^^^^^^^^^^^^^^^^^^^ Map type will be approximated to #{dynamic() => dynamic()}, suppressing potential errors. -Only one default association per map is allowed, all other keys should be composed of statically defined atoms or tuples. - -error: bad_map_key (See https://fb.me/eqwalizer_errors#bad_map_key) - ┌─ debug/src/types1.erl:315:5 - │ -315 │ atom() := atom(), - │ ^^^^^^^^^^^^^^ Map type will be approximated to #{dynamic() => dynamic()}, suppressing potential errors. -Use => instead of := here. Required map key should always be composed of statically defined atoms or tuples. - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/types1-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/types1.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/debug/types1-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/debug/types1.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/types2-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/types2-OTP-27.pretty deleted file mode 100644 index 1bab90f3a6..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/types2-OTP-27.pretty +++ /dev/null @@ -1,19 +0,0 @@ -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ debug/src/types2.erl:18:5 - │ -18 │ forms1:my_number(). - │ ^^^^^^^^^^^^^^^^^^ Unknown id: forms1:my_number/0 - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ debug/src/types2.erl:21:5 - │ -21 │ unknown:my_number(). - │ ^^^^^^^^^^^^^^^^^^^ Unknown id: unknown:my_number/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ debug/src/types2.erl:30:1 - │ -30 │ -type recur_invalid(X) :: o( - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type recur_invalid/1 is not productive - -3 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/types2-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/types2-OTP-28.pretty deleted file mode 100644 index 1bab90f3a6..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/types2-OTP-28.pretty +++ /dev/null @@ -1,19 +0,0 @@ -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ debug/src/types2.erl:18:5 - │ -18 │ forms1:my_number(). - │ ^^^^^^^^^^^^^^^^^^ Unknown id: forms1:my_number/0 - -error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id) - ┌─ debug/src/types2.erl:21:5 - │ -21 │ unknown:my_number(). - │ ^^^^^^^^^^^^^^^^^^^ Unknown id: unknown:my_number/0 - -error: type_alias_is_non_productive (See https://fb.me/eqwalizer_errors#type_alias_is_non_productive) - ┌─ debug/src/types2.erl:30:1 - │ -30 │ -type recur_invalid(X) :: o( - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type recur_invalid/1 is not productive - -3 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/types2-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/types2.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/debug/types2-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/debug/types2.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/wip_maps-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/wip_maps-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/wip_maps-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/wip_maps-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/wip_maps-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/wip_maps-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/debug/wip_maps-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/wip_maps-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/debug/wip_maps-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/fancy_generics-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/debug/wip_maps.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/fancy_generics-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/debug/wip_maps.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/basics-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/basics-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/basics-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/basics-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/basics-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/basics-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/basics-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/basics-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/basics-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_regression_01-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/basics.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/gradual_regression_01-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/elm_core/basics.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/list-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/list-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/list-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/list-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/list-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/list-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/list-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/list-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/list-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_regression_01-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/list.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/gradual_regression_01-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/elm_core/list.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/gradual_regression_01-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/gradual_regression_01-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/elm_core/map.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map_ffi-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map_ffi-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map_ffi-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map_ffi-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map_ffi-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map_ffi-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map_ffi-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map_ffi-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map_ffi-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/kp_01-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/map_ffi.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/kp_01-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/elm_core/map_ffi.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/maybe-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/maybe-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/maybe-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/maybe-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/maybe-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/maybe-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/maybe-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/maybe-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/maybe-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/kp_01-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/maybe.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/kp_01-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/elm_core/maybe.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/result-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/result-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/result-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/result-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/result-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/result-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/result-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/result-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/result-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/kp_01-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/result.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/kp_01-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/elm_core/result.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/tuple-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/tuple-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/tuple-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/tuple-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/tuple-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/tuple-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/tuple-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/tuple-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/elm_core/tuple-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/misc_lib-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/elm_core/tuple.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/misc_lib-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/elm_core/tuple.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/deep_tuples-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/deep_tuples-OTP-27.pretty deleted file mode 100644 index 5a3c9743cb..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/deep_tuples-OTP-27.pretty +++ /dev/null @@ -1,33 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/deep_tuples.erl:14:3 - │ -14 │ Tag1. - │ ^^^^ Tag1. -Expression has type: 'ok' -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/deep_tuples.erl:20:3 - │ -20 │ Tag2. - │ ^^^^ Tag2. -Expression has type: 'ok' -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/deep_tuples.erl:26:3 - │ -26 │ Tag1. - │ ^^^^ Tag1. -Expression has type: 'ok' -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/deep_tuples.erl:32:3 - │ -32 │ Tag2. - │ ^^^^ Tag2. -Expression has type: 'ok' -Context expected type: none() - -4 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/deep_tuples-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/deep_tuples-OTP-28.pretty deleted file mode 100644 index 5a3c9743cb..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/deep_tuples-OTP-28.pretty +++ /dev/null @@ -1,33 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/deep_tuples.erl:14:3 - │ -14 │ Tag1. - │ ^^^^ Tag1. -Expression has type: 'ok' -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/deep_tuples.erl:20:3 - │ -20 │ Tag2. - │ ^^^^ Tag2. -Expression has type: 'ok' -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/deep_tuples.erl:26:3 - │ -26 │ Tag1. - │ ^^^^ Tag1. -Expression has type: 'ok' -Context expected type: none() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/deep_tuples.erl:32:3 - │ -32 │ Tag2. - │ ^^^^ Tag2. -Expression has type: 'ok' -Context expected type: none() - -4 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/deep_tuples-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/deep_tuples.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/eqwater/deep_tuples-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/eqwater/deep_tuples.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater-OTP-26.pretty deleted file mode 100644 index 05fbf33987..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater-OTP-26.pretty +++ /dev/null @@ -1,683 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:162:7 - │ -162 │ B - │ ^ - │ │ - │ B. -Expression has type: none() | number() | binary() -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: number() - Differs from the expected type: binary() - ------------------------------- Detailed message ------------------------------ - - none() | 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 - │ -172 │ occ05_3_neg_cl(B) -> B. - │ ^ - │ │ - │ B. -Expression has type: none() | number() | binary() -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: number() - Differs from the expected type: binary() - ------------------------------- Detailed message ------------------------------ - - none() | 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 - │ -183 │ A - │ ^ - │ │ - │ A. -Expression has type: none() | number() | binary() -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: number() - Differs from the expected type: binary() - ------------------------------- Detailed message ------------------------------ - - none() | 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 - │ -228 │ occ08(A) when is_number(A) -> A. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:340:13 - │ -340 │ occ11(A) -> A. - │ ^ - │ │ - │ A. -Expression has type: #ab_rec{} | 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: #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 - │ -356 │ occ13(A, _) -> A. - │ ^ - │ │ - │ A. -Expression has type: #ab_rec{} | 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: #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 - │ -404 │ get_int4_neg({_, I}) -> I. - │ ^ I. -Expression has type: atom() -Context expected type: number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ eqwater/src/eqwater.erl:408:1 - │ -408 │ ╭ get_int5({A, A}) -409 │ │ when is_atom(A) -> A. - │ ╰──────────────────────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ eqwater/src/eqwater.erl:413:1 - │ -413 │ ╭ get_int6({A1, A2}) -414 │ │ when is_atom(A1) and is_atom(A2) -> 1; - │ ╰───────────────────────────────────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:415:21 - │ -415 │ get_int6({_, I}) -> I. - │ ^ - │ │ - │ I. -Expression has type: number() | atom() -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: 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 - │ -419 │ ╭ get_int7_neg({A, A}) -420 │ │ % A is none() -421 │ │ when is_atom(A) -> 0; - │ ╰──────────────────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:422:25 - │ -422 │ get_int7_neg({_, I}) -> I. - │ ^ - │ │ - │ I. -Expression has type: number() | atom() -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: 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 - │ -429 │ get_int8_neg({_, I}) -> I. - │ ^ - │ │ - │ I. -Expression has type: number() | atom() -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: 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 - │ -496 │ A. - │ ^ - │ │ - │ A. -Expression has type: atom() | none() -Context expected type: binary() - │ - -Because in the expression's type: - Here the type is: atom() - Context expects type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:521:22 - │ -521 │ record_occ07_tuple(R). - │ ^ - │ │ - │ R. -Expression has type: #union_field{} -Context expected type: {'union_field', atom()} - │ - -Because in the expression's type: - { 'union_field', - Here the type is: binary() - Context expects type: atom() - } - ------------------------------- Detailed message ------------------------------ - - at tuple index 2: - {'union_field', none() | binary()} is not compatible with {'union_field', atom()} - because - none() | binary() is not compatible with atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:559:50 - │ -559 │ record_occ13_neg(#union_field4{x = A, y = _}) -> A. - │ ^ - │ │ - │ A. -Expression has type: number() | 'ok' -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: '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 - │ -590 │ -> B#b.id; - │ ^ - │ │ - │ B. -Expression has type: none() | #b{} | #c{} -Context expected type: #b{} - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #b{} - However the following candidate: #c{} - Differs from the expected type: #b{} - ------------------------------- Detailed message ------------------------------ - - none() | #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 - │ -631 │ occ23_neg({_, B}, F) -> F(B). - │ ^ - │ │ - │ B. -Expression has type: A | B -Context expected type: B - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: B - 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 - │ -649 │ occ26_neg(T) -> T. - │ ^ - │ │ - │ T. -Expression has type: fun() | {term()} -Context expected type: {term()} - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: {term()} - 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 - │ -660 │ occ28_neg(A) -> A. - │ ^ - │ │ - │ A. -Expression has type: tuple() | 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: 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:681:18 - │ -681 │ {_N, _N1} -> X#one_field.f1 - │ ^ - │ │ - │ X. -Expression has type: #one_field{} | #two_fields1{} -Context expected type: #one_field{} - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #one_field{} - However the following candidate: #two_fields1{} - Differs from the expected type: #one_field{} - ------------------------------- Detailed message ------------------------------ - - #one_field{} | #two_fields1{} is not compatible with #one_field{} - because - #two_fields1{} is not compatible with #one_field{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:839:27 - │ -839 │ multi_param2_neg(_, Y) -> Y. - │ ^ - │ │ - │ Y. -Expression has type: number() | atom() -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: 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 - │ -997 │ occ42_neg({F, S} = {_, _}) -> F. - │ ^ F. -Expression has type: string() | 'undefined' -Context expected type: string() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:1004:31 - │ -1004 │ occ43_neg({F, S} = {_, _}) -> F. - │ ^ F. -Expression has type: string() | 'undefined' -Context expected type: string() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ eqwater/src/eqwater.erl:1090:1 - │ -1090 │ occ53_neg(L, undefined) when is_integer(L) -> 0; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:1091:20 - │ -1091 │ occ53_neg(_, I) -> I. - │ ^ - │ │ - │ I. -Expression has type: number() | 'undefined' -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: '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 - │ -1122 │ A -> [A] - │ ^^^ - │ │ - │ [A]. -Expression has type: [[atom()]] | [atom()] -Context expected type: [atom()] - │ - -Because in the expression's type: - The type is a union type with some valid candidates: [atom()] - However, the following candidate doesn't match: - [ - Here the type is: [atom()] - 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 - │ -1131 │ A2 -> [A2] - │ ^^^^ - │ │ - │ [A2]. -Expression has type: [[atom()]] | [atom()] -Context expected type: [atom()] - │ - -Because in the expression's type: - The type is a union type with some valid candidates: [atom()] - However, the following candidate doesn't match: - [ - Here the type is: [atom()] - 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 - │ -1155 │ X - │ ^ - │ │ - │ X. -Expression has type: binary() | string() -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 ------------------------------ - - 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 - │ -1181 │ Y - │ ^ - │ │ - │ Y. -Expression has type: binary() | atom() -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: 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 - │ -1189 │ occ_guard_binary_2_neg(V) when V =:= <<"ok">>; V =:= ok -> V; - │ ^ - │ │ - │ V. -Expression has type: 'ok' | binary() -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: '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 - │ -1194 │ occ_guard_binary_3_neg(V) -> V. - │ ^ - │ │ - │ V. -Expression has type: binary() | 'ok' -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: 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 - │ -1225 │ _ -> Args - │ ^^^^ - │ │ - │ Args. -Expression has type: {term(), my_list()} | none() | 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: {term(), my_list()} - Differs from the expected type: number() - ------------------------------- Detailed message ------------------------------ - - {term(), my_list()} | none() | 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 - │ -1231 │ _ when is_tuple(T) -> T - │ ^ T. -Expression has type: tuple() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:1257:29 - │ -1257 │ non_linear_neg_1({B, B}) -> B. - │ ^ - │ │ - │ B. -Expression has type: 'a' | 'b' -Context expected type: 'b' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'b' - 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 - │ -1269 │ V. - │ ^ - │ │ - │ V. -Expression has type: 'a' | none() -Context expected type: 'b' - │ - -Because in the expression's type: - Here the type is: 'a' - Context expects type: 'b' - -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. -Expression has type: none() | 'c' -Context expected type: 'a' | 'b' - │ - -Because in the expression's type: - Here the type is: 'c' - Context expects type: 'a' | 'b' - No candidate matches in the expected union. - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:1291:43 - │ -1291 │ negate_number_neg(N) when not (N == 1) -> N; - │ ^ N. -Expression has type: number() -Context expected type: 'ok' - -38 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater-OTP-28.pretty deleted file mode 100644 index 05fbf33987..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater-OTP-28.pretty +++ /dev/null @@ -1,683 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:162:7 - │ -162 │ B - │ ^ - │ │ - │ B. -Expression has type: none() | number() | binary() -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: number() - Differs from the expected type: binary() - ------------------------------- Detailed message ------------------------------ - - none() | 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 - │ -172 │ occ05_3_neg_cl(B) -> B. - │ ^ - │ │ - │ B. -Expression has type: none() | number() | binary() -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: number() - Differs from the expected type: binary() - ------------------------------- Detailed message ------------------------------ - - none() | 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 - │ -183 │ A - │ ^ - │ │ - │ A. -Expression has type: none() | number() | binary() -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: number() - Differs from the expected type: binary() - ------------------------------- Detailed message ------------------------------ - - none() | 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 - │ -228 │ occ08(A) when is_number(A) -> A. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:340:13 - │ -340 │ occ11(A) -> A. - │ ^ - │ │ - │ A. -Expression has type: #ab_rec{} | 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: #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 - │ -356 │ occ13(A, _) -> A. - │ ^ - │ │ - │ A. -Expression has type: #ab_rec{} | 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: #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 - │ -404 │ get_int4_neg({_, I}) -> I. - │ ^ I. -Expression has type: atom() -Context expected type: number() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ eqwater/src/eqwater.erl:408:1 - │ -408 │ ╭ get_int5({A, A}) -409 │ │ when is_atom(A) -> A. - │ ╰──────────────────────^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ eqwater/src/eqwater.erl:413:1 - │ -413 │ ╭ get_int6({A1, A2}) -414 │ │ when is_atom(A1) and is_atom(A2) -> 1; - │ ╰───────────────────────────────────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:415:21 - │ -415 │ get_int6({_, I}) -> I. - │ ^ - │ │ - │ I. -Expression has type: number() | atom() -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: 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 - │ -419 │ ╭ get_int7_neg({A, A}) -420 │ │ % A is none() -421 │ │ when is_atom(A) -> 0; - │ ╰──────────────────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:422:25 - │ -422 │ get_int7_neg({_, I}) -> I. - │ ^ - │ │ - │ I. -Expression has type: number() | atom() -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: 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 - │ -429 │ get_int8_neg({_, I}) -> I. - │ ^ - │ │ - │ I. -Expression has type: number() | atom() -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: 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 - │ -496 │ A. - │ ^ - │ │ - │ A. -Expression has type: atom() | none() -Context expected type: binary() - │ - -Because in the expression's type: - Here the type is: atom() - Context expects type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:521:22 - │ -521 │ record_occ07_tuple(R). - │ ^ - │ │ - │ R. -Expression has type: #union_field{} -Context expected type: {'union_field', atom()} - │ - -Because in the expression's type: - { 'union_field', - Here the type is: binary() - Context expects type: atom() - } - ------------------------------- Detailed message ------------------------------ - - at tuple index 2: - {'union_field', none() | binary()} is not compatible with {'union_field', atom()} - because - none() | binary() is not compatible with atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:559:50 - │ -559 │ record_occ13_neg(#union_field4{x = A, y = _}) -> A. - │ ^ - │ │ - │ A. -Expression has type: number() | 'ok' -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: '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 - │ -590 │ -> B#b.id; - │ ^ - │ │ - │ B. -Expression has type: none() | #b{} | #c{} -Context expected type: #b{} - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #b{} - However the following candidate: #c{} - Differs from the expected type: #b{} - ------------------------------- Detailed message ------------------------------ - - none() | #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 - │ -631 │ occ23_neg({_, B}, F) -> F(B). - │ ^ - │ │ - │ B. -Expression has type: A | B -Context expected type: B - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: B - 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 - │ -649 │ occ26_neg(T) -> T. - │ ^ - │ │ - │ T. -Expression has type: fun() | {term()} -Context expected type: {term()} - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: {term()} - 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 - │ -660 │ occ28_neg(A) -> A. - │ ^ - │ │ - │ A. -Expression has type: tuple() | 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: 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:681:18 - │ -681 │ {_N, _N1} -> X#one_field.f1 - │ ^ - │ │ - │ X. -Expression has type: #one_field{} | #two_fields1{} -Context expected type: #one_field{} - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #one_field{} - However the following candidate: #two_fields1{} - Differs from the expected type: #one_field{} - ------------------------------- Detailed message ------------------------------ - - #one_field{} | #two_fields1{} is not compatible with #one_field{} - because - #two_fields1{} is not compatible with #one_field{} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:839:27 - │ -839 │ multi_param2_neg(_, Y) -> Y. - │ ^ - │ │ - │ Y. -Expression has type: number() | atom() -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: 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 - │ -997 │ occ42_neg({F, S} = {_, _}) -> F. - │ ^ F. -Expression has type: string() | 'undefined' -Context expected type: string() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:1004:31 - │ -1004 │ occ43_neg({F, S} = {_, _}) -> F. - │ ^ F. -Expression has type: string() | 'undefined' -Context expected type: string() - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ eqwater/src/eqwater.erl:1090:1 - │ -1090 │ occ53_neg(L, undefined) when is_integer(L) -> 0; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:1091:20 - │ -1091 │ occ53_neg(_, I) -> I. - │ ^ - │ │ - │ I. -Expression has type: number() | 'undefined' -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: '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 - │ -1122 │ A -> [A] - │ ^^^ - │ │ - │ [A]. -Expression has type: [[atom()]] | [atom()] -Context expected type: [atom()] - │ - -Because in the expression's type: - The type is a union type with some valid candidates: [atom()] - However, the following candidate doesn't match: - [ - Here the type is: [atom()] - 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 - │ -1131 │ A2 -> [A2] - │ ^^^^ - │ │ - │ [A2]. -Expression has type: [[atom()]] | [atom()] -Context expected type: [atom()] - │ - -Because in the expression's type: - The type is a union type with some valid candidates: [atom()] - However, the following candidate doesn't match: - [ - Here the type is: [atom()] - 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 - │ -1155 │ X - │ ^ - │ │ - │ X. -Expression has type: binary() | string() -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 ------------------------------ - - 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 - │ -1181 │ Y - │ ^ - │ │ - │ Y. -Expression has type: binary() | atom() -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: 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 - │ -1189 │ occ_guard_binary_2_neg(V) when V =:= <<"ok">>; V =:= ok -> V; - │ ^ - │ │ - │ V. -Expression has type: 'ok' | binary() -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: '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 - │ -1194 │ occ_guard_binary_3_neg(V) -> V. - │ ^ - │ │ - │ V. -Expression has type: binary() | 'ok' -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: 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 - │ -1225 │ _ -> Args - │ ^^^^ - │ │ - │ Args. -Expression has type: {term(), my_list()} | none() | 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: {term(), my_list()} - Differs from the expected type: number() - ------------------------------- Detailed message ------------------------------ - - {term(), my_list()} | none() | 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 - │ -1231 │ _ when is_tuple(T) -> T - │ ^ T. -Expression has type: tuple() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:1257:29 - │ -1257 │ non_linear_neg_1({B, B}) -> B. - │ ^ - │ │ - │ B. -Expression has type: 'a' | 'b' -Context expected type: 'b' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'b' - 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 - │ -1269 │ V. - │ ^ - │ │ - │ V. -Expression has type: 'a' | none() -Context expected type: 'b' - │ - -Because in the expression's type: - Here the type is: 'a' - Context expects type: 'b' - -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. -Expression has type: none() | 'c' -Context expected type: 'a' | 'b' - │ - -Because in the expression's type: - Here the type is: 'c' - Context expects type: 'a' | 'b' - No candidate matches in the expected union. - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater.erl:1291:43 - │ -1291 │ negate_number_neg(N) when not (N == 1) -> N; - │ ^ N. -Expression has type: number() -Context expected type: 'ok' - -38 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater.pretty similarity index 72% rename from crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater.pretty index 05fbf33987..3c6de10f94 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater.pretty @@ -5,7 +5,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^ │ │ │ B. -Expression has type: none() | number() | binary() +Expression has type: number() | binary() Context expected type: binary() │ @@ -14,12 +14,6 @@ Because in the expression's type: However the following candidate: number() Differs from the expected type: binary() ------------------------------- Detailed message ------------------------------ - - none() | 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 │ @@ -27,7 +21,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^ │ │ │ B. -Expression has type: none() | number() | binary() +Expression has type: number() | binary() Context expected type: binary() │ @@ -36,12 +30,6 @@ Because in the expression's type: However the following candidate: number() Differs from the expected type: binary() ------------------------------- Detailed message ------------------------------ - - none() | 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 │ @@ -49,7 +37,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^ │ │ │ A. -Expression has type: none() | number() | binary() +Expression has type: number() | binary() Context expected type: binary() │ @@ -58,12 +46,6 @@ Because in the expression's type: However the following candidate: number() Differs from the expected type: binary() ------------------------------- Detailed message ------------------------------ - - none() | 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 │ @@ -86,12 +68,6 @@ 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 │ @@ -108,12 +84,6 @@ 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 │ @@ -152,12 +122,6 @@ 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 │ @@ -182,12 +146,6 @@ 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 │ @@ -204,26 +162,13 @@ 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 │ 496 │ A. - │ ^ - │ │ - │ A. -Expression has type: atom() | none() + │ ^ A. +Expression has type: atom() Context expected type: binary() - │ - -Because in the expression's type: - Here the type is: atom() - Context expects type: binary() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:521:22 @@ -242,13 +187,6 @@ Because in the expression's type: Context expects type: atom() } ------------------------------- Detailed message ------------------------------ - - at tuple index 2: - {'union_field', none() | binary()} is not compatible with {'union_field', atom()} - because - none() | binary() is not compatible with atom() - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:559:50 │ @@ -265,12 +203,6 @@ 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 │ @@ -278,7 +210,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^ │ │ │ B. -Expression has type: none() | #b{} | #c{} +Expression has type: #b{} | #c{} Context expected type: #b{} │ @@ -287,12 +219,6 @@ Because in the expression's type: However the following candidate: #c{} Differs from the expected type: #b{} ------------------------------- Detailed message ------------------------------ - - none() | #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 │ @@ -309,12 +235,6 @@ 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 │ @@ -331,12 +251,6 @@ 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 │ @@ -353,34 +267,6 @@ 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:681:18 - │ -681 │ {_N, _N1} -> X#one_field.f1 - │ ^ - │ │ - │ X. -Expression has type: #one_field{} | #two_fields1{} -Context expected type: #one_field{} - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: #one_field{} - However the following candidate: #two_fields1{} - Differs from the expected type: #one_field{} - ------------------------------- Detailed message ------------------------------ - - #one_field{} | #two_fields1{} is not compatible with #one_field{} - because - #two_fields1{} is not compatible with #one_field{} - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:839:27 │ @@ -397,12 +283,6 @@ 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 │ @@ -441,12 +321,6 @@ 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 │ @@ -466,14 +340,6 @@ 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 │ @@ -493,14 +359,6 @@ 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 │ @@ -517,12 +375,6 @@ 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 │ @@ -539,12 +391,6 @@ 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 │ @@ -561,12 +407,6 @@ 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 │ @@ -583,12 +423,6 @@ 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 │ @@ -596,7 +430,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^^^^ │ │ │ Args. -Expression has type: {term(), my_list()} | none() | number() +Expression has type: {term(), my_list()} | number() Context expected type: number() │ @@ -605,12 +439,6 @@ Because in the expression's type: However the following candidate: {term(), my_list()} Differs from the expected type: number() ------------------------------- Detailed message ------------------------------ - - {term(), my_list()} | none() | 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 │ @@ -635,42 +463,21 @@ 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 │ 1269 │ V. - │ ^ - │ │ - │ V. -Expression has type: 'a' | none() + │ ^ V. +Expression has type: 'a' Context expected type: 'b' - │ - -Because in the expression's type: - Here the type is: 'a' - Context expects type: 'b' 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. -Expression has type: none() | 'c' + │ ^ A. +Expression has type: 'c' Context expected type: 'a' | 'b' - │ - -Because in the expression's type: - Here the type is: 'c' - Context expects type: 'a' | 'b' - No candidate matches in the expected union. error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ eqwater/src/eqwater.erl:1291:43 @@ -680,4 +487,12 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: number() Context expected type: 'ok' +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ eqwater/src/eqwater.erl:1309:45 + │ +1309 │ negate_fun_neg(F) when is_function(F, 2) -> F; + │ ^ F. +Expression has type: fun((term(), term()) -> term()) +Context expected type: 'ok' + 38 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_aliases-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_aliases-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_aliases-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_aliases-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_aliases-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_aliases-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_aliases-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_aliases-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_aliases-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/misc_lib-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_aliases.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/misc_lib-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_aliases.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_generics-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_generics-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_generics-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_generics-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_generics-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_generics-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_generics-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_generics-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_generics-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/misc_lib-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_generics.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/misc_lib-OTP-28.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_generics.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists-OTP-26.pretty deleted file mode 100644 index b505f94dee..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists-OTP-26.pretty +++ /dev/null @@ -1,168 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_lists.erl:31:51 - │ -31 │ occ_list_04_neg(L = [H | _]) when is_binary(H) -> L. - │ ^ - │ │ - │ L. -Expression has type: [binary() | atom()] -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: atom() - 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 - │ -48 │ occ_list_07_neg(L) -> L. - │ ^ - │ │ - │ L. -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) - ┌─ eqwater/src/eqwater_lists.erl:54:23 - │ -54 │ occ_list_08_neg(A) -> A. - │ ^ - │ │ - │ A. -Expression has type: none() | 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 ------------------------------ - - none() | 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 - │ -61 │ occ_list_09(A) -> A. - │ ^ - │ │ - │ A. -Expression has type: none() | 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 ------------------------------ - - none() | 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 - │ -69 │ occ_list_10(L) -> L. - │ ^ - │ │ - │ L. -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) - ┌─ eqwater/src/eqwater_lists.erl:76:23 - │ -76 │ occ_list_11_neg(L) -> L. - │ ^ - │ │ - │ L. -Expression has type: [atom()] | [binary()] -Context expected type: [binary()] - │ - -Because in the expression's type: - The type is a union type with some valid candidates: [binary()] - However, the following candidate doesn't match: - [ - Here the type is: atom() - 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 - │ -97 │ occ_list_14_neg(L) -> L. - │ ^ L. -Expression has type: [] -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_lists.erl:130:23 - │ -130 │ occ_list_20_neg(V) -> [ok | [V]]. - │ ^^^^^^^^^^ - │ │ - │ ['ok', V]. -Expression has type: [atom() | binary()] -Context expected type: [atom()] | [binary()] - │ - -Because in the expression's type: - [ - Here the type is a union type with some valid candidates: atom() - However the following candidate: binary() - 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_lists-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists-OTP-28.pretty deleted file mode 100644 index b505f94dee..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists-OTP-28.pretty +++ /dev/null @@ -1,168 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_lists.erl:31:51 - │ -31 │ occ_list_04_neg(L = [H | _]) when is_binary(H) -> L. - │ ^ - │ │ - │ L. -Expression has type: [binary() | atom()] -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: atom() - 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 - │ -48 │ occ_list_07_neg(L) -> L. - │ ^ - │ │ - │ L. -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) - ┌─ eqwater/src/eqwater_lists.erl:54:23 - │ -54 │ occ_list_08_neg(A) -> A. - │ ^ - │ │ - │ A. -Expression has type: none() | 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 ------------------------------ - - none() | 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 - │ -61 │ occ_list_09(A) -> A. - │ ^ - │ │ - │ A. -Expression has type: none() | 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 ------------------------------ - - none() | 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 - │ -69 │ occ_list_10(L) -> L. - │ ^ - │ │ - │ L. -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) - ┌─ eqwater/src/eqwater_lists.erl:76:23 - │ -76 │ occ_list_11_neg(L) -> L. - │ ^ - │ │ - │ L. -Expression has type: [atom()] | [binary()] -Context expected type: [binary()] - │ - -Because in the expression's type: - The type is a union type with some valid candidates: [binary()] - However, the following candidate doesn't match: - [ - Here the type is: atom() - 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 - │ -97 │ occ_list_14_neg(L) -> L. - │ ^ L. -Expression has type: [] -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_lists.erl:130:23 - │ -130 │ occ_list_20_neg(V) -> [ok | [V]]. - │ ^^^^^^^^^^ - │ │ - │ ['ok', V]. -Expression has type: [atom() | binary()] -Context expected type: [atom()] | [binary()] - │ - -Because in the expression's type: - [ - Here the type is a union type with some valid candidates: atom() - However the following candidate: binary() - 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_lists-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists.pretty similarity index 76% rename from crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists.pretty index b505f94dee..bfb8103b16 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_lists.pretty @@ -16,14 +16,6 @@ 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 │ @@ -48,7 +40,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^ │ │ │ A. -Expression has type: none() | atom() | [] +Expression has type: atom() | [] Context expected type: atom() │ @@ -57,12 +49,6 @@ Because in the expression's type: However the following candidate: [] Differs from the expected type: atom() ------------------------------- Detailed message ------------------------------ - - none() | 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 │ @@ -70,7 +56,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^ │ │ │ A. -Expression has type: none() | atom() | [] +Expression has type: atom() | [] Context expected type: atom() │ @@ -79,12 +65,6 @@ Because in the expression's type: However the following candidate: [] Differs from the expected type: atom() ------------------------------- Detailed message ------------------------------ - - none() | 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 │ @@ -121,14 +101,6 @@ 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 │ @@ -155,14 +127,4 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps-OTP-26.pretty deleted file mode 100644 index 0b5e330414..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps-OTP-26.pretty +++ /dev/null @@ -1,87 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_maps.erl:26:53 - │ -26 │ map_occ_04_neg(M = #{a := I}) when is_integer(I) -> M; - │ ^ - │ │ - │ M. -Expression has type: #{a := number(), b => number()} -Context expected type: #{a := number(), b := number()} - │ - -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) - ┌─ eqwater/src/eqwater_maps.erl:27:22 - │ -27 │ map_occ_04_neg(M) -> M#{a => 0}. - │ ^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{a := number(), b => number()} -Context expected type: #{a := number(), b := number()} - │ - -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) - ┌─ eqwater/src/eqwater_maps.erl:36:22 - │ -36 │ map_occ_06_neg(V) -> V. - │ ^ - │ │ - │ V. -Expression has type: #{} | 'ok' -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: #{} - 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 - │ -42 │ map_occ_07_neg(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: none() | #{c := number()} -Context expected type: #{b := number()} - │ - -Because in the expression's type: - Here the type is: #{...} - Context expects type: #{b := ..., ...} - The type of the expression is missing the following required keys: b. - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_maps.erl:55:34 - │ -55 │ map_occ_08_neg(#{a := _} = M) -> M; - │ ^ M. -Expression has type: #{a := dynamic(), dynamic() => dynamic()} -Context expected type: 'err' - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps-OTP-28.pretty deleted file mode 100644 index 0b5e330414..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps-OTP-28.pretty +++ /dev/null @@ -1,87 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_maps.erl:26:53 - │ -26 │ map_occ_04_neg(M = #{a := I}) when is_integer(I) -> M; - │ ^ - │ │ - │ M. -Expression has type: #{a := number(), b => number()} -Context expected type: #{a := number(), b := number()} - │ - -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) - ┌─ eqwater/src/eqwater_maps.erl:27:22 - │ -27 │ map_occ_04_neg(M) -> M#{a => 0}. - │ ^^^^^^^^^^ - │ │ - │ ..#{..}. -Expression has type: #{a := number(), b => number()} -Context expected type: #{a := number(), b := number()} - │ - -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) - ┌─ eqwater/src/eqwater_maps.erl:36:22 - │ -36 │ map_occ_06_neg(V) -> V. - │ ^ - │ │ - │ V. -Expression has type: #{} | 'ok' -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: #{} - 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 - │ -42 │ map_occ_07_neg(M) -> M. - │ ^ - │ │ - │ M. -Expression has type: none() | #{c := number()} -Context expected type: #{b := number()} - │ - -Because in the expression's type: - Here the type is: #{...} - Context expects type: #{b := ..., ...} - The type of the expression is missing the following required keys: b. - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_maps.erl:55:34 - │ -55 │ map_occ_08_neg(#{a := _} = M) -> M; - │ ^ M. -Expression has type: #{a := dynamic(), dynamic() => dynamic()} -Context expected type: 'err' - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps.pretty similarity index 81% rename from crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps.pretty index 0b5e330414..b5f637ead3 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps.pretty @@ -14,10 +14,6 @@ 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 │ @@ -34,10 +30,6 @@ 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 │ @@ -54,12 +46,6 @@ 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 │ @@ -67,7 +53,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types │ ^ │ │ │ M. -Expression has type: none() | #{c := number()} +Expression has type: #{c := number()} Context expected type: #{b := number()} │ @@ -84,4 +70,20 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: #{a := dynamic(), dynamic() => dynamic()} Context expected type: 'err' -5 ERRORS +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 diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records-OTP-26.pretty deleted file mode 100644 index 5a01001d2e..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records-OTP-26.pretty +++ /dev/null @@ -1,136 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_records.erl:35:16 - │ -35 │ id3_neg(Id) -> Id. - │ ^^ - │ │ - │ Id. -Expression has type: user() -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: #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 - │ -40 │ id4_neg(Id) -> Id. - │ ^^ - │ │ - │ Id. -Expression has type: user() -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: #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 - │ -47 │ Id -> Id - │ ^^ - │ │ - │ Id. -Expression has type: user() -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: #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 - │ -104 │ ╭ normalize_neg1({R = #rec2{}, R}) -> -105 │ │ {R, R}; - │ ╰────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_records.erl:106:25 - │ -106 │ normalize_neg1(Pair) -> Pair. - │ ^^^^ - │ │ - │ Pair. -Expression has type: {#rec1{}, #rec2{}} | {#rec2{}, #rec1{}} -Context expected type: {#rec1{}, #rec2{}} - │ - -Because in the expression's type: - The type is a union type with some valid candidates: {#rec1{}, #rec2{}} - However, the following candidate doesn't match: - { - Here the type is: #rec2{} - 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 - │ -115 │ normalize_neg2(Pair) -> Pair. - │ ^^^^ - │ │ - │ Pair. -Expression has type: {#rec1{}, #rec2{}} | {#rec2{}, #rec1{}} -Context expected type: {#rec1{}, #rec2{}} - │ - -Because in the expression's type: - The type is a union type with some valid candidates: {#rec1{}, #rec2{}} - However, the following candidate doesn't match: - { - Here the type is: #rec2{} - 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_records-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records-OTP-28.pretty deleted file mode 100644 index 5a01001d2e..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records-OTP-28.pretty +++ /dev/null @@ -1,136 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_records.erl:35:16 - │ -35 │ id3_neg(Id) -> Id. - │ ^^ - │ │ - │ Id. -Expression has type: user() -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: #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 - │ -40 │ id4_neg(Id) -> Id. - │ ^^ - │ │ - │ Id. -Expression has type: user() -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: #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 - │ -47 │ Id -> Id - │ ^^ - │ │ - │ Id. -Expression has type: user() -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: #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 - │ -104 │ ╭ normalize_neg1({R = #rec2{}, R}) -> -105 │ │ {R, R}; - │ ╰────────^ Clause is not covered by spec - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_records.erl:106:25 - │ -106 │ normalize_neg1(Pair) -> Pair. - │ ^^^^ - │ │ - │ Pair. -Expression has type: {#rec1{}, #rec2{}} | {#rec2{}, #rec1{}} -Context expected type: {#rec1{}, #rec2{}} - │ - -Because in the expression's type: - The type is a union type with some valid candidates: {#rec1{}, #rec2{}} - However, the following candidate doesn't match: - { - Here the type is: #rec2{} - 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 - │ -115 │ normalize_neg2(Pair) -> Pair. - │ ^^^^ - │ │ - │ Pair. -Expression has type: {#rec1{}, #rec2{}} | {#rec2{}, #rec1{}} -Context expected type: {#rec1{}, #rec2{}} - │ - -Because in the expression's type: - The type is a union type with some valid candidates: {#rec1{}, #rec2{}} - However, the following candidate doesn't match: - { - Here the type is: #rec2{} - 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_records-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records.pretty similarity index 70% rename from crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records.pretty index 5a01001d2e..245813d1e8 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_records.pretty @@ -14,14 +14,6 @@ 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 │ @@ -38,14 +30,6 @@ 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 │ @@ -62,14 +46,6 @@ 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 │ @@ -96,15 +72,6 @@ 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 │ @@ -124,13 +91,4 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound-OTP-26.pretty deleted file mode 100644 index 4ee35cc78d..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound-OTP-26.pretty +++ /dev/null @@ -1,73 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_sound.erl:44:26 - │ -44 │ t02(A) -> atom_to_binary(A). - │ ^ - │ │ - │ A. -Expression has type: ab() -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: 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 - │ -50 │ t03(_, B) -> B. - │ ^ - │ │ - │ B. -Expression has type: ab() -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: 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 - │ -53 │ tuple_trick_neg({X}, _) -> X. - │ ^ X. -Expression has type: term() -Context expected type: U - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_sound.erl:57:6 - │ -57 │ -> X. - │ ^ X. -Expression has type: _T -Context expected type: U - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_sound.erl:60:24 - │ -60 │ union_trick(_, {B}) -> B. - │ ^ B. -Expression has type: term() -Context expected type: B - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound-OTP-28.pretty deleted file mode 100644 index 4ee35cc78d..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound-OTP-28.pretty +++ /dev/null @@ -1,73 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_sound.erl:44:26 - │ -44 │ t02(A) -> atom_to_binary(A). - │ ^ - │ │ - │ A. -Expression has type: ab() -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: 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 - │ -50 │ t03(_, B) -> B. - │ ^ - │ │ - │ B. -Expression has type: ab() -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: 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 - │ -53 │ tuple_trick_neg({X}, _) -> X. - │ ^ X. -Expression has type: term() -Context expected type: U - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_sound.erl:57:6 - │ -57 │ -> X. - │ ^ X. -Expression has type: _T -Context expected type: U - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_sound.erl:60:24 - │ -60 │ union_trick(_, {B}) -> B. - │ ^ B. -Expression has type: term() -Context expected type: B - -5 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound.pretty similarity index 79% rename from crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound.pretty index 4ee35cc78d..332e999cda 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_sound.pretty @@ -14,14 +14,6 @@ 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 │ @@ -38,14 +30,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement-OTP-26.pretty deleted file mode 100644 index 8b70994f10..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement-OTP-26.pretty +++ /dev/null @@ -1,31 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/unlimited_refinement.erl:60:14 - │ -60 │ is_special(X). - │ ^ - │ │ - │ X. -Expression has type: binary() | 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: 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 - │ -94 │ V -> V - │ ^ V. -Expression has type: {'ok7' | 'ok2' | 'ok6' | 'ok1' | 'ok5' | 'ok8' | 'ok4' | 'ok9' | 'ok3', map3() | map5() | map2() | map9() | map1() | map7() | map6() | map8() | map4()} -Context expected type: 'ok' - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement-OTP-28.pretty deleted file mode 100644 index 8b70994f10..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement-OTP-28.pretty +++ /dev/null @@ -1,31 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/unlimited_refinement.erl:60:14 - │ -60 │ is_special(X). - │ ^ - │ │ - │ X. -Expression has type: binary() | 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: 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 - │ -94 │ V -> V - │ ^ V. -Expression has type: {'ok7' | 'ok2' | 'ok6' | 'ok1' | 'ok5' | 'ok8' | 'ok4' | 'ok9' | 'ok3', map3() | map5() | map2() | map9() | map1() | map7() | map6() | map8() | map4()} -Context expected type: 'ok' - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement.pretty similarity index 83% rename from crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement.pretty index 8b70994f10..c0c48c5e3c 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/unlimited_refinement.pretty @@ -14,12 +14,6 @@ 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-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance-OTP-26.pretty deleted file mode 100644 index 7e7da4fad6..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance-OTP-26.pretty +++ /dev/null @@ -1,943 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:23:3 - │ -23 │ true; - │ ^^^^ 'true'. -Expression has type: 'true' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:25:3 - │ -25 │ false. - │ ^^^^^ 'false'. -Expression has type: 'false' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:32:3 - │ -32 │ A. - │ ^ - │ │ - │ A. -Expression has type: 'false' | none() -Context expected type: number() - │ - -Because in the expression's type: - Here the type is: 'false' - Context expects type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:37:3 - │ -37 │ true; - │ ^^^^ 'true'. -Expression has type: 'true' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:39:3 - │ -39 │ A. - │ ^ - │ │ - │ A. -Expression has type: 'false' | none() -Context expected type: number() - │ - -Because in the expression's type: - Here the type is: 'false' - Context expects type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:44:3 - │ -44 │ 1; - │ ^ 1. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:46:3 - │ -46 │ 2; - │ ^ 2. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:48:3 - │ -48 │ 3; - │ ^ 3. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:50:3 - │ -50 │ 4. - │ ^ 4. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:55:3 - │ -55 │ 1; - │ ^ 1. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:57:3 - │ -57 │ 2; - │ ^ 2. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:59:3 - │ -59 │ 3; - │ ^ 3. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:61:3 - │ -61 │ 4; - │ ^ 4. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:63:3 - │ -63 │ 5; - │ ^ 5. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:65:3 - │ -65 │ 6; - │ ^ 6. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:67:3 - │ -67 │ 7; - │ ^ 7. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:69:3 - │ -69 │ 8; - │ ^ 8. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:71:3 - │ -71 │ 9; - │ ^ 9. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:73:3 - │ -73 │ 10. - │ ^^ 10. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:78:3 - │ -78 │ ╭ erlang:atom_to_binary( -79 │ │ b_to_n( -80 │ │ N -81 │ │ ) -82 │ │ ). - │ ╰───^ erlang:atom_to_binary(b_to_n(N)). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:79:5 - │ -79 │ ╭ b_to_n( -80 │ │ N -81 │ │ ) - │ ╰─────^ b_to_n(N). -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:80:7 - │ -80 │ N - │ ^ N. -Expression has type: number() -Context expected type: boolean() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ fault_tolerance/src/fault_tolerance.erl:87:7 - │ -87 │ X = F(), - │ ^ F. -Expected fun type with arity 0 -Got: term() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ fault_tolerance/src/fault_tolerance.erl:88:7 - │ -88 │ Y = F(), - │ ^ F. -Expected fun type with arity 0 -Got: term() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:89:3 - │ -89 │ {X, Y}. - │ ^^^^^^ {X, Y}. -Expression has type: {dynamic(), dynamic()} -Context expected type: number() - -error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) - ┌─ fault_tolerance/src/fault_tolerance.erl:94:17 - │ -94 │ X = lists:map(fun(_X, _Y) -> 1 end, Ns), - │ ^^^^^^^^^^^^^^^^^^^^ fun. -fun with arity 2 used as fun with 1 arguments - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:96:5 - │ -96 │ X + - │ ^ X. -Expression has type: [number()] -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:97:7 - │ -97 │ A, - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:108:5 - │ -108 │ M1, - │ ^^ M1. -Expression has type: #{dynamic() => dynamic()} -Context expected type: [T] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:108:5 - │ -108 │ M1, - │ ^^ M1. -Expression has type: #{dynamic() => dynamic()} -Context expected type: [dynamic()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:109:5 - │ -109 │ M2 - │ ^^ M2. -Expression has type: #{dynamic() => dynamic()} -Context expected type: [T] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:109:5 - │ -109 │ M2 - │ ^^ M2. -Expression has type: #{dynamic() => dynamic()} -Context expected type: [dynamic()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:111:3 - │ -111 │ Res. - │ ^^^ Res. -Expression has type: [dynamic()] -Context expected type: #{dynamic() => dynamic()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:116:8 - │ -116 │ M1 = M#{ - │ ^ M. -Expression has type: term() -Context expected type: #{term() => term()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:118:7 - │ -118 │ V + - │ ^ V. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:119:9 - │ -119 │ V}, - │ ^ V. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:120:3 - │ -120 │ M1. - │ ^^ M1. -Expression has type: #{dynamic() => dynamic()} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:126:8 - │ -126 │ M1 = M#{ - │ ^ M. -Expression has type: term() -Context expected type: #{term() => term()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:128:5 - │ -128 │ V + - │ ^ V. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:129:7 - │ -129 │ V}, - │ ^ V. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:130:3 - │ -130 │ M1. - │ ^^ M1. -Expression has type: #{dynamic() => dynamic()} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:138:7 - │ -138 │ L1, - │ ^^ L1. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:139:7 - │ -139 │ L2 - │ ^^ L2. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:141:3 - │ -141 │ Res. - │ ^^^ Res. -Expression has type: [dynamic()] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:150:7 - │ -150 │ X + - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:151:9 - │ -151 │ Y, - │ ^ Y. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:152:5 - │ -152 │ Z - │ ^ Z. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:159:8 - │ -159 │ [H | - │ ╭────────^ -160 │ │ T], - │ ╰────────^ T. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:161:8 - │ -161 │ [T | - │ ╭────────^ -162 │ │ H] - │ ╰────────^ H. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:164:3 - │ -164 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: [term()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: term() - 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 - │ -169 │ case F() of - │ ^ F. -Expected fun type with arity 0 -Got: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:170:13 - │ -170 │ true -> A + 1; - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:171:14 - │ -171 │ false -> A - 1 - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:178:10 - │ -178 │ F -> A + 1; - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:179:13 - │ -179 │ true -> A - 1 - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:186:5 - │ -186 │ F + 1, - │ ^ F. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:187:6 - │ -187 │ -M - │ ^ M. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:192:3 - │ -192 │ ╭ [X || -193 │ │ X <- #{ -194 │ │ a => b, -195 │ │ c => d + 1 - · │ -198 │ │ {X} -199 │ │ )]. - │ ╰──────^ [ || ]. -Expression has type: [dynamic()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:193:10 - │ -193 │ X <- #{ - │ ╭──────────^ -194 │ │ a => b, -195 │ │ c => d + 1 -196 │ │ }, - │ ╰─────^ #{..}. -Expression has type: #{a := 'b', c := number()} -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:195:12 - │ -195 │ c => d + 1 - │ ^ 'd'. -Expression has type: 'd' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:198:7 - │ -198 │ {X} - │ ^^^ {X}. -Expression has type: {dynamic()} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:204:20 - │ -204 │ atom_to_binary(Y) || - │ ^ Y. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:205:14 - │ -205 │ <> <= L - │ ^ L. -Expression has type: [term()] -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:207:3 - │ -207 │ Res. - │ ^^^ Res. -Expression has type: [binary()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:213:7 - │ -213 │ B - │ ^ B. -Expression has type: binary() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:215:3 - │ -215 │ Res. - │ ^^^ Res. -Expression has type: binary() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:221:13 - │ -221 │ #{id := a + 1}, - │ ^ 'a'. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:223:13 - │ -223 │ #{id := b + 2}, - │ ^ 'b'. -Expression has type: 'b' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:224:3 - │ -224 │ M1 + M2. - │ ^^ M1. -Expression has type: #{id := number(), dynamic() => dynamic()} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:224:3 - │ -224 │ M1 + M2. - │ ^^^^^^^ _ + _. -Expression has type: number() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:224:8 - │ -224 │ M1 + M2. - │ ^^ M2. -Expression has type: #{id := number(), dynamic() => dynamic()} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:229:5 - │ -229 │ A: - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:230:5 - │ -230 │ S - │ ^ S. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:232:3 - │ -232 │ B + 1. - │ ^ B. -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:232:3 - │ -232 │ B + 1. - │ ^^^^^ _ + _. -Expression has type: number() -Context expected type: atom() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ fault_tolerance/src/fault_tolerance.erl:237:11 - │ -237 │ catch F(), - │ ^ F. -Expected fun type with arity 0 -Got: atom() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ fault_tolerance/src/fault_tolerance.erl:243:5 - │ -243 │ A() - │ ^ A. -Expected fun type with arity 0 -Got: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:247:9 - │ -247 │ 1 + a - │ ^ 'a'. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:249:3 - │ -249 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: dynamic() | [] -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: [] - 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 - │ -254 │ A() - │ ^ A. -Expected fun type with arity 0 -Got: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:257:13 - │ -257 │ A + 1 - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:261:15 - │ -261 │ 1 + a - │ ^ 'a'. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:263:3 - │ -263 │ Res. - │ ^^^ Res. -Expression has type: number() | [] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:273:10 - │ -273 │ id = Pid, - │ ^^^ Pid. -Expression has type: pid() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:274:11 - │ -274 │ pid = Id - │ ^^ Id. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:276:3 - │ -276 │ Res. - │ ^^^ Res. -Expression has type: #rec{} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:281:11 - │ -281 │ pid = Id - │ ^^ Id. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:283:3 - │ -283 │ Res#rec.id. - │ ^^^^^^^^^^ ...#rec.id. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:288:9 - │ -288 │ _ = <<>> - │ ^^^^ <<..>>. -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:288:9 - │ -288 │ _ = <<>> - │ ^^^^ <<..>>. -Expression has type: binary() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:290:3 - │ -290 │ Res. - │ ^^^ Res. -Expression has type: #rec{} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:297:7 - │ -297 │ ╭ atom_to_binary( -298 │ │ [N] -299 │ │ ++ a -300 │ │ ); - │ ╰───────^ erlang:atom_to_binary(_ ++ _). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:298:9 - │ -298 │ ╭ [N] -299 │ │ ++ a - │ ╰──────────────^ _ ++ _. -Expression has type: [dynamic()] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:299:14 - │ -299 │ ++ a - │ ^ 'a'. -Expression has type: 'a' -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:302:7 - │ -302 │ ╭ atom_to_binary( -303 │ │ <> -304 │ │ ++ b -305 │ │ ) - │ ╰───────^ erlang:atom_to_binary(_ ++ _). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:303:9 - │ -303 │ <> - │ ^^^^^ <<..>>. -Expression has type: binary() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:303:9 - │ -303 │ ╭ <> -304 │ │ ++ b - │ ╰──────────────^ _ ++ _. -Expression has type: [dynamic()] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:304:14 - │ -304 │ ++ b - │ ^ 'b'. -Expression has type: 'b' -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:313:7 - │ -313 │ ╭ atom_to_binary( -314 │ │ [N] -315 │ │ ); - │ ╰───────^ erlang:atom_to_binary([N]). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:314:9 - │ -314 │ [N] - │ ^^^ [N]. -Expression has type: [dynamic()] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:317:7 - │ -317 │ ╭ atom_to_binary( -318 │ │ <> -319 │ │ ) - │ ╰───────^ erlang:atom_to_binary(<<..>>). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:318:9 - │ -318 │ <> - │ ^^^^^ <<..>>. -Expression has type: binary() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:321:5 - │ -321 │ [] - │ ^^ []. -Expression has type: [] -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:326:3 - │ -326 │ a + b. - │ ^ 'a'. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:326:7 - │ -326 │ a + b. - │ ^ 'b'. -Expression has type: 'b' -Context expected type: number() - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ fault_tolerance/src/fault_tolerance.erl:331:1 - │ -331 │ -spec use_invalid(loop()) -> none(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use_invalid/1 references type with invalid definition: loop/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:348:3 - │ -348 │ error. - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - -error: redundant_fixme (See https://fb.me/eqwalizer_errors#redundant_fixme) - ┌─ fault_tolerance/src/fault_tolerance.erl:352:3 - │ -352 │ % eqwalizer:fixme - │ ^^^^^^^^^^^^^^^^^ redundant fixme - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:364:17 - │ -364 │ map_pair(L, fun make_pair/2). - │ ^^^^^^^^^^^^^^^ Arg 2 of 'make_pair/2'. -Expression has type: term() -Context expected type: number() - -109 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance-OTP-28.pretty deleted file mode 100644 index 7e7da4fad6..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance-OTP-28.pretty +++ /dev/null @@ -1,943 +0,0 @@ -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:23:3 - │ -23 │ true; - │ ^^^^ 'true'. -Expression has type: 'true' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:25:3 - │ -25 │ false. - │ ^^^^^ 'false'. -Expression has type: 'false' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:32:3 - │ -32 │ A. - │ ^ - │ │ - │ A. -Expression has type: 'false' | none() -Context expected type: number() - │ - -Because in the expression's type: - Here the type is: 'false' - Context expects type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:37:3 - │ -37 │ true; - │ ^^^^ 'true'. -Expression has type: 'true' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:39:3 - │ -39 │ A. - │ ^ - │ │ - │ A. -Expression has type: 'false' | none() -Context expected type: number() - │ - -Because in the expression's type: - Here the type is: 'false' - Context expects type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:44:3 - │ -44 │ 1; - │ ^ 1. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:46:3 - │ -46 │ 2; - │ ^ 2. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:48:3 - │ -48 │ 3; - │ ^ 3. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:50:3 - │ -50 │ 4. - │ ^ 4. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:55:3 - │ -55 │ 1; - │ ^ 1. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:57:3 - │ -57 │ 2; - │ ^ 2. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:59:3 - │ -59 │ 3; - │ ^ 3. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:61:3 - │ -61 │ 4; - │ ^ 4. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:63:3 - │ -63 │ 5; - │ ^ 5. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:65:3 - │ -65 │ 6; - │ ^ 6. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:67:3 - │ -67 │ 7; - │ ^ 7. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:69:3 - │ -69 │ 8; - │ ^ 8. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:71:3 - │ -71 │ 9; - │ ^ 9. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:73:3 - │ -73 │ 10. - │ ^^ 10. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:78:3 - │ -78 │ ╭ erlang:atom_to_binary( -79 │ │ b_to_n( -80 │ │ N -81 │ │ ) -82 │ │ ). - │ ╰───^ erlang:atom_to_binary(b_to_n(N)). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:79:5 - │ -79 │ ╭ b_to_n( -80 │ │ N -81 │ │ ) - │ ╰─────^ b_to_n(N). -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:80:7 - │ -80 │ N - │ ^ N. -Expression has type: number() -Context expected type: boolean() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ fault_tolerance/src/fault_tolerance.erl:87:7 - │ -87 │ X = F(), - │ ^ F. -Expected fun type with arity 0 -Got: term() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ fault_tolerance/src/fault_tolerance.erl:88:7 - │ -88 │ Y = F(), - │ ^ F. -Expected fun type with arity 0 -Got: term() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:89:3 - │ -89 │ {X, Y}. - │ ^^^^^^ {X, Y}. -Expression has type: {dynamic(), dynamic()} -Context expected type: number() - -error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) - ┌─ fault_tolerance/src/fault_tolerance.erl:94:17 - │ -94 │ X = lists:map(fun(_X, _Y) -> 1 end, Ns), - │ ^^^^^^^^^^^^^^^^^^^^ fun. -fun with arity 2 used as fun with 1 arguments - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:96:5 - │ -96 │ X + - │ ^ X. -Expression has type: [number()] -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:97:7 - │ -97 │ A, - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:108:5 - │ -108 │ M1, - │ ^^ M1. -Expression has type: #{dynamic() => dynamic()} -Context expected type: [T] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:108:5 - │ -108 │ M1, - │ ^^ M1. -Expression has type: #{dynamic() => dynamic()} -Context expected type: [dynamic()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:109:5 - │ -109 │ M2 - │ ^^ M2. -Expression has type: #{dynamic() => dynamic()} -Context expected type: [T] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:109:5 - │ -109 │ M2 - │ ^^ M2. -Expression has type: #{dynamic() => dynamic()} -Context expected type: [dynamic()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:111:3 - │ -111 │ Res. - │ ^^^ Res. -Expression has type: [dynamic()] -Context expected type: #{dynamic() => dynamic()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:116:8 - │ -116 │ M1 = M#{ - │ ^ M. -Expression has type: term() -Context expected type: #{term() => term()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:118:7 - │ -118 │ V + - │ ^ V. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:119:9 - │ -119 │ V}, - │ ^ V. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:120:3 - │ -120 │ M1. - │ ^^ M1. -Expression has type: #{dynamic() => dynamic()} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:126:8 - │ -126 │ M1 = M#{ - │ ^ M. -Expression has type: term() -Context expected type: #{term() => term()} - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:128:5 - │ -128 │ V + - │ ^ V. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:129:7 - │ -129 │ V}, - │ ^ V. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:130:3 - │ -130 │ M1. - │ ^^ M1. -Expression has type: #{dynamic() => dynamic()} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:138:7 - │ -138 │ L1, - │ ^^ L1. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:139:7 - │ -139 │ L2 - │ ^^ L2. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:141:3 - │ -141 │ Res. - │ ^^^ Res. -Expression has type: [dynamic()] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:150:7 - │ -150 │ X + - │ ^ X. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:151:9 - │ -151 │ Y, - │ ^ Y. -Expression has type: term() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:152:5 - │ -152 │ Z - │ ^ Z. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:159:8 - │ -159 │ [H | - │ ╭────────^ -160 │ │ T], - │ ╰────────^ T. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:161:8 - │ -161 │ [T | - │ ╭────────^ -162 │ │ H] - │ ╰────────^ H. -Expression has type: term() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:164:3 - │ -164 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: [term()] -Context expected type: [atom()] - │ - -Because in the expression's type: - [ - Here the type is: term() - 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 - │ -169 │ case F() of - │ ^ F. -Expected fun type with arity 0 -Got: boolean() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:170:13 - │ -170 │ true -> A + 1; - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:171:14 - │ -171 │ false -> A - 1 - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:178:10 - │ -178 │ F -> A + 1; - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:179:13 - │ -179 │ true -> A - 1 - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:186:5 - │ -186 │ F + 1, - │ ^ F. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:187:6 - │ -187 │ -M - │ ^ M. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:192:3 - │ -192 │ ╭ [X || -193 │ │ X <- #{ -194 │ │ a => b, -195 │ │ c => d + 1 - · │ -198 │ │ {X} -199 │ │ )]. - │ ╰──────^ [ || ]. -Expression has type: [dynamic()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:193:10 - │ -193 │ X <- #{ - │ ╭──────────^ -194 │ │ a => b, -195 │ │ c => d + 1 -196 │ │ }, - │ ╰─────^ #{..}. -Expression has type: #{a := 'b', c := number()} -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:195:12 - │ -195 │ c => d + 1 - │ ^ 'd'. -Expression has type: 'd' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:198:7 - │ -198 │ {X} - │ ^^^ {X}. -Expression has type: {dynamic()} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:204:20 - │ -204 │ atom_to_binary(Y) || - │ ^ Y. -Expression has type: number() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:205:14 - │ -205 │ <> <= L - │ ^ L. -Expression has type: [term()] -Context expected type: binary() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:207:3 - │ -207 │ Res. - │ ^^^ Res. -Expression has type: [binary()] -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:213:7 - │ -213 │ B - │ ^ B. -Expression has type: binary() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:215:3 - │ -215 │ Res. - │ ^^^ Res. -Expression has type: binary() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:221:13 - │ -221 │ #{id := a + 1}, - │ ^ 'a'. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:223:13 - │ -223 │ #{id := b + 2}, - │ ^ 'b'. -Expression has type: 'b' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:224:3 - │ -224 │ M1 + M2. - │ ^^ M1. -Expression has type: #{id := number(), dynamic() => dynamic()} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:224:3 - │ -224 │ M1 + M2. - │ ^^^^^^^ _ + _. -Expression has type: number() -Context expected type: 'ok' - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:224:8 - │ -224 │ M1 + M2. - │ ^^ M2. -Expression has type: #{id := number(), dynamic() => dynamic()} -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:229:5 - │ -229 │ A: - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:230:5 - │ -230 │ S - │ ^ S. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:232:3 - │ -232 │ B + 1. - │ ^ B. -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:232:3 - │ -232 │ B + 1. - │ ^^^^^ _ + _. -Expression has type: number() -Context expected type: atom() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ fault_tolerance/src/fault_tolerance.erl:237:11 - │ -237 │ catch F(), - │ ^ F. -Expected fun type with arity 0 -Got: atom() - -error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type) - ┌─ fault_tolerance/src/fault_tolerance.erl:243:5 - │ -243 │ A() - │ ^ A. -Expected fun type with arity 0 -Got: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:247:9 - │ -247 │ 1 + a - │ ^ 'a'. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:249:3 - │ -249 │ Res. - │ ^^^ - │ │ - │ Res. -Expression has type: dynamic() | [] -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: [] - 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 - │ -254 │ A() - │ ^ A. -Expected fun type with arity 0 -Got: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:257:13 - │ -257 │ A + 1 - │ ^ A. -Expression has type: atom() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:261:15 - │ -261 │ 1 + a - │ ^ 'a'. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:263:3 - │ -263 │ Res. - │ ^^^ Res. -Expression has type: number() | [] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:273:10 - │ -273 │ id = Pid, - │ ^^^ Pid. -Expression has type: pid() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:274:11 - │ -274 │ pid = Id - │ ^^ Id. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:276:3 - │ -276 │ Res. - │ ^^^ Res. -Expression has type: #rec{} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:281:11 - │ -281 │ pid = Id - │ ^^ Id. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:283:3 - │ -283 │ Res#rec.id. - │ ^^^^^^^^^^ ...#rec.id. -Expression has type: number() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:288:9 - │ -288 │ _ = <<>> - │ ^^^^ <<..>>. -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:288:9 - │ -288 │ _ = <<>> - │ ^^^^ <<..>>. -Expression has type: binary() -Context expected type: pid() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:290:3 - │ -290 │ Res. - │ ^^^ Res. -Expression has type: #rec{} -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:297:7 - │ -297 │ ╭ atom_to_binary( -298 │ │ [N] -299 │ │ ++ a -300 │ │ ); - │ ╰───────^ erlang:atom_to_binary(_ ++ _). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:298:9 - │ -298 │ ╭ [N] -299 │ │ ++ a - │ ╰──────────────^ _ ++ _. -Expression has type: [dynamic()] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:299:14 - │ -299 │ ++ a - │ ^ 'a'. -Expression has type: 'a' -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:302:7 - │ -302 │ ╭ atom_to_binary( -303 │ │ <> -304 │ │ ++ b -305 │ │ ) - │ ╰───────^ erlang:atom_to_binary(_ ++ _). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:303:9 - │ -303 │ <> - │ ^^^^^ <<..>>. -Expression has type: binary() -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:303:9 - │ -303 │ ╭ <> -304 │ │ ++ b - │ ╰──────────────^ _ ++ _. -Expression has type: [dynamic()] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:304:14 - │ -304 │ ++ b - │ ^ 'b'. -Expression has type: 'b' -Context expected type: [term()] - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:313:7 - │ -313 │ ╭ atom_to_binary( -314 │ │ [N] -315 │ │ ); - │ ╰───────^ erlang:atom_to_binary([N]). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:314:9 - │ -314 │ [N] - │ ^^^ [N]. -Expression has type: [dynamic()] -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:317:7 - │ -317 │ ╭ atom_to_binary( -318 │ │ <> -319 │ │ ) - │ ╰───────^ erlang:atom_to_binary(<<..>>). -Expression has type: binary() -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:318:9 - │ -318 │ <> - │ ^^^^^ <<..>>. -Expression has type: binary() -Context expected type: atom() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:321:5 - │ -321 │ [] - │ ^^ []. -Expression has type: [] -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:326:3 - │ -326 │ a + b. - │ ^ 'a'. -Expression has type: 'a' -Context expected type: number() - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:326:7 - │ -326 │ a + b. - │ ^ 'b'. -Expression has type: 'b' -Context expected type: number() - -error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type) - ┌─ fault_tolerance/src/fault_tolerance.erl:331:1 - │ -331 │ -spec use_invalid(loop()) -> none(). - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use_invalid/1 references type with invalid definition: loop/0 - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:348:3 - │ -348 │ error. - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - -error: redundant_fixme (See https://fb.me/eqwalizer_errors#redundant_fixme) - ┌─ fault_tolerance/src/fault_tolerance.erl:352:3 - │ -352 │ % eqwalizer:fixme - │ ^^^^^^^^^^^^^^^^^ redundant fixme - -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ fault_tolerance/src/fault_tolerance.erl:364:17 - │ -364 │ map_pair(L, fun make_pair/2). - │ ^^^^^^^^^^^^^^^ Arg 2 of 'make_pair/2'. -Expression has type: term() -Context expected type: number() - -109 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance.pretty similarity index 97% rename from crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance.pretty index 7e7da4fad6..554970c163 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance-OTP-27.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/fault_tolerance/fault_tolerance.pretty @@ -18,16 +18,9 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ fault_tolerance/src/fault_tolerance.erl:32:3 │ 32 │ A. - │ ^ - │ │ - │ A. -Expression has type: 'false' | none() + │ ^ A. +Expression has type: 'false' Context expected type: number() - │ - -Because in the expression's type: - Here the type is: 'false' - Context expects type: number() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ fault_tolerance/src/fault_tolerance.erl:37:3 @@ -41,16 +34,9 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types ┌─ fault_tolerance/src/fault_tolerance.erl:39:3 │ 39 │ A. - │ ^ - │ │ - │ A. -Expression has type: 'false' | none() + │ ^ A. +Expression has type: 'false' Context expected type: number() - │ - -Because in the expression's type: - Here the type is: 'false' - Context expects type: number() error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ fault_tolerance/src/fault_tolerance.erl:44:3 @@ -430,12 +416,6 @@ 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 │ @@ -686,12 +666,6 @@ 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/eqwalizer_tests/options/bad_maps-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/bad_maps-OTP-27.pretty deleted file mode 100644 index 6c7920b6af..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/options/bad_maps-OTP-27.pretty +++ /dev/null @@ -1,15 +0,0 @@ -error: bad_map_key (See https://fb.me/eqwalizer_errors#bad_map_key) - ┌─ options/src/bad_maps.erl:10:24 - │ -10 │ -type bad_map_1() :: #{atom() := integer()}. - │ ^^^^^^^^^^^^^^^^^ Map type will be approximated to #{dynamic() => dynamic()}, suppressing potential errors. -Use => instead of := here. Required map key should always be composed of statically defined atoms or tuples. - -error: bad_map_key (See https://fb.me/eqwalizer_errors#bad_map_key) - ┌─ options/src/bad_maps.erl:14:32 - │ -14 │ -type bad_map_3() :: #{a => b, atom() := integer()}. - │ ^^^^^^^^^^^^^^^^^ Map type will be approximated to #{dynamic() => dynamic()}, suppressing potential errors. -Use => instead of := here. Required map key should always be composed of statically defined atoms or tuples. - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/bad_maps-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/bad_maps-OTP-28.pretty deleted file mode 100644 index 6c7920b6af..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/options/bad_maps-OTP-28.pretty +++ /dev/null @@ -1,15 +0,0 @@ -error: bad_map_key (See https://fb.me/eqwalizer_errors#bad_map_key) - ┌─ options/src/bad_maps.erl:10:24 - │ -10 │ -type bad_map_1() :: #{atom() := integer()}. - │ ^^^^^^^^^^^^^^^^^ Map type will be approximated to #{dynamic() => dynamic()}, suppressing potential errors. -Use => instead of := here. Required map key should always be composed of statically defined atoms or tuples. - -error: bad_map_key (See https://fb.me/eqwalizer_errors#bad_map_key) - ┌─ options/src/bad_maps.erl:14:32 - │ -14 │ -type bad_map_3() :: #{a => b, atom() := integer()}. - │ ^^^^^^^^^^^^^^^^^ Map type will be approximated to #{dynamic() => dynamic()}, suppressing potential errors. -Use => instead of := here. Required map key should always be composed of statically defined atoms or tuples. - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/bad_maps-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/bad_maps.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/options/bad_maps-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/options/bad_maps.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/dynamic_lambdas-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/dynamic_lambdas-OTP-27.pretty deleted file mode 100644 index 01c204c224..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/options/dynamic_lambdas-OTP-27.pretty +++ /dev/null @@ -1,37 +0,0 @@ -error: dynamic_lambda (See https://fb.me/eqwalizer_errors#dynamic_lambda) - ┌─ options/src/dynamic_lambdas.erl:11:11 - │ -11 │ Fun = fun(X) -> X end, - │ ^^^^^^^^^^^^^^^ Lambda without context: parameters are dynamic() - -error: dynamic_lambda (See https://fb.me/eqwalizer_errors#dynamic_lambda) - ┌─ options/src/dynamic_lambdas.erl:16:11 - │ -16 │ Fun = fun(X) -> X end, - │ ^^^^^^^^^^^^^^^ Lambda without context: parameters are dynamic() - -error: dynamic_lambda (See https://fb.me/eqwalizer_errors#dynamic_lambda) - ┌─ options/src/dynamic_lambdas.erl:23:9 - │ -23 │ fun(X) -> X end, - │ ^^^^^^^^^^^^^^^ Lambda without context: parameters are dynamic() - -error: dynamic_lambda (See https://fb.me/eqwalizer_errors#dynamic_lambda) - ┌─ options/src/dynamic_lambdas.erl:24:9 - │ -24 │ fun(#{}=M) -> M#{a => b} end - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Lambda without context: parameters are dynamic() - -error: dynamic_lambda (See https://fb.me/eqwalizer_errors#dynamic_lambda) - ┌─ options/src/dynamic_lambdas.erl:31:14 - │ -31 │ a => fun(X) -> X end, - │ ^^^^^^^^^^^^^^^ Lambda without context: parameters are dynamic() - -error: dynamic_lambda (See https://fb.me/eqwalizer_errors#dynamic_lambda) - ┌─ options/src/dynamic_lambdas.erl:32:14 - │ -32 │ b => fun(#{}=M) -> M#{a => b} end - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Lambda without context: parameters are dynamic() - -6 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/dynamic_lambdas-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/dynamic_lambdas-OTP-28.pretty deleted file mode 100644 index 01c204c224..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/options/dynamic_lambdas-OTP-28.pretty +++ /dev/null @@ -1,37 +0,0 @@ -error: dynamic_lambda (See https://fb.me/eqwalizer_errors#dynamic_lambda) - ┌─ options/src/dynamic_lambdas.erl:11:11 - │ -11 │ Fun = fun(X) -> X end, - │ ^^^^^^^^^^^^^^^ Lambda without context: parameters are dynamic() - -error: dynamic_lambda (See https://fb.me/eqwalizer_errors#dynamic_lambda) - ┌─ options/src/dynamic_lambdas.erl:16:11 - │ -16 │ Fun = fun(X) -> X end, - │ ^^^^^^^^^^^^^^^ Lambda without context: parameters are dynamic() - -error: dynamic_lambda (See https://fb.me/eqwalizer_errors#dynamic_lambda) - ┌─ options/src/dynamic_lambdas.erl:23:9 - │ -23 │ fun(X) -> X end, - │ ^^^^^^^^^^^^^^^ Lambda without context: parameters are dynamic() - -error: dynamic_lambda (See https://fb.me/eqwalizer_errors#dynamic_lambda) - ┌─ options/src/dynamic_lambdas.erl:24:9 - │ -24 │ fun(#{}=M) -> M#{a => b} end - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Lambda without context: parameters are dynamic() - -error: dynamic_lambda (See https://fb.me/eqwalizer_errors#dynamic_lambda) - ┌─ options/src/dynamic_lambdas.erl:31:14 - │ -31 │ a => fun(X) -> X end, - │ ^^^^^^^^^^^^^^^ Lambda without context: parameters are dynamic() - -error: dynamic_lambda (See https://fb.me/eqwalizer_errors#dynamic_lambda) - ┌─ options/src/dynamic_lambdas.erl:32:14 - │ -32 │ b => fun(#{}=M) -> M#{a => b} end - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Lambda without context: parameters are dynamic() - -6 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/dynamic_lambdas-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/dynamic_lambdas.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/options/dynamic_lambdas-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/options/dynamic_lambdas.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/overloaded_specs_dynamic_result-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/overloaded_specs_dynamic_result-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/options/overloaded_specs_dynamic_result-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/overloaded_specs_dynamic_result-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/overloaded_specs_dynamic_result-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/options/overloaded_specs_dynamic_result-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/overloaded_specs_dynamic_result-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/overloaded_specs_dynamic_result-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/options/overloaded_specs_dynamic_result-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested1-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/overloaded_specs_dynamic_result.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested1-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/options/overloaded_specs_dynamic_result.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/redundant_guards-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/redundant_guards-OTP-26.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/options/redundant_guards-OTP-26.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/redundant_guards-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/redundant_guards-OTP-27.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/options/redundant_guards-OTP-27.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/redundant_guards-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/redundant_guards-OTP-28.pretty deleted file mode 100644 index 89dc33db74..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/options/redundant_guards-OTP-28.pretty +++ /dev/null @@ -1 +0,0 @@ -NO ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested1-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/redundant_guards.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/misc_nested1-OTP-27.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/options/redundant_guards.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/uncovered_clauses-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/uncovered_clauses-OTP-27.pretty deleted file mode 100644 index 0304f7976a..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/options/uncovered_clauses-OTP-27.pretty +++ /dev/null @@ -1,43 +0,0 @@ -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:11:1 - │ -11 │ uncovered_1(A) when A == a -> A; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:15:1 - │ -15 │ uncovered_2(_, {a, A}) -> A; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:20:1 - │ -20 │ uncovered_3({ok, A}) -> A; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:28:1 - │ -28 │ uncovered_5({err, _A}) -> ok; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:32:1 - │ -32 │ uncovered_6(#{a := V}) when is_integer(V) -> V; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:46:1 - │ -46 │ uncovered_single(#{a_typo := A}) -> A. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:57:1 - │ -57 │ uncovered_last_3({err, _A}) -> ok. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -7 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/uncovered_clauses-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/uncovered_clauses-OTP-28.pretty deleted file mode 100644 index 0304f7976a..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/options/uncovered_clauses-OTP-28.pretty +++ /dev/null @@ -1,43 +0,0 @@ -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:11:1 - │ -11 │ uncovered_1(A) when A == a -> A; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:15:1 - │ -15 │ uncovered_2(_, {a, A}) -> A; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:20:1 - │ -20 │ uncovered_3({ok, A}) -> A; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:28:1 - │ -28 │ uncovered_5({err, _A}) -> ok; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:32:1 - │ -32 │ uncovered_6(#{a := V}) when is_integer(V) -> V; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:46:1 - │ -46 │ uncovered_single(#{a_typo := A}) -> A. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) - ┌─ options/src/uncovered_clauses.erl:57:1 - │ -57 │ uncovered_last_3({err, _A}) -> ok. - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec - -7 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/options/uncovered_clauses-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/options/uncovered_clauses.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/options/uncovered_clauses-OTP-26.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/options/uncovered_clauses.pretty diff --git a/crates/elp/src/resources/test/glean_help.stdout b/crates/elp/src/resources/test/glean_help.stdout index bdde2ec540..c4e938e143 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] [--prefix ARG] +Usage: [--project PROJECT] [--module MODULE] [--to TO] [--v2] [--pretty] [--multi] Available options: --project Path to directory with project, or to a JSON file (defaults to `.`) @@ -7,5 +7,4 @@ 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 67fa0d9498..1510d5bddb 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] [COMMAND ...] +Usage: [--log-file LOG_FILE] [--erl ERL] [--escript ESCRIPT] [--no-log-buffering] [--no-buck-generated] [--buck-quick-start] [[--color WHEN]] [COMMAND ...] Available options: --log-file @@ -6,24 +6,27 @@ Available options: --escript --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: + version Print version + server Run lsp server + shell Starts an interactive ELP shell eqwalize Eqwalize specified module eqwalize-all Eqwalize all opted-in modules in a project eqwalize-app Eqwalize all opted-in modules in specified application eqwalize-target Eqwalize all opted-in modules in specified buck target 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. - server Run lsp server - generate-completions Generate shell completions + 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 - build-info Generate build info JSON file - version Print version - shell Starts an interactive ELP shell - eqwalize-stats Return statistics about code quality for eqWAlizer explain Explain a diagnostic code + build-info Generate build info JSON file project-info Generate project info file glean Glean indexer + generate-completions Generate shell completions config Dump a JSON config stanza suitable for use in VS Code project.json diff --git a/crates/elp/src/resources/test/hierarchical_config/basic.stdout b/crates/elp/src/resources/test/hierarchical_config/basic.stdout new file mode 100644 index 0000000000..de8cb63308 --- /dev/null +++ b/crates/elp/src/resources/test/hierarchical_config/basic.stdout @@ -0,0 +1,5 @@ +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 8d03db6ee3..bffdd1fe91 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]] [--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] ... +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] ... Available positional items: Rest of args are space separated list of apps to ignore @@ -14,7 +14,6 @@ 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 @@ -38,4 +37,5 @@ 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 08c0321771..c552fa7dfa 100644 --- a/crates/elp/src/resources/test/linter/custom_function_matches.stdout +++ b/crates/elp/src/resources/test/linter/custom_function_matches.stdout @@ -1,5 +1,4 @@ Reporting all diagnostics codes module specified: custom_function_matches -Diagnostics reported in 1 modules: - custom_function_matches: 1 - 13:4-13:25::[Warning] [W0017] Function 'not_excluded:function/0' is undefined. +Diagnostics reported: +app_a/src/custom_function_matches.erl:14:5-14:26::[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 db2b6e3afa..471efc7900 100644 --- a/crates/elp/src/resources/test/linter/elp_lint_ct.stdout +++ b/crates/elp/src/resources/test/linter/elp_lint_ct.stdout @@ -1,3 +1,2 @@ -Diagnostics reported in 1 modules: - app_a_unreachable_test_SUITE: 1 - 7:0-7:1::[Error] [W0008] Unreachable test (b/1) +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 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 022b3b8972..a667df3930 100644 --- a/crates/elp/src/resources/test/linter/elp_lint_edoc.stdout +++ b/crates/elp/src/resources/test/linter/elp_lint_edoc.stdout @@ -1,3 +1,2 @@ -Diagnostics reported in 1 modules: - app_a_edoc: 1 - 4:0-5:0::[Warning] [O0039] tag @docc not recognized. +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 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 b0cc8a1337..47dc6d4a5e 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 in 1 modules: - app_a: 1 - 8:0-8:4::[Error] [P1700] head mismatch 'fooX' vs 'food' +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 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 5adeaace66..0d0d56491d 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,13 +1,12 @@ module specified: app_b -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 +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 --------------------------------------------- Applying fixes in module 'app_b' for - 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 + 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 @@ -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 a5c27f4367..edd7c5cf1c 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 in 1 modules: - app_a: 1 - 8:0-8:4::[Error] [P1700] head mismatch 'fooX' vs 'food' +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 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 8b6d166b16..6daa076a31 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,13 +1,10 @@ -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 + 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 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 50166d0687..90ccbcb5c0 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,9 +1,5 @@ -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 +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 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 071903fae8..eeb41e5adf 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,4 +1,3 @@ module specified: expression_updates_literal -Diagnostics reported in 1 modules: - expression_updates_literal: 1 - 7:6-8:15::[Warning] [L1318] expression updates a literal +Diagnostics reported: +app_a/src/expression_updates_literal.erl:8:7-9:16::[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 6304537096..1d7771b3b9 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,17 +1,12 @@ -Diagnostics reported in 6 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_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. +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 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 4c42e88eec..3e4a25f329 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,11 +1,10 @@ module specified: app_b -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` +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` --------------------------------------------- Applying fix in module 'app_b' for - 4:4-4:34::[Warning] [W0011] module `app_b` belongs to app `app_b`, but reads env for `misc` + 5:5-5:35::[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 fcba7f3aee..2cec0678d2 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,11 +1,10 @@ module specified: spelling -Diagnostics reported in 1 modules: - spelling: 1 - 1:1-1:9::[Error] [W0013] misspelled attribute, saw 'dyalizer' but expected 'dialyzer' +Diagnostics reported: +app_a/src/spelling.erl:2:2-2:10::[Error] [W0013] misspelled attribute, saw 'dyalizer' but expected 'dialyzer' --------------------------------------------- Applying fix in module 'spelling' for - 1:1-1:9::[Error] [W0013] misspelled attribute, saw 'dyalizer' but expected 'dialyzer' + 2:2-2:10::[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 07a81b80e2..1e7e049554 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,9 +1,6 @@ -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 +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 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 e7a35d0262..4b8d3cc466 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,3 +1,2 @@ -Diagnostics reported in 1 modules: - app_b_unused_param: 1 - 4:4-4:5::[Warning] [W0010] this variable is unused +Diagnostics reported: +app_b/src/app_b_unused_param.erl:5:5-5:6::[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 00d4e2355e..5a42009118 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,5 +1,3 @@ -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 +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 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 4fb3478926..5d6b5e78bc 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"} +{"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 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 deleted file mode 100644 index 7389cc926a..0000000000 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_json_output_prefix.stdout +++ /dev/null @@ -1,3 +0,0 @@ -{"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 008b2b5469..7b6a1e705c 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,28 +1,18 @@ -{"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":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.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":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_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_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.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":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_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_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"} +{"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 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 01ac36d828..5bcd503e10 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,38 +1,21 @@ + 7:1-7:5: Mismatched clause name +Diagnostics reported: Reporting all diagnostics codes -Diagnostics reported in 8 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_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. +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 diff --git a/crates/elp/src/resources/test/linter/ssr_ad_hoc.stdout b/crates/elp/src/resources/test/linter/ssr_ad_hoc.stdout new file mode 100644 index 0000000000..7ded0e8d2f --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc.stdout @@ -0,0 +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 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 new file mode 100644 index 0000000000..e673a7be31 --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli.stdout @@ -0,0 +1,5 @@ + 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 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 new file mode 100644 index 0000000000..880b8f3473 --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_dump_config.stdout @@ -0,0 +1,12 @@ + +# 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 new file mode 100644 index 0000000000..78f52012ac --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_expand.stdout @@ -0,0 +1,4 @@ + app_a_ssr: 1 + 11:11-11:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: {4}. + +Matches found in 1 modules 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 new file mode 100644 index 0000000000..f5a1e98710 --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_no_expand.stdout @@ -0,0 +1,4 @@ + app_a_ssr: 1 + 11:11-11:18::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: ?BAR(_@AA). + +Matches found in 1 modules 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 new file mode 100644 index 0000000000..6f49895580 --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_macros_visible_expand.stdout @@ -0,0 +1,5 @@ + 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 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 new file mode 100644 index 0000000000..a71ebede29 --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_multiple.stdout @@ -0,0 +1,5 @@ + 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 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 new file mode 100644 index 0000000000..6938fabb87 --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_parens_invisible.stdout @@ -0,0 +1,4 @@ + app_a_ssr: 1 + 7:10-7:15::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: (((3))). + +Matches found in 1 modules 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 new file mode 100644 index 0000000000..a43317a2cf --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_parens_visible.stdout @@ -0,0 +1,6 @@ + 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 diff --git a/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_parse_error.stdout b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_parse_error.stdout new file mode 100644 index 0000000000..7db783fb72 --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_cli_parse_error.stdout @@ -0,0 +1 @@ +invalid SSR pattern 'ssr: {_@A, = _@B}.': Parse error: Could not lower rule diff --git a/crates/elp/src/resources/test/linter/ssr_ad_hoc_parse_fail.stdout b/crates/elp/src/resources/test/linter/ssr_ad_hoc_parse_fail.stdout new file mode 100644 index 0000000000..4957343496 --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_ad_hoc_parse_fail.stdout @@ -0,0 +1 @@ +errors parsing "{project_path}/elp_lint_ssr_adhoc_parse_fail.toml": invalid SSR pattern 'ssr: {_@A, = 10}.': Parse error: Could not lower rule for key `ad_hoc_lints.lints` at line 3 column 1 diff --git a/crates/elp/src/resources/test/linter/ssr_as_cli_arg.stdout b/crates/elp/src/resources/test/linter/ssr_as_cli_arg.stdout new file mode 100644 index 0000000000..55650830ba --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_as_cli_arg.stdout @@ -0,0 +1,3 @@ +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_context_separator.stdout b/crates/elp/src/resources/test/linter/ssr_context_separator.stdout new file mode 100644 index 0000000000..f791ea85bf --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_context_separator.stdout @@ -0,0 +1,20 @@ + 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 new file mode 100644 index 0000000000..119d62a52b --- /dev/null +++ b/crates/elp/src/resources/test/linter/ssr_context_separator_color.stdout @@ -0,0 +1,18 @@ + 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 8ffe5b1201..01007e94c4 100644 --- a/crates/elp/src/resources/test/linter/warnings_as_errors.stdout +++ b/crates/elp/src/resources/test/linter/warnings_as_errors.stdout @@ -1,38 +1,21 @@ + 7:1-7:5: Mismatched clause name +Diagnostics reported: Reporting all diagnostics codes -Diagnostics reported in 8 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_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. +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 diff --git a/crates/elp/src/resources/test/linter_config/basic.stdout b/crates/elp/src/resources/test/linter_config/basic.stdout new file mode 100644 index 0000000000..946fd7dc9a --- /dev/null +++ b/crates/elp/src/resources/test/linter_config/basic.stdout @@ -0,0 +1,5 @@ +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 1457aed5c5..75cc38354e 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] +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]] Available options: --project Path to directory with project, or to a JSON file (defaults to `.`) @@ -15,4 +15,5 @@ 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/project_info_help.stdout b/crates/elp/src/resources/test/project_info_help.stdout index 637b221d66..2f761a19fa 100644 --- a/crates/elp/src/resources/test/project_info_help.stdout +++ b/crates/elp/src/resources/test/project_info_help.stdout @@ -1,7 +1,8 @@ -Usage: [--project PROJECT] [--to TO] [--buck-query] +Usage: [--project PROJECT] [--to TO] [--buck-query] [--target-types] Available options: --project Path to directory with project, or to a JSON file (defaults to `.`) --to Path to a directory where to dump wa.build_info --buck-query Include the buck uquery results in the output + --target-types Dump a list of targets and their types -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 new file mode 100644 index 0000000000..d51bdf1627 --- /dev/null +++ b/crates/elp/src/resources/test/ssr_help.stdout @@ -0,0 +1,26 @@ +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] ... + +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 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 fc5bc27296..1d868bbbc6 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,10 +44,6 @@ 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 │ @@ -68,17 +64,6 @@ 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 │ @@ -100,17 +85,6 @@ 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 │ @@ -179,12 +153,6 @@ 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 - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -202,12 +170,6 @@ 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 │ @@ -230,6 +192,14 @@ 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 │ @@ -238,4 +208,4 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: [T] Context expected type: T -20 ERRORS +21 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 89db77919f..b311705d68 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------------------------------ 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/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/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,9 +12,10 @@ {"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------------------------------ Detailed message ------------------------------\n\n [term()] is not compatible with [T | X]\n because\n term() is not compatible with T | 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":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_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_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 fc5bc27296..1d868bbbc6 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.pretty @@ -44,10 +44,6 @@ 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 │ @@ -68,17 +64,6 @@ 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 │ @@ -100,17 +85,6 @@ 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 │ @@ -179,12 +153,6 @@ 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 - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -202,12 +170,6 @@ 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 │ @@ -230,6 +192,14 @@ 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 │ @@ -238,4 +208,4 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: [T] Context expected type: T -20 ERRORS +21 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 89db77919f..b311705d68 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------------------------------ 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/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/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,9 +12,10 @@ {"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------------------------------ Detailed message ------------------------------\n\n [term()] is not compatible with [T | X]\n because\n term() is not compatible with T | 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":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_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_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 f56ea404dc..943c4a231d 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------------------------------ 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/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} 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 3cfdbd0dc2..f5f3065414 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_app_a.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_app_a.pretty @@ -44,10 +44,6 @@ 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 │ @@ -68,17 +64,6 @@ 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 │ @@ -100,15 +85,4 @@ 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 6bb5a7421b..8c93bd01fe 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,12 +50,6 @@ 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 - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -73,10 +67,4 @@ 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 5aba82bc71..482195c7ab 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics.pretty @@ -44,10 +44,6 @@ 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 │ @@ -68,17 +64,6 @@ 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 │ @@ -100,17 +85,6 @@ 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 │ @@ -171,12 +145,6 @@ 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 - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -194,12 +162,6 @@ 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 5aba82bc71..482195c7ab 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,10 +44,6 @@ 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 │ @@ -68,17 +64,6 @@ 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 │ @@ -100,17 +85,6 @@ 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 │ @@ -171,12 +145,6 @@ 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 - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -194,12 +162,6 @@ 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 b72b8d1178..043aa00af0 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,10 +44,6 @@ 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 │ @@ -68,17 +64,6 @@ 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 │ @@ -100,17 +85,6 @@ 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 │ @@ -179,12 +153,6 @@ 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 - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -202,12 +170,6 @@ 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 │ @@ -230,4 +192,12 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: 'wrong_ret' Context expected type: 'error' -19 ERRORS +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 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 b72b8d1178..043aa00af0 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,10 +44,6 @@ 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 │ @@ -68,17 +64,6 @@ 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 │ @@ -100,17 +85,6 @@ 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 │ @@ -179,12 +153,6 @@ 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 - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -202,12 +170,6 @@ 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 │ @@ -230,4 +192,12 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: 'wrong_ret' Context expected type: 'error' -19 ERRORS +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 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 5aba82bc71..482195c7ab 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_target_diagnostics.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_target_diagnostics.pretty @@ -44,10 +44,6 @@ 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 │ @@ -68,17 +64,6 @@ 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 │ @@ -100,17 +85,6 @@ 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 │ @@ -171,12 +145,6 @@ 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 - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_a/src/app_a_lists.erl:1305:15 │ @@ -194,12 +162,6 @@ 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 new file mode 100644 index 0000000000..688be17de3 --- /dev/null +++ b/crates/elp/src/resources/test/xref/unavailable_type.stdout @@ -0,0 +1,5 @@ +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 43406fd200..98890640bc 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; +use crossbeam_channel::select_biased; use dispatch::NotificationDispatcher; use elp_eqwalizer::ast::Pos; use elp_eqwalizer::types::Type; @@ -62,6 +62,7 @@ use elp_log::timeit; use elp_log::timeit_exceeds; use elp_project_model::ElpConfig; use elp_project_model::Project; +use elp_project_model::ProjectBuildData; use elp_project_model::ProjectManifest; use elp_project_model::buck::BuckQueryConfig; use elp_project_model::buck::BuckQueryError; @@ -350,7 +351,7 @@ impl Server { projects: Arc::new(vec![]), project_loader: Arc::new(Mutex::new(ProjectLoader::new())), initial_load_status: InitialLoading::Initial, - reload_manager: Arc::new(Mutex::new(ReloadManager::new())), + reload_manager: Arc::new(Mutex::new(ReloadManager::new(config.buck_quick_start()))), dynamic_registrations_done: false, unresolved_app_id_paths: Arc::new(FxHashMap::default()), generated_app_inputs: Arc::new(FxHashMap::default()), @@ -433,27 +434,28 @@ impl Server { } fn next_event(&self) -> Option { - 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())) - } - + // 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())) } + recv(self.connection.receiver) -> msg => { + msg.ok().map(Event::Lsp) + } + + recv(self.task_pool.receiver) -> msg => { + Some(Event::Task(msg.unwrap())) + } + recv (self.project_pool.receiver) -> msg => { Some(Event::Task(msg.unwrap())) } @@ -466,6 +468,16 @@ 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())) + } + + } } @@ -499,9 +511,17 @@ impl Server { Event::Task(task) => match task { Task::Response(response) => self.send_response(response), Task::FetchProject(spinner, projects) => { - self.fetch_project_completed(&spinner, projects)?; + let mut a_file_per_project = extract_dirs_for_buck_projects(&projects); + if !self.fetch_project_completed(&spinner, projects)? { + // We already have changed files, will restart loading. + // So no point heading to generate targets yet + a_file_per_project = FxHashSet::default(); + } spinner.end(); - self.reload_manager.lock().set_reload_done(); + log::info!(target: FILE_WATCH_LOGGER_NAME, "Project reloading complete"); + self.reload_manager + .lock() + .set_reload_done(a_file_per_project); } Task::NativeDiagnostics(diags) => self.native_diagnostics_completed(diags), Task::EqwalizerDiagnostics(spinner, diags_types) => { @@ -550,8 +570,9 @@ impl Server { let to_reload = self.reload_manager.lock().query_changed_files(); if let Some(to_reload) = to_reload { - self.reload_manager.lock().set_reload_active(); - self.reload_project(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); } let (changed, highest_file_id) = self.process_changes_to_vfs_store(); @@ -614,7 +635,16 @@ impl Server { .diagnostics .diagnostics_for(*file_id) .iter() - .map(|d| ide_to_lsp_diagnostic(&line_index, &url, d)) + .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)) + }) + }) .collect(); self.send_notification::( @@ -724,13 +754,12 @@ impl Server { this.ct_diagnostics_requested = true; this.native_diagnostics_requested = true; if let Ok(path) = convert::abs_path(¶ms.text_document.uri) { - this.fetch_projects_if_needed(&path); - let path = VfsPath::from(path); + let vfs_path = VfsPath::from(path.clone()); let already_exists = this .mem_docs .write() .insert( - path.clone(), + vfs_path.clone(), DocumentData::new( params.text_document.version, params.text_document.text.clone().into_bytes(), @@ -738,24 +767,31 @@ impl Server { ) .is_err(); if already_exists { - tracing::error!("duplicate DidOpenTextDocument: {}", path); - log::error!("duplicate DidOpenTextDocument: {path}"); + tracing::error!("duplicate DidOpenTextDocument: {}", &vfs_path); + log::error!("duplicate DidOpenTextDocument: {vfs_path}"); } - let mut vfs = this.vfs.write(); - let bytes = params.text_document.text.into_bytes(); - vfs.set_file_contents(path.clone(), Some(bytes.clone())); + let file_id = { + let mut vfs = this.vfs.write(); + let bytes = params.text_document.text.into_bytes(); + vfs.set_file_contents(vfs_path.clone(), Some(bytes.clone())); - // Until we bring over the full rust-analyzer - // style change processing, make a list of files - // that are freshly opened so diagnostics are - // generated for them, despite no changes being - // registered in vfs. - let (file_id, _) = vfs.file_id(&path).unwrap(); - this.newly_opened_documents.push(ChangedFile { - file_id, - change: Change::Modify(bytes, params.text_document.version as u64), - }); + // Until we bring over the full rust-analyzer + // style change processing, make a list of files + // that are freshly opened so diagnostics are + // generated for them, despite no changes being + // registered in vfs. + let (file_id, _) = vfs.file_id(&vfs_path).unwrap(); + this.newly_opened_documents.push(ChangedFile { + file_id, + change: Change::Modify(bytes, params.text_document.version as u64), + }); + file_id + }; + if this.status != Status::Running || this.analysis_host.raw_database().app_data_id_by_file(file_id).is_none() { + // We do not have a project associated with this file + this.fetch_projects_if_needed(&path); + } } else { log::error!( "DidOpenTextDocument: could not get vfs path for {}", @@ -812,11 +848,20 @@ 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| ide_to_lsp_diagnostic(&line_index, &url, d)) + .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)) + }) + }) .collect() } } @@ -838,19 +883,14 @@ impl Server { if let Ok(path) = convert::abs_path(&change.uri) { // We only put .erl/.hrl files into the // `mem_docs` store, but will get changes for - // other kinds of files. So we neede to do + // other kinds of files. So we need to do // this check. + // Note: we only receive DidSaveTextDocument notifications for files that pass the filter + // in the TextDocumentRegistrationOptions setting at the beginning of main_loop. let opened = convert::vfs_path(&change.uri) .map(|vfs_path| this.mem_docs.read().contains(&vfs_path)) .unwrap_or(false); if opened { - if this.should_reload_config_for_path(&path) { - // e.g. `.elp_lint.toml` - this.refresh_config(); - } - if this.should_reload_project_for_path(&path, &change) { - this.reload_manager.lock().add(path.clone()); - } this.eqwalizer_and_erlang_service_diagnostics_requested = true; if this.config.eqwalizer().all { this.eqwalizer_project_diagnostics_requested = true; @@ -867,22 +907,31 @@ impl Server { Ok(()) })? .on::(|this, params| { + // For some reason, we are seeing duplicate notifications for the same file. + // But we cannot use FxHashSet because change does not implement Hash. let changes: &[FileEvent] = ¶ms.changes; let mut refresh_config = false; + let mut seen: FxHashMap = FxHashMap::default(); for change in changes { + if seen.get(&change.uri).is_some_and(|prev_typ| prev_typ == &change.typ) { + continue; + } + seen.insert(change.uri.clone(), change.typ); if let Ok(path) = convert::abs_path(&change.uri) { let opened = convert::vfs_path(&change.uri) .map(|vfs_path| this.mem_docs.read().contains(&vfs_path)) .unwrap_or(false); log::info!(target: FILE_WATCH_LOGGER_NAME, "DidChangeWatchedFiles:{}:{}", &opened, &path); + // We process config changes here, because we do not register to receive + // DidSaveTextDocument notifiactions for these kinds of files + if this.should_reload_project_for_path(&path, change) { + this.reload_manager.lock().add(path.clone()); + } + if this.should_reload_config_for_path(&path) { + // e.g. `.elp_lint.toml` + refresh_config = true; + } if !opened { - if this.should_reload_project_for_path(&path, change) { - this.reload_manager.lock().add(path.clone()); - } - if this.should_reload_config_for_path(&path) { - // e.g. `.elp_lint.toml` - refresh_config = true; - } this.vfs_loader.handle.invalidate(path); } } @@ -953,9 +1002,14 @@ impl Server { always!(config_version <= self.vfs_config_version); match progress { LoadingProgress::Started => { + let pb_message = if self.status != Status::Running { + "Loading source files" + } else { + "Reloading source files" + }; let pb = self .progress - .begin_bar_with_telemetry("Loading source files".into(), Some(n_total)); + .begin_bar_with_telemetry(pb_message.into(), Some(n_total)); self.transition(Status::Loading(pb)); } LoadingProgress::Progress(n_done) => { @@ -972,7 +1026,8 @@ impl Server { self.show_message(params); } self.transition(Status::Running); - self.telemetry_manager.operational(); + self.telemetry_manager + .operational(self.config.buck_quick_start()); self.initial_load_status = InitialLoading::DoneButVfsChanges; self.schedule_compile_deps(); self.schedule_cache(); @@ -998,8 +1053,10 @@ 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`, if it has changed. + // 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. vfs.set_file_contents(path, contents); } } @@ -1372,9 +1429,11 @@ 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 { @@ -1405,12 +1464,38 @@ 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, }; + let registration_id = "workspace/didChangeWatchedFiles".to_string(); + + // Unregister the old watcher + let unregistrations = vec![lsp_types::Unregistration { + id: registration_id.clone(), + method: notification::DidChangeWatchedFiles::METHOD.to_string(), + }]; + + self.send_request::( + lsp_types::UnregistrationParams { + unregisterations: unregistrations, + }, + |_, _| Ok(()), + ); + + // Register the new watcher let registrations = vec![lsp_types::Registration { - id: "workspace/didChangeWatchedFiles".to_string(), + id: registration_id, method: notification::DidChangeWatchedFiles::METHOD.to_string(), register_options: Some(serde_json::to_value(register_options).unwrap()), }]; @@ -1425,6 +1510,7 @@ impl Server { watch: vec![], version: 0, }; + spinner.report("Starting file loader".to_string()); self.vfs_loader.handle.set_config(vfs_loader_config); self.projects = Arc::new(projects); @@ -1481,12 +1567,18 @@ impl Server { fn update_configuration(&mut self, config: Config) { let _p = tracing::info_span!("Server::update_configuration").entered(); - let _old_config = mem::replace(&mut self.config, Arc::new(config)); + let old_config = mem::replace(&mut self.config, Arc::new(config)); self.logger .reconfigure(LOGGER_NAME, self.config.log_filter()); self.logger.reconfigure("default", self.config.log_filter()); + if old_config.buck_quick_start() != self.config.buck_quick_start() { + self.reload_manager + .lock() + .set_buck_quickstart(self.config.buck_quick_start()); + } + // Read the lint config file let loader = self.project_loader.clone(); let loader = loader.lock(); @@ -1635,14 +1727,15 @@ impl Server { .register(request.id.clone(), (request.method.clone(), received_timer)) } - fn reload_project(&mut self, paths: FxHashSet) { + fn reload_project(&mut self, paths: FxHashSet, query_config: BuckQueryConfig) { if !paths.is_empty() { let loader = self.project_loader.clone(); - let query_config = self.config.buck_query(); let paths = self.resolve_generated_project_paths(paths); - let spinner = self - .progress - .begin_spinner_with_telemetry("ELP reloading project config".to_string()); + let spinner_message = match query_config { + BuckQueryConfig::BuildGeneratedCode => "ELP generating projects".to_string(), + _ => "ELP reloading projects".to_string(), + }; + let spinner = self.progress.begin_spinner_with_telemetry(spinner_message); self.project_pool.handle.spawn_with_sender({ move |sender| { let mut loader = loader.lock(); @@ -1724,12 +1817,9 @@ impl Server { }; spinner.report("Loading project".to_string()); - let mut project = Project::load( - &manifest, - elp_config.eqwalizer.clone(), - query_config, - &|message| spinner.report(message.to_string()), - ); + let mut project = Project::load(&manifest, &elp_config, query_config, &|message| { + spinner.report(message.to_string()) + }); if let Err(err) = &project { log::error!("Failed to load project for manifest {manifest:?}, error: {err:?}"); match err.downcast_ref::() { @@ -1745,10 +1835,9 @@ impl Server { } } if !fallback_used { - project = - Project::load(&fallback, elp_config.eqwalizer, query_config, &|message| { - spinner.report(message.to_string()) - }); + project = Project::load(&fallback, &elp_config, query_config, &|message| { + spinner.report(message.to_string()) + }); if let Err(err) = &project { log::error!( "Failed to load project for fallback manifest {manifest:?}, error: {err:?}" @@ -1759,9 +1848,13 @@ 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: err, + message: error_message, actions: Some(vec![MessageActionItem { title: "Open Buck UI".to_string(), properties: HashMap::from_iter(vec![( @@ -1784,6 +1877,11 @@ impl Server { } fn fetch_projects_if_needed(&mut self, path: &AbsPath) { + // We do not try to load a project for a file that is in the buck-out directory, + // as it will have been generated by buck from a file originating in a different directory. + if path.to_string().contains("/buck-out/") { + return; + } let path = path.to_path_buf(); let loader = self.project_loader.clone(); let query_config = self.config.buck_query(); @@ -1817,12 +1915,18 @@ impl Server { }) } - fn fetch_project_completed(&mut self, spinner: &Spinner, projects: Vec) -> Result<()> { - if self.reload_manager.lock().has_changed_files() { + fn fetch_project_completed( + &mut self, + spinner: &Spinner, + projects: Vec, + ) -> Result { + if !self.reload_manager.lock().ok_to_switch_workspace() { // There are other changed files, abort this reload, to // allow the next one. - return Ok(()); + 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()); if let Err(err) = self.switch_workspaces(spinner, projects) { let params = lsp_types::ShowMessageParams { typ: lsp_types::MessageType::ERROR, @@ -1835,7 +1939,7 @@ impl Server { self.register_dynamic_now_operational(); self.dynamic_registrations_done = true; } - Ok(()) + Ok(true) } fn register_dynamic_now_operational(&mut self) { @@ -1969,7 +2073,7 @@ impl Server { }; for (_, _, file_id) in module_index.iter_own() { - match snapshot.analysis.should_eqwalize(file_id, false) { + match snapshot.analysis.should_eqwalize(file_id) { Ok(true) => { files.push(file_id); } @@ -2075,6 +2179,23 @@ impl Server { } } +/// For each buck project, extract a directory inside it, for possible +/// project reloading to generate targets +fn extract_dirs_for_buck_projects(projects: &[Project]) -> FxHashSet { + let files: FxHashSet = projects + .iter() + .filter_map(|p| { + if let ProjectBuildData::Buck(_) = &p.project_build_data { + // We just need a single path inside the project somewhere + Some(p.project_apps.first()?.dir.clone()) + } else { + None + } + }) + .collect(); + files +} + fn lsp_msg_for_context(message: &lsp_server::Message) -> String { match message { lsp_server::Message::Request(m) => m.method.clone(), diff --git a/crates/elp/src/server/setup.rs b/crates/elp/src/server/setup.rs index 6dade5c677..4b8615e07c 100644 --- a/crates/elp/src/server/setup.rs +++ b/crates/elp/src/server/setup.rs @@ -33,6 +33,7 @@ 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; @@ -125,8 +126,9 @@ impl ServerSetup { // Set up a logger for tracking down why we are seeing stale // results when branches are switched, as per T218973130 - let log_dir = "/tmp/elp"; - let _ = fs::create_dir_all(log_dir); + // @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_file = format!( "{}/elp_file_watch_reports-{}.log", log_dir, diff --git a/crates/elp/src/server/telemetry_manager.rs b/crates/elp/src/server/telemetry_manager.rs index b1cb2d3ac9..5d4293d5ec 100644 --- a/crates/elp/src/server/telemetry_manager.rs +++ b/crates/elp/src/server/telemetry_manager.rs @@ -26,17 +26,23 @@ use crate::memory_usage::MemoryUsage; const PERIODIC_INTERVAL_MS: Duration = Duration::from_millis(60_000); +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum OperationalState { + NotStarted, + Started, + Restarted, +} pub(crate) struct TelemetryManager { last_periodic_processed: Instant, server_started_at: SystemTime, - already_operational: bool, + operational_state: OperationalState, } impl TelemetryManager { pub(crate) fn new() -> Self { Self { last_periodic_processed: Instant::now(), server_started_at: SystemTime::now(), - already_operational: false, + operational_state: OperationalState::NotStarted, } } @@ -70,32 +76,48 @@ impl TelemetryManager { } } - pub(crate) fn operational(&mut self) { - if !self.already_operational { - let duration = self - .server_started_at - .elapsed() - .map(|e| e.as_millis()) - .unwrap_or(0) as u32; - - #[derive(Serialize)] - struct Operational { - title: String, + pub(crate) fn operational(&mut self, buck_quick_start: bool) { + let title = if buck_quick_start { + match self.operational_state { + OperationalState::NotStarted => "ELP operational (quick start)", + OperationalState::Started => "ELP operational (fully)", + OperationalState::Restarted => return, } - let data = Operational { - title: "ELP operational".to_string(), - }; - let data = serde_json::to_value(data).unwrap_or_else(|err| { - serde_json::Value::String(format!("JSON serialization failed: {err}")) - }); - telemetry::send_with_duration( - String::from("telemetry"), - data, - duration, - self.server_started_at, - ); - self.already_operational = true; + } else { + match self.operational_state { + OperationalState::NotStarted => "ELP operational", + OperationalState::Started => return, + OperationalState::Restarted => return, + } + }; + + let duration = self + .server_started_at + .elapsed() + .map(|e| e.as_millis()) + .unwrap_or(0) as u32; + + #[derive(Serialize)] + struct Operational { + title: String, } + let data = Operational { + title: title.to_string(), + }; + let data = serde_json::to_value(data).unwrap_or_else(|err| { + serde_json::Value::String(format!("JSON serialization failed: {err}")) + }); + telemetry::send_with_duration( + String::from("telemetry"), + data, + duration, + self.server_started_at, + ); + self.operational_state = if self.operational_state == OperationalState::NotStarted { + OperationalState::Started + } else { + OperationalState::Restarted + }; } } @@ -256,12 +278,14 @@ mod test { // Control lock scope by having it in braces let mut telemetry = TEST_TELEMETRY.lock(); telemetry.next_segment(token.clone(), None); - let new = telemetry.active.get(&token).unwrap(); + let new = telemetry.active.get_mut(&token).unwrap(); assert_ne!(orig.segment_start_time, new.segment_start_time); assert_eq!(orig.start_time, new.start_time); + // We sometimes run on a rollover boundary, set the value to zero to avoid flakiness + for seg in &mut new.segments { + seg.1 = 0; + } let expected = format!("{:#?}\n", &new.segments); - // We sometimes run on a rollover boundary - let expected = expected.replace("1", "0"); expect![[r#" [ ( diff --git a/crates/elp/src/snapshot.rs b/crates/elp/src/snapshot.rs index e79251f73a..69ea6b97e0 100644 --- a/crates/elp/src/snapshot.rs +++ b/crates/elp/src/snapshot.rs @@ -36,9 +36,11 @@ 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; @@ -186,6 +188,14 @@ 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, @@ -193,7 +203,7 @@ impl Snapshot { ) -> Result<()> { let _ = self.analysis.def_map(file_id)?; if optimize_for_eqwalizer { - let should_eqwalize = self.analysis.should_eqwalize(file_id, false)?; + let should_eqwalize = self.analysis.should_eqwalize(file_id)?; if should_eqwalize { let _ = self.analysis.module_ast(file_id)?; } @@ -242,7 +252,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, false) { + if let Ok(true) = self.analysis.should_eqwalize(file_id) { Some(file_id) } else { None diff --git a/crates/elp/src/to_proto.rs b/crates/elp/src/to_proto.rs index f9263cfcab..3e5b1fd1e1 100644 --- a/crates/elp/src/to_proto.rs +++ b/crates/elp/src/to_proto.rs @@ -10,6 +10,7 @@ //! Conversion of rust-analyzer specific types to lsp_types equivalents. +use std::mem; use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering; @@ -47,10 +48,11 @@ 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; @@ -121,9 +123,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 @@ -131,34 +133,131 @@ 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, - source_change: SourceChange, + mut source_change: SourceChange, ) -> Result { - let mut edits: Vec<_> = vec![]; - for (file_id, edit) in source_change.source_file_edits { - // 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(), - }); + 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); + } } - let document_changes = lsp_types::DocumentChanges::Edits(edits); + + 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); + } + } + + 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(), + }, + )); + } + + // 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 workspace_edit = lsp_types::WorkspaceEdit { changes: None, - document_changes: Some(document_changes), + document_changes: Some(lsp_types::DocumentChanges::Operations(document_changes)), change_annotations: None, }; Ok(workspace_edit) @@ -182,10 +281,6 @@ 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 45b24c99f6..91f2b234d9 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_projects/buck_tests"; + let path_str = "../../test/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, false) + .is_eqwalizer_enabled(file_id) .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,19 +76,14 @@ mod tests { #[test] #[ignore] fn test_load_buck_targets() { - let path_str = "../../test_projects/buck_tests"; + let path_str = "../../test/test_projects/buck_tests"; let path: PathBuf = path_str.into(); let (elp_config, buck_config) = ProjectManifest::discover(&to_abs_path_buf(&path).unwrap()).unwrap(); - let project = Project::load( - &buck_config, - elp_config.eqwalizer, - &BUCK_QUERY_CONFIG, - &|_| {}, - ) - .unwrap(); + let project = + Project::load(&buck_config, &elp_config, &BUCK_QUERY_CONFIG, &|_| {}).unwrap(); let project_data: Vec = project .non_otp_apps() diff --git a/crates/elp/tests/slow-tests/main.rs b/crates/elp/tests/slow-tests/main.rs index 98455e8850..e256ce2c62 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_projects/end_to_end"), + Utf8Path::new(env!("CARGO_WORKSPACE_DIR")).join("test/test_projects/end_to_end"), ); // Sanity check @@ -70,7 +70,7 @@ fn test_run_mock_lsp() { } ], "textDocument": { - "uri": "file:///[..]/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", + "uri": "file:///[..]/test/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_projects/end_to_end/assist_examples/src/head_mismatch.erl", + "uri": "file:///[..]/test/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_projects/end_to_end/assist_examples/src/head_mismatch.erl", + "uri": "file:///[..]/test/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_projects/end_to_end/assist_examples/src/head_mismatch.erl", + "uri": "file:///[..]/test/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_projects/standard"), + Utf8Path::new(env!("CARGO_WORKSPACE_DIR")).join("test/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\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", + "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", "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\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", + "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", "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\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", + "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", "range": { "end": { "character": 5, @@ -321,7 +321,7 @@ fn test_e2e_eqwalizer_module() { "source": "eqWAlizer" } ], - "uri": "file:///[..]/test_projects/standard/app_a/src/app_a.erl", + "uri": "file:///[..]/test/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_projects/standard")); +// AbsPathBuf::assert(Path::new(env!("CARGO_WORKSPACE_DIR")).join("test/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 bf482a7816..2c794f6246 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_secs(60); + let timeout = Duration::from_mins(1); select! { recv(receiver) -> msg => Ok(msg.ok()), recv(after(timeout)) -> _ => Err(Timeout), diff --git a/crates/elp_log/src/telemetry.rs b/crates/elp_log/src/telemetry.rs index 4132de6102..86da912528 100644 --- a/crates/elp_log/src/telemetry.rs +++ b/crates/elp_log/src/telemetry.rs @@ -20,18 +20,18 @@ use std::time::SystemTime; -use humantime::format_rfc3339_millis; +pub use humantime::format_rfc3339_millis; use lazy_static::lazy_static; use serde::Deserialize; use serde::Serialize; pub type TelemetryData = serde_json::Value; -pub type Duration = u32; +pub type DurationMs = u32; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TelemetryMessage { #[serde(rename = "type")] pub typ: String, - pub duration_ms: Option, + pub duration_ms: Option, pub start_time: Option, pub start_time_string: Option, pub end_time_string: Option, @@ -56,7 +56,7 @@ pub fn receiver() -> &'static TelemetryReceiver { fn build_message( typ: String, data: TelemetryData, - duration_ms: Option, + duration_ms: Option, start_time: Option, ) -> TelemetryMessage { let start_time_string = start_time.map(|time| format_rfc3339_millis(time).to_string()); @@ -84,7 +84,7 @@ fn build_message( fn do_send( typ: String, data: serde_json::Value, - duration: Option, + duration: Option, start_time: Option, ) { let message = build_message(typ, data, duration, start_time); @@ -98,12 +98,18 @@ pub fn send(typ: String, data: serde_json::Value) { pub fn send_with_duration( typ: String, data: serde_json::Value, - duration: Duration, + duration: DurationMs, start_time: SystemTime, ) { do_send(typ, data, Some(duration), Some(start_time)); } +pub fn report_elapsed_time(what: &str, start_time: SystemTime) { + let data = serde_json::Value::String(what.to_string()); + let duration = start_time.elapsed().map(|e| e.as_millis()).unwrap_or(0) as u32; + send_with_duration("telemetry".to_string(), data, duration, start_time); +} + #[cfg(test)] mod tests { use std::time::SystemTime; diff --git a/crates/eqwalizer/build.rs b/crates/eqwalizer/build.rs index f7e9a0acaa..2fb342b00e 100644 --- a/crates/eqwalizer/build.rs +++ b/crates/eqwalizer/build.rs @@ -11,16 +11,20 @@ use std::env; use std::fs; use std::path::Path; +use std::path::PathBuf; use std::process::Command; fn main() { let source_directory = Path::new("../../../eqwalizer/eqwalizer"); + let tools_dir = source_directory.join("tools"); let out_dir = env::var_os("OUT_DIR").unwrap(); let eqwalizer_out_dir = Path::new("../../../../../buck-out/eqwalizer/scala-3.6.4"); let dest_path = Path::new(&out_dir).join("eqwalizer"); let extension; + let java; if let Some(path) = env::var_os("ELP_EQWALIZER_PATH") { + java = "java".into(); let from = Path::new(&path); extension = from .extension() @@ -30,60 +34,75 @@ fn main() { .to_string(); fs::copy(from, dest_path).expect("Copying precompiled eqwalizer failed"); } else { - extension = "".to_string(); - // Use the sbt wrapper on linux or otherwise require sbt to be installed - let sbt = fs::canonicalize(source_directory.join("./meta/sbt.sh")).unwrap(); - let output = Command::new(sbt) - .arg("assembly") - .current_dir(source_directory) - .env("EQWALIZER_USE_BUCK_OUT", "true") - .output() - .expect("failed to execute sbt assembly"); + let jar = build_jar(source_directory, eqwalizer_out_dir); - if !output.status.success() { - let stdout = - String::from_utf8(output.stdout).expect("valid utf8 output from sbt assembly"); - let stderr = - String::from_utf8(output.stderr).expect("valid utf8 output from sbt assembly"); - panic!("sbt assembly failed with stdout:\n{stdout}\n\nstderr:\n{stderr}"); + if env::var("OPT_LEVEL").unwrap_or_default() == "0" { + extension = "jar".to_string(); + java = if env::var("CARGO_CFG_TARGET_OS").unwrap() == "linux" { + fs::canonicalize(tools_dir.join("graalvm/bin/java")).unwrap() + } else { + "java".into() + }; + fs::copy(jar, dest_path).expect("Copying fresh eqwalizer failed"); + } else { + extension = "".to_string(); + java = "java".into(); + let image_path = build_native_image(source_directory, eqwalizer_out_dir, jar); + fs::copy(image_path, dest_path).expect("Copying fresh eqwalizer failed"); } - let jar = fs::canonicalize(eqwalizer_out_dir.join("eqwalizer.jar")).unwrap(); - - let native_image = - fs::canonicalize(source_directory.join("./meta/native-image.sh")).unwrap(); - let image_path = fs::canonicalize(eqwalizer_out_dir) - .unwrap() - .join("eqwalizer"); - let output = Command::new(native_image) - .current_dir(source_directory) - .arg("-H:IncludeResources=application.conf") - .arg("--no-server") - .arg("--no-fallback") - .arg("-jar") - .arg(jar) - .arg(&image_path) - .output() - .expect("failed to execute native-image"); - - if !output.status.success() { - let stdout = - String::from_utf8(output.stdout).expect("valid utf8 output from native-image"); - let stderr = - String::from_utf8(output.stderr).expect("valid utf8 output from native-image"); - panic!("native-image failed with stdout:\n{stdout}\n\nstderr:\n{stderr}"); - } - - fs::copy(image_path, dest_path).expect("Copying fresh eqwalizer failed"); - rerun_if_changed(source_directory.join("build.sbt")); rerun_if_changed(source_directory.join("src")); } println!("cargo:rustc-env=ELP_EQWALIZER_EXT={extension}"); + println!("cargo:rustc-env=ELP_EQWALIZER_JAVA={}", java.display()); println!("cargo:rerun-if-env-changed=ELP_EQWALIZER_PATH"); } +fn build_native_image(source_directory: &Path, eqwalizer_out_dir: &Path, jar: PathBuf) -> PathBuf { + let native_image = fs::canonicalize(source_directory.join("./meta/native-image.sh")).unwrap(); + let image_path = fs::canonicalize(eqwalizer_out_dir) + .unwrap() + .join("eqwalizer"); + let output = Command::new(native_image) + .current_dir(source_directory) + .arg("-H:IncludeResources=application.conf") + .arg("--no-server") + .arg("--no-fallback") + .arg("-jar") + .arg(jar) + .arg(&image_path) + .output() + .expect("failed to execute native-image"); + + if !output.status.success() { + let stdout = String::from_utf8(output.stdout).expect("valid utf8 output from native-image"); + let stderr = String::from_utf8(output.stderr).expect("valid utf8 output from native-image"); + panic!("native-image failed with stdout:\n{stdout}\n\nstderr:\n{stderr}"); + } + image_path +} + +fn build_jar(source_directory: &Path, eqwalizer_out_dir: &Path) -> PathBuf { + // Use the sbt wrapper on linux or otherwise require sbt to be installed + let sbt = fs::canonicalize(source_directory.join("./meta/sbt.sh")).unwrap(); + let output = Command::new(sbt) + .arg("assembly") + .current_dir(source_directory) + .env("EQWALIZER_USE_BUCK_OUT", "true") + .output() + .expect("failed to execute sbt assembly"); + + if !output.status.success() { + let stdout = String::from_utf8(output.stdout).expect("valid utf8 output from sbt assembly"); + let stderr = String::from_utf8(output.stderr).expect("valid utf8 output from sbt assembly"); + panic!("sbt assembly failed with stdout:\n{stdout}\n\nstderr:\n{stderr}"); + } + + fs::canonicalize(eqwalizer_out_dir.join("eqwalizer.jar")).unwrap() +} + fn rerun_if_changed(path: impl AsRef) { println!("cargo:rerun-if-changed={}", path.as_ref().display()); } diff --git a/crates/eqwalizer/src/ast/convert_types.rs b/crates/eqwalizer/src/ast/convert_types.rs index e097e1a028..ccfc635cdc 100644 --- a/crates/eqwalizer/src/ast/convert_types.rs +++ b/crates/eqwalizer/src/ast/convert_types.rs @@ -258,9 +258,15 @@ impl TypeConverter { ExtType::ListExtType(ty) => Ok(self .convert_type(sub, *ty.t)? .map(|t| Type::ListType(ListType { t: Box::new(t) }))), - ExtType::UnionExtType(tys) => Ok(self - .convert_types(sub, tys.tys)? - .map(|tys| Type::UnionType(UnionType { tys }))), + // unions with NoneType are meaningless, we can remove them early + ExtType::UnionExtType(tys) => Ok(self.convert_types(sub, tys.tys)?.map(|mut tys| { + tys.retain(|ty| *ty != Type::NoneType); + match tys.len() { + 0 => Type::NoneType, + 1 => tys.into_iter().next().unwrap(), + _ => Type::UnionType(UnionType { tys }), + } + })), ExtType::RemoteExtType(ty) if ty.id.module == "eqwalizer" && ty.id.name == "refinable" diff --git a/crates/eqwalizer/src/ipc.rs b/crates/eqwalizer/src/ipc.rs index 30b1dae582..4d10d663ec 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_secs(240); -const READ_TIMEOUT: Duration = Duration::from_secs(240); +const WRITE_TIMEOUT: Duration = Duration::from_mins(4); +const READ_TIMEOUT: Duration = Duration::from_mins(4); impl IpcHandle { fn spawn_cmd(cmd: &mut Command) -> Result { diff --git a/crates/eqwalizer/src/lib.rs b/crates/eqwalizer/src/lib.rs index e8c7b18b92..54333570fd 100644 --- a/crates/eqwalizer/src/lib.rs +++ b/crates/eqwalizer/src/lib.rs @@ -220,7 +220,7 @@ impl EqwalizerExe { let (cmd, args) = match ext.as_str() { "jar" => ( - "java".into(), + env!("ELP_EQWALIZER_JAVA").into(), vec!["-Xss20M".into(), "-jar".into(), path.into()], ), "" => (path, vec![]), @@ -244,7 +244,9 @@ impl EqwalizerExe { impl Eqwalizer { fn cmd(&self) -> Command { let mut exe = EQWALIZER_EXE.lock(); - if !exe.cmd.is_file() { + // 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() { 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 16020d78f6..072f439db3 100644 --- a/crates/erlang_service/src/lib.rs +++ b/crates/erlang_service/src/lib.rs @@ -59,12 +59,13 @@ lazy_static! { pub static ref ESCRIPT: RwLock = RwLock::new("escript".to_string()); } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum DiagnosticLocation { Normal(TextRange), Included { - directive_location: TextRange, // Location of include directive in the file compiled - error_location: TextRange, // Location of the error in the included file + 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 }, } @@ -735,7 +736,8 @@ fn decode_errors(buf: &[u8]) -> Result> { eetf::Term::decode(buf)? .as_match(pattern::VarList(( - Str, + Str, // path + Str, // error path pattern::Or(( (pattern::U32, pattern::U32), // Normal location pattern::FixList(((pattern::U32, pattern::U32), (pattern::U32, pattern::U32))), // Location in include file @@ -747,7 +749,7 @@ fn decode_errors(buf: &[u8]) -> Result> { .map_err(|err| anyhow!("Failed to decode errors: {:?}", err)) .map(|res| { res.into_iter() - .map(|(path, position, msg, code)| ParseError { + .map(|(path, error_path, position, msg, code)| ParseError { path: path.into(), location: match position { pattern::Union3::A((a, b)) => Some(DiagnosticLocation::Normal( @@ -755,7 +757,8 @@ fn decode_errors(buf: &[u8]) -> Result> { )), pattern::Union3::B(((a, b), (c, d))) => { Some(DiagnosticLocation::Included { - directive_location: safe_textrange(a.into(), b.into()), + file_attribute_location: safe_textrange(a.into(), b.into()), + error_path: error_path.into(), error_location: safe_textrange(c.into(), d.into()), }) } diff --git a/crates/hir/src/body.rs b/crates/hir/src/body.rs index e4731ddc87..9ebac17c66 100644 --- a/crates/hir/src/body.rs +++ b/crates/hir/src/body.rs @@ -43,6 +43,7 @@ use crate::FormList; use crate::FunctionClause; use crate::FunctionClauseId; use crate::InFile; +use crate::IncludeAttributeId; use crate::Literal; use crate::Name; use crate::NameArity; @@ -661,6 +662,15 @@ impl FunctionClauseBody { tree_print::print_function_clause_with_strategy(db, self, strategy) } + pub fn tree_print_with_range( + &self, + db: &dyn InternDatabase, + strategy: Strategy, + source_map: &BodySourceMap, + ) -> String { + tree_print::print_function_clause_with_strategy_and_range(db, self, strategy, source_map) + } + pub fn fold(&self, strategy: Strategy, initial: T, callback: AnyCallBack<'_, T>) -> T { match &self.from_macro { Some(from_macro) if strategy.macros == MacroStrategy::DoNotExpand => { @@ -1056,8 +1066,12 @@ impl Index for FoldBody<'_> { type Output = TypeExpr; fn index(&self, index: TypeExprId) -> &Self::Output { - // Do not "look through" macro expansion + // Apply the visibility strategies to macros and parens match &self.body.type_exprs[index] { + TypeExpr::Paren { ty } => match self.parens { + ParenStrategy::VisibleParens => &self.body.type_exprs[index], + ParenStrategy::InvisibleParens => self.index(*ty), + }, type_expr @ TypeExpr::MacroCall { expansion, .. } => match self.macros { VisibleMacros::Yes => type_expr, VisibleMacros::No => self.index(*expansion), @@ -1142,6 +1156,24 @@ 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 @@ -1218,6 +1250,7 @@ pub struct BodySourceMap { term_map: FxHashMap, term_map_back: ArenaMap, macro_map: FxHashMap, + diagnostics: Vec, } impl BodySourceMap { @@ -1279,6 +1312,10 @@ 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 f6a03b8a2c..4abf0737b2 100644 --- a/crates/hir/src/body/lower.rs +++ b/crates/hir/src/body/lower.rs @@ -38,6 +38,7 @@ use crate::AttributeBody; use crate::BasedInteger; use crate::BinarySeg; use crate::Body; +use crate::BodyDiagnostic; use crate::BodySourceMap; use crate::CRClause; use crate::CallTarget; @@ -116,6 +117,10 @@ 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)] @@ -152,6 +157,8 @@ impl<'a> Ctx<'a> { starting_stack_size: 1, macro_source_map: FxHashMap::default(), in_ssr: false, + in_macro_rhs: false, + diagnostics: Vec::new(), } } @@ -216,6 +223,7 @@ 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) } @@ -401,7 +409,9 @@ 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) } @@ -812,6 +822,9 @@ 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() @@ -847,11 +860,8 @@ impl<'a> Ctx<'a> { self.alloc_pat(Pat::Missing, Some(expr)) } ast::ExprMax::ParenExpr(paren_expr) => { - if let Some(paren_expr) = paren_expr.expr() { - let pat_id = self.lower_pat(&paren_expr); - let ptr = AstPtr::new(&paren_expr); - let source = InFileAstPtr::new(self.curr_file_id(), ptr); - self.record_pat_source(pat_id, source); + if let Some(inner_paren_expr) = paren_expr.expr() { + let pat_id = self.lower_pat(&inner_paren_expr); self.alloc_pat(Pat::Paren { pat: pat_id }, Some(expr)) } else { self.alloc_pat(Pat::Missing, Some(expr)) @@ -1172,6 +1182,9 @@ 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()) @@ -1403,8 +1416,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); @@ -1467,6 +1480,9 @@ 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() @@ -1483,14 +1499,12 @@ impl<'a> Ctx<'a> { }, Some(expr), ) - }), + }) + } ast::ExprMax::MacroString(_) => self.alloc_expr(Expr::Missing, Some(expr)), ast::ExprMax::ParenExpr(paren_expr) => { - if let Some(paren_expr) = paren_expr.expr() { - let expr_id = self.lower_expr(&paren_expr); - let ptr = AstPtr::new(expr); - let source = InFileAstPtr::new(self.curr_file_id(), ptr); - self.record_expr_source(expr_id, source); + if let Some(inner_expr) = paren_expr.expr() { + let expr_id = self.lower_expr(&inner_expr); self.alloc_expr(Expr::Paren { expr: expr_id }, Some(expr)) } else { self.alloc_expr(Expr::Missing, Some(expr)) @@ -1996,6 +2010,9 @@ 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()) @@ -2176,6 +2193,9 @@ 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() @@ -2195,12 +2215,9 @@ impl<'a> Ctx<'a> { }), ast::ExprMax::MacroString(_) => self.alloc_type_expr(TypeExpr::Missing, Some(expr)), ast::ExprMax::ParenExpr(paren_expr) => { - if let Some(expr) = paren_expr.expr() { - let type_expr_id = self.lower_type_expr(&expr); - let ptr = AstPtr::new(&expr); - let source = InFileAstPtr::new(self.curr_file_id(), ptr); - self.record_type_source(type_expr_id, source); - type_expr_id + if let Some(inner_expr) = paren_expr.expr() { + let type_expr_id = self.lower_type_expr(&inner_expr); + self.alloc_type_expr(TypeExpr::Paren { ty: type_expr_id }, Some(expr)) } else { self.alloc_type_expr(TypeExpr::Missing, Some(expr)) } @@ -2545,6 +2562,9 @@ 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() @@ -3006,6 +3026,23 @@ 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/pretty.rs b/crates/hir/src/body/pretty.rs index e19c97e637..5b84b4e8ef 100644 --- a/crates/hir/src/body/pretty.rs +++ b/crates/hir/src/body/pretty.rs @@ -776,6 +776,7 @@ impl<'a> Printer<'a> { macro_def: _, macro_name: _, } => self.print_type(&self.body[*expansion]), + TypeExpr::Paren { ty } => self.print_type(&self.body[*ty]), TypeExpr::SsrPlaceholder(ssr) => self.print_ssr_placeholder(ssr), } } diff --git a/crates/hir/src/body/scope.rs b/crates/hir/src/body/scope.rs index dd1da23e94..4ac4e366d8 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 dd5e5e4699..eab603a76d 100644 --- a/crates/hir/src/body/tests.rs +++ b/crates/hir/src/body/tests.rs @@ -8,6 +8,8 @@ * above-listed licenses. */ +use std::fmt::Write; + use elp_base_db::fixture::WithFixture; use expect_test::Expect; use expect_test::expect; @@ -446,6 +448,7 @@ 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 = }. "#, @@ -471,6 +474,7 @@ foo2(#record{field}) -> #record{field = }. fn record_update() { check( r#" +//- expect_parse_errors foo1() -> Expr#record{field = undefined}. foo2() -> Expr#record{field = ok, missing = }. "#, @@ -555,7 +559,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. "#, @@ -564,7 +568,7 @@ foo() -> case (1 + 2) of X when (X andalso true); - (X < 100), + (X =< 100), (X >= 5) -> ok; @@ -834,6 +838,7 @@ foo() -> fn parens() { check( r#" +//- expect_parse_errors foo((ok), ()) -> (ok), (). @@ -993,6 +998,7 @@ foo(fun() -> ok end) -> ok. fn invalid_comprehension() { check( r#" +//- expect_parse_errors foo(<>, [Byte || Byte <- List]]) -> ok. "#, expect![[r#" @@ -1390,6 +1396,7 @@ 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 ::}. @@ -1527,6 +1534,7 @@ fn record_definition() { fn simple_term() { check( r#" +//- expect_parse_errors -foo(ok). -missing_value(). "#, @@ -2691,6 +2699,7 @@ 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"). "#, @@ -2721,6 +2730,7 @@ fn verbatim_binary_sigil_in_term() { fn lowering_with_error_nodes() { check( r#" + //- expect_parse_errors f(1a) -> ok begin 1 end. "#, expect![[r#" @@ -2759,6 +2769,74 @@ fn tree_print_function() { ); } +#[test] +fn tree_print_function_with_ranges() { + let (db, file_ids, _) = TestDB::with_many_files( + r#" + foo( (((A))) ) -> ((3)). + "#, + ); + let file_id = file_ids[0]; + let form_list = db.file_form_list(file_id); + let strategy = Strategy { + macros: MacroStrategy::ExpandButIncludeMacroCall, + parens: ParenStrategy::VisibleParens, + }; + let pretty = form_list + .forms() + .iter() + .flat_map(|&form_idx| match form_idx { + FormIdx::FunctionClause(function_id) => { + let def_map = db.def_map(file_id); + let function_def_id = InFile::new(file_id, FunctionDefId::new(function_id)); + if let Some(_fun_def) = def_map.get_by_function_id(&function_def_id) { + let (body, source_maps) = db.function_body_with_source(function_def_id); + let mut out = String::new(); + if let Some((_, clause)) = body.clauses.iter().next() { + if let Some(na) = clause.name.clone() { + writeln!(out, "function: {na}").ok(); + } + if let Some(source_map) = source_maps.first() { + write!( + out, + "{}", + clause.tree_print_with_range(&db, strategy, source_map) + ) + .ok(); + } + } + writeln!(out, ".").ok(); + Some(out) + } else { + None + } + } + _ => None, + }) + .collect::>() + .join(""); + expect![[r#" + function: foo/1 + + Clause { + pats + Pat<3>:Pat::Paren { (range: 5..12) + Pat<2>:Pat::Paren { (range: 6..11) + Pat<1>:Pat::Paren { (range: 7..10) + Pat<0>:Pat::Var(A)}}}, + guards + exprs + Expr<3>:Expr::Paren { (range: 18..23) + Expr<2>:Expr::Paren { (range: 19..22) + Expr<1>:Literal(Integer(3)) + } + }, + } + . + "#]] + .assert_eq(pretty.trim_start()); +} + #[test] fn tree_print_type_body() { check_ast( @@ -2919,8 +2997,10 @@ 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 ff89265c10..d6b956690f 100644 --- a/crates/hir/src/body/tree_print.rs +++ b/crates/hir/src/body/tree_print.rs @@ -15,12 +15,15 @@ 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; use super::SpecBody; use super::SpecOrCallback; use crate::AnyAttribute; +use crate::AnyExprId; use crate::AttributeBody; use crate::BinarySeg; use crate::CRClause; @@ -32,11 +35,15 @@ 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; @@ -49,6 +56,7 @@ 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; @@ -175,6 +183,23 @@ pub(crate) fn print_function_clause_with_strategy( out } +pub(crate) fn print_function_clause_with_strategy_and_range( + db: &dyn InternDatabase, + clause: &FunctionClauseBody, + strategy: Strategy, + source_map: &crate::BodySourceMap, +) -> String { + let mut out = String::new(); + + let fold_body = fold_body(strategy, &clause.body); + let mut printer = Printer::new_with_strategy_and_range(db, &fold_body, strategy, source_map); + printer.print_clause(&clause.clause); + write!(out, "{}", printer.result_raw()).unwrap(); + writeln!(out).unwrap(); + + out +} + pub(crate) fn print_type_alias( db: &dyn InternDatabase, body: &crate::TypeBody, @@ -314,6 +339,63 @@ 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>, @@ -322,6 +404,8 @@ struct Printer<'a> { indent_level: usize, needs_indent: bool, include_id: bool, + source_map: Option<&'a crate::BodySourceMap>, + current: Option, } impl<'a> Printer<'a> { @@ -334,6 +418,8 @@ impl<'a> Printer<'a> { indent_level: 0, needs_indent: true, include_id: true, + source_map: None, + current: None, } } @@ -350,6 +436,27 @@ impl<'a> Printer<'a> { indent_level: 0, needs_indent: true, include_id: true, + source_map: None, + current: None, + } + } + + fn new_with_strategy_and_range( + db: &'a dyn InternDatabase, + body: &'a FoldBody, + strategy: Strategy, + source_map: &'a crate::BodySourceMap, + ) -> Self { + Printer { + db, + body, + expand_macros: strategy.macros != MacroStrategy::DoNotExpand, + buf: String::new(), + indent_level: 0, + needs_indent: true, + include_id: true, + source_map: Some(source_map), + current: None, } } @@ -373,6 +480,7 @@ impl<'a> Printer<'a> { } fn print_expr(&mut self, expr_id: &ExprId) { + self.current = Some(AnyExprId::Expr(*expr_id)); if self.include_id { write!(self, "Expr<{}>:", expr_id.into_raw().into_u32()).ok(); } @@ -732,6 +840,7 @@ impl<'a> Printer<'a> { Expr::Paren { expr } => { self.print_herald("Expr::Paren", &mut |this| { this.print_expr(expr); + writeln!(this).ok(); }); } Expr::SsrPlaceholder(ssr) => self.print_ssr_placeholder(ssr), @@ -739,6 +848,7 @@ impl<'a> Printer<'a> { } fn print_pat(&mut self, pat: &PatId) { + self.current = Some(AnyExprId::Pat(*pat)); if self.include_id { write!(self, "Pat<{}>:", pat.into_raw().into_u32()).ok(); } @@ -871,6 +981,7 @@ impl<'a> Printer<'a> { } fn print_term(&mut self, term: &TermId) { + self.current = Some(AnyExprId::Term(*term)); match &self.body[*term] { Term::Missing => { write!(self, "Term::Missing").ok(); @@ -972,6 +1083,7 @@ impl<'a> Printer<'a> { } fn print_type(&mut self, ty: &TypeExprId) { + self.current = Some(AnyExprId::TypeExpr(*ty)); match &self.body[*ty] { TypeExpr::AnnType { var, ty } => { self.print_herald("TypeExpr::AnnType", &mut |this| { @@ -1140,6 +1252,11 @@ impl<'a> Printer<'a> { } }); } + TypeExpr::Paren { ty } => { + self.print_herald("TypeExpr::Paren", &mut |this| { + this.print_type(ty); + }); + } TypeExpr::SsrPlaceholder(ssr) => self.print_ssr_placeholder(ssr), } } @@ -1234,7 +1351,16 @@ impl<'a> Printer<'a> { } fn print_herald(&mut self, label: &str, print: &mut dyn FnMut(&mut Self)) { - writeln!(self, "{label} {{").ok(); + let range = self + .current + .and_then(|id| self.source_map.and_then(|sm| sm.any(id))) + .map(|es| es.range().range); + + if let Some(r) = range { + writeln!(self, "{label} {{ (range: {r:?})").ok(); + } else { + writeln!(self, "{label} {{").ok(); + } self.indent(); print(self); self.dedent(); @@ -1461,13 +1587,8 @@ 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::db::DefDatabase; + use crate::body::tree_print::print_form_list; use crate::fold::MacroStrategy; use crate::fold::ParenStrategy; use crate::test_db::TestDB; @@ -1484,52 +1605,7 @@ mod tests { #[track_caller] fn check_with_strategy(strategy: Strategy, fixture: &str, expect: Expect) { let (db, file_id) = TestDB::with_single_file(fixture); - 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(""); + let pretty = print_form_list(&db, file_id, strategy); expect.assert_eq(pretty.trim_start()); } @@ -1937,6 +2013,16 @@ 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 @@ -2254,7 +2340,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. "#, @@ -2295,7 +2381,7 @@ mod tests { rhs Expr<8>:Literal(Integer(100)) op - CompOp(Ord { ordering: Less, strict: true }), + CompOp(Ord { ordering: Less, strict: false }), }, Expr<12>:Expr::BinaryOp { lhs @@ -3028,6 +3114,7 @@ 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 ::}. @@ -3301,7 +3388,9 @@ mod tests { exprs Expr<3>:Expr::Paren { Expr<2>:Expr::Paren { - Expr<1>:Literal(Integer(3))}}, + Expr<1>:Literal(Integer(3)) + } + }, }. "#]], ); @@ -3348,10 +3437,111 @@ mod tests { Expr<4>:Expr::Tuple { Expr<3>:Expr::Paren { Expr<2>:Expr::Paren { - Expr<1>:Literal(Integer(3))}}, + Expr<1>:Literal(Integer(3)) + } + }, }, }. "#]], ); } + + #[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 eed60a47a2..114930efe3 100644 --- a/crates/hir/src/expr.rs +++ b/crates/hir/src/expr.rs @@ -581,6 +581,26 @@ 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 { @@ -657,6 +677,16 @@ impl CallTarget { } } } + + pub fn module_range( + &self, + in_clause: &InFunctionClauseBody<&FunctionDef>, + ) -> Option { + match self { + CallTarget::Local { .. } => None, + CallTarget::Remote { module, .. } => in_clause.range_for_expr(*module), + } + } } #[derive(Debug, Clone, Copy, Eq, PartialEq)] @@ -898,6 +928,13 @@ pub enum TypeExpr { macro_def: Option>, macro_name: MacroCallName, }, + Paren { + // This constructor allows us to analyze the usage of parens + // when deciding on assists. + // Much like `TypeExpr::MacroCall`, it is normally hidden during a + // `fold`, but can be made visible if needed. + ty: TypeExprId, + }, SsrPlaceholder(SsrPlaceholder), } @@ -926,6 +963,7 @@ impl TypeExpr { TypeExpr::UnaryOp { .. } => "TypeExpr::UnaryOp", TypeExpr::Var(_) => "TypeExpr::Var", TypeExpr::MacroCall { .. } => "TypeExpr::MacroCall", + TypeExpr::Paren { .. } => "TypeExpr::Paren", TypeExpr::SsrPlaceholder(_) => "TypeExpr::SsrPlaceholder", } } diff --git a/crates/hir/src/fold.rs b/crates/hir/src/fold.rs index e28a81d0fe..59b12be6fd 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, + pub in_macro: Option<(HirIdx, 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, + macro_stack: Vec<(HirIdx, Option>)>, 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 { + fn in_macro(&self) -> Option<(HirIdx, Option>)> { self.macro_stack.first().copied() } @@ -752,16 +752,19 @@ 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), - }); + self.macro_stack.push(( + HirIdx { + body_origin: self.body_origin, + idx: AnyExprId::Expr(expr_id), + }, + *macro_def, + )); let e = self.do_fold_expr(*expansion, acc); self.macro_stack.pop(); e @@ -950,16 +953,19 @@ 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), - }); + self.macro_stack.push(( + HirIdx { + body_origin: self.body_origin, + idx: AnyExprId::Pat(pat_id), + }, + *macro_def, + )); let e = self.do_fold_pat(*expansion, acc); self.macro_stack.pop(); e @@ -1165,21 +1171,25 @@ 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), - }); + self.macro_stack.push(( + HirIdx { + body_origin: self.body_origin, + idx: AnyExprId::TypeExpr(type_expr_id), + }, + *macro_def, + )); let e = self.do_fold_type_expr(*expansion, acc); self.macro_stack.pop(); e } } + TypeExpr::Paren { ty } => self.do_fold_type_expr(*ty, acc), TypeExpr::SsrPlaceholder(_) => acc, }; self.parents.pop(); @@ -1616,7 +1626,7 @@ bar() -> -define(AA, {foo,foo,foo}). bar(XX) -> begin %% clause.exprs[0] - case XX of + case XX of ?AA -> ok end, {fo~o} @@ -1678,7 +1688,7 @@ bar() -> -define(AA, {foo,foo,foo}). bar(XX) -> begin %% clause.exprs[0] - case XX of + case XX of ?AA -> ok end, {fo~o} @@ -2211,7 +2221,9 @@ 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}). "#; @@ -2651,6 +2663,56 @@ bar() -> count_parens(fixture_str, 3); } + #[test] + fn parens_in_type_expr() { + let fixture_str = r#" + -type foo() :: ((integer())). + "#; + count_parens_in_type_expr(fixture_str, 2); + } + + #[test] + fn parens_in_type_expr_complex() { + let fixture_str = r#" + -type bar() :: {((atom())), (integer() | (binary()))}. + "#; + count_parens_in_type_expr(fixture_str, 4); + } + + #[track_caller] + fn count_parens_in_type_expr(fixture_str: &str, n: u32) { + let (db, fixture) = TestDB::with_fixture(fixture_str); + let file_id = fixture.files[0]; + let sema = Semantic::new(&db); + + let r = do_count_parens_in_type_expr(&sema, ParenStrategy::InvisibleParens, file_id); + assert_eq!(r, 0); + + let r = do_count_parens_in_type_expr(&sema, ParenStrategy::VisibleParens, file_id); + assert_eq!(r, n); + } + + fn do_count_parens_in_type_expr( + sema: &Semantic, + parens: ParenStrategy, + file_id: FileId, + ) -> u32 { + fold_file( + sema, + Strategy { + macros: MacroStrategy::Expand, + parens, + }, + file_id, + 0, + &mut |acc, ctx| match ctx.item { + AnyExpr::TypeExpr(TypeExpr::Paren { .. }) => acc + 1, + _ => acc, + }, + &mut |acc, _on, _form_id| acc, + ) + } + // End of testing paren visibility // ----------------------------------------------------------------- } diff --git a/crates/hir/src/form_list.rs b/crates/hir/src/form_list.rs index 560befbb4b..a1431d7506 100644 --- a/crates/hir/src/form_list.rs +++ b/crates/hir/src/form_list.rs @@ -188,6 +188,11 @@ 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() } @@ -650,6 +655,23 @@ 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 00a5ec4020..79f542fd0d 100644 --- a/crates/hir/src/form_list/tests.rs +++ b/crates/hir/src/form_list/tests.rs @@ -318,6 +318,7 @@ 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 11d4b40971..751a2f4907 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -35,6 +35,7 @@ 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; @@ -154,7 +155,7 @@ pub use name::MacroName; pub use name::Name; pub use name::NameArity; pub use name::known; -// @fb-only +// @fb-only: pub use name::meta_only; pub use sema::AtomDef; pub use sema::CallDef; pub use sema::DefinitionOrReference; @@ -231,6 +232,10 @@ 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 477637b775..0420e19bb6 100644 --- a/crates/hir/src/module_data.rs +++ b/crates/hir/src/module_data.rs @@ -91,6 +91,19 @@ impl File { pub fn def_map(&self, db: &dyn DefDatabase) -> Arc { db.def_map(self.file_id) } + + pub fn is_in_otp(&self, db: &dyn DefDatabase) -> bool { + let file_id = self.file_id; + // Context for T171541590 + let _ = stdx::panic_context::enter(format!("\nis_in_otp:2: {file_id:?}")); + match db.file_app_data(file_id) { + Some(app_data) => { + let project_id = app_data.project_id; + db.project_data(project_id).otp_project_id == Some(project_id) + } + None => false, + } + } } /// Represents a module definition @@ -111,7 +124,7 @@ impl Module { } pub fn is_in_otp(&self, db: &dyn DefDatabase) -> bool { - is_in_otp(self.file.file_id, db) + self.file.is_in_otp(db) } pub fn has_moduledoc(&self, db: &dyn DefDatabase) -> bool { @@ -270,7 +283,7 @@ impl FunctionDef { } pub fn is_in_otp(&self, db: &dyn DefDatabase) -> bool { - is_in_otp(self.file.file_id, db) + self.file.is_in_otp(db) } pub fn edoc_comments(&self, db: &dyn DefDatabase) -> Option { @@ -602,8 +615,9 @@ impl TypeAliasDef { } pub fn name_range(&self, db: &dyn SourceDatabase) -> Option { - let range = self.source(db).type_name()?.syntax().text_range(); - Some(range) + let type_name = self.source(db).type_name()?; + let name = type_name.name()?; + Some(name.syntax().text_range()) } /// This information is used for completion. @@ -697,15 +711,3 @@ impl VarDef { db.lookup_var(self.hir_var).clone() } } - -fn is_in_otp(file_id: FileId, db: &dyn DefDatabase) -> bool { - // Context for T171541590 - let _ = stdx::panic_context::enter(format!("\nis_in_otp:2: {file_id:?}")); - match db.file_app_data(file_id) { - Some(app_data) => { - let project_id = app_data.project_id; - db.project_data(project_id).otp_project_id == Some(project_id) - } - None => false, - } -} diff --git a/crates/hir/src/name.rs b/crates/hir/src/name.rs index 00ce2f89f1..f94f139d38 100644 --- a/crates/hir/src/name.rs +++ b/crates/hir/src/name.rs @@ -10,7 +10,7 @@ //! See [`Name`]. -// @fb-only +// @fb-only: pub mod meta_only; use std::borrow::Cow; use std::collections::HashSet; diff --git a/crates/hir/src/sema.rs b/crates/hir/src/sema.rs index 78a7db7c3c..68577d2a2e 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 +// @fb-only: pub mod meta_only; pub mod to_def; pub struct ModuleIter(Arc); @@ -1006,6 +1006,28 @@ 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 fcefa17929..01d17278a2 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 +// @fb-only: use crate::sema::meta_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 + // @fb-only: meta_only::resolve_handle_call_target(sema, arity, file_id, &module_name, &fn_name); if let Some(r) = mo { r } else { @@ -786,19 +786,20 @@ use lazy_static::lazy_static; /// Pattern for matching dynamic call expressions (apply, rpc calls, etc.) #[derive(Debug, Clone)] -struct DynamicCallPattern { +pub(crate) struct DynamicCallPattern { /// Index of the target module argument (None when target function is in same module) - module_arg_index: Option, + pub(crate) module_arg_index: Option, /// Index of the target function argument - function_arg_index: usize, + pub(crate) function_arg_index: usize, /// Index of the arguments list or arity argument - args_list_index: usize, + pub(crate) args_list_index: usize, /// Whether to extract arity directly from an integer argument (true) or from list length (false) - direct_arity: bool, + pub(crate) direct_arity: bool, } -type PatternKey = (Option<&'static str>, &'static str, usize); +pub(crate) type PatternKey = (Option<&'static str>, &'static str, usize); +#[macro_export] macro_rules! add_patterns { ($patterns:ident, [$(($module:expr, $func:literal, $arity:literal, $module_idx:expr, $func_idx:literal, $args_idx:literal, $direct:expr)),* $(,)?]) => { $( @@ -815,9 +816,7 @@ macro_rules! add_patterns { }; } -fn create_dynamic_call_patterns() -> FxHashMap { - let mut patterns = FxHashMap::default(); - +fn add_dynamic_call_patterns(patterns: &mut FxHashMap) { // Each entry follows the format: // // (module, function, arity, module_arg_index, function_arg_index, args_list_index, direct_arity) @@ -884,20 +883,197 @@ fn create_dynamic_call_patterns() -> FxHashMap { (Some("erpc"), "send_request", 6, Some(1), 2, 3, false), ] ); - - patterns } -// Lazy static initialization for the patterns map +/// Specifies what forms a module argument can take. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ModuleArgType { + /// The argument must be a single module atom (e.g., `apply(Mod, Fun, Args)`) + Atom, + /// The argument must be a list of module atoms (e.g., some batch operations) + List, + /// The argument can be either a single module atom or a list of modules + /// (e.g., `meck:new(Mod | [Mod], Opts)`) + AtomOrList, +} + +/// Pattern for matching module argument positions in function calls. +/// Used by rename operations to identify which argument contains a module name. +#[derive(Debug, Clone, Copy)] +pub struct ModuleArgPattern { + /// Index of the argument containing the module name (0-based) + pub index: usize, + /// The type of the module argument (atom, list, or either) + pub arg_type: ModuleArgType, +} + +impl ModuleArgPattern { + /// Creates a pattern where the argument is a single module atom. + pub const fn atom(index: usize) -> 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! { - static ref DYNAMIC_CALL_PATTERNS: FxHashMap = - create_dynamic_call_patterns(); + 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); + } + patterns + }; } fn get_dynamic_call_patterns() -> &'static FxHashMap { &DYNAMIC_CALL_PATTERNS } +pub fn get_module_arg_patterns() -> &'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 aba9731379..acba8ef642 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml @@ -10,12 +10,11 @@ workspace = true elp_eqwalizer.workspace = true elp_erlang_service.workspace = true elp_ide_assists.workspace = true -elp_ide_completion.workspace = true elp_ide_db.workspace = true +elp_ide_completion.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 6cbdd3469c..d0ae18c158 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 +// @fb-only: use crate::meta_only; use crate::runnables::Runnable; use crate::runnables::runnables; @@ -57,11 +57,11 @@ pub struct Link { } #[rustfmt::skip] -// @fb-only +// @fb-only: pub(crate) fn annotations(db: &RootDatabase, file_id: FileId) -> Vec { pub(crate) fn annotations(_db: &RootDatabase, _file_id: FileId) -> Vec { // @oss-only - // @fb-only + // @fb-only: let mut annotations = Vec::default(); let annotations = Vec::default(); // @oss-only - // @fb-only + // @fb-only: meta_only::annotations(db, file_id, &mut annotations); annotations } diff --git a/crates/ide/src/codemod_helpers.rs b/crates/ide/src/codemod_helpers.rs index dc0b57b97e..2ecd21e82c 100644 --- a/crates/ide/src/codemod_helpers.rs +++ b/crates/ide/src/codemod_helpers.rs @@ -439,13 +439,14 @@ impl TryFrom<&str> for MFA { } } +#[allow(unused)] pub struct CheckCallCtx<'a, T> { - #[allow(unused)] + pub sema: &'a Semantic<'a>, pub mfa: &'a FunctionMatch, pub parents: &'a Vec, pub target: &'a CallTarget, pub t: &'a T, - pub args: Args, + pub args: &'a Args, pub in_clause: &'a InFunctionClauseBody<'a, &'a FunctionDef>, } @@ -470,10 +471,11 @@ impl Args { } } - pub fn as_vec(&self) -> Vec { + pub fn as_slice(&self) -> &[ExprId] { + const EMPTY_SLICE: &[ExprId] = &[]; match self { - Args::Args(args) => args.to_vec(), - Args::Arity(_arity) => vec![], + Args::Args(args) => args, + Args::Arity(_arity) => EMPTY_SLICE, } } } @@ -485,7 +487,7 @@ pub struct MatchCtx<'a, Extra> { pub sema: &'a Semantic<'a>, pub def_fb: &'a InFunctionClauseBody<'a, &'a FunctionDef>, pub target: &'a CallTarget, - pub args: Args, + pub args: &'a Args, /// Range of the module:fun part of an MFA, if not defined in a /// macro. pub range_surface_mf: Option, @@ -549,29 +551,30 @@ pub(crate) fn find_call_in_function( } && let None = excluded_matcher.get_match( &target, args.arity(), - Some(&args.as_vec()), + Some(args.as_slice()), sema, &def_fb.body(clause_id), ) && let Some((mfa, t)) = matcher.get_match( &target, args.arity(), - Some(&args.as_vec()), + Some(args.as_slice()), sema, &def_fb.body(clause_id), ) { let in_clause = &def_fb.in_clause(clause_id); let context = CheckCallCtx { + sema, mfa, parents: ctx.parents, t, target: &target, - args: args.clone(), + args: &args, in_clause, }; if let Some(extra) = check_call(context) { // Got one. - let call_expr_id = if let Some(expr_id) = ctx.in_macro { - expr_id.idx + let call_expr_id = if let Some((hir_idx, _macro_def)) = ctx.in_macro { + hir_idx.idx } else { ctx.item_id }; @@ -586,7 +589,7 @@ pub(crate) fn find_call_in_function( sema, def_fb: in_clause, target: &target, - args, + args: &args, extra: &extra, range_surface_mf, range: *range, @@ -602,6 +605,42 @@ pub(crate) fn find_call_in_function( Some(()) } +/// Helper function to create a fix that replaces the module name in a remote call. +/// This is useful for linters that need to rename module references (e.g., replacing +/// `old_module:function()` with `new_module:function()`). +/// +/// # Arguments +/// * `match_context` - The match context from the FunctionCallLinter +/// * `file_id` - The file being analyzed +/// * `new_module_name` - The new module name to replace with +/// * `fix_id` - A unique identifier for this fix (e.g., "rename_module_to_new_name") +/// * `fix_label` - A human-readable label for the fix (e.g., "Rename to new_module") +/// +/// # Returns +/// An `Assist` that replaces just the module name, or `None` if the target is not a +/// remote call or if the module range is in a different file. +pub fn make_module_rename_fix( + match_context: &MatchCtx, + file_id: FileId, + new_module_name: &str, + fix_id: &'static str, + fix_label: &str, +) -> Option { + use elp_ide_db::source_change::SourceChangeBuilder; + + let module_range = match_context.target.module_range(match_context.def_fb)?; + + let mut builder = SourceChangeBuilder::new(file_id); + builder.replace(module_range.range, new_module_name.to_string()); + + Some(crate::fix( + fix_id, + fix_label, + builder.finish(), + module_range.range, + )) +} + // --------------------------------------------------------------------- #[cfg(test)] @@ -752,9 +791,9 @@ mod tests { bar(Config) -> foo:fire_bombs(Config), - %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message foo:fire_bombs(Config, zz). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message "#, ) } @@ -768,9 +807,9 @@ mod tests { bar(Config) -> foo:fire_bombs(Config), - %% ^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message foo:fire_bombs(Config, zz). - %% ^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message "#, ) } @@ -786,7 +825,7 @@ mod tests { bar(Config) -> ?MY_MACRO(Config). - %% ^^^^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message "#, ) } @@ -803,7 +842,7 @@ mod tests { bar(Config) -> ?MY_MACRO(Config). - %% ^^^^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message //- /src/inc.hrl -define(MY_MACRO(A), fun() -> foo:fire_bombs(A) end). @@ -820,7 +859,7 @@ mod tests { bar(Node) -> spawn(Node, mod, fff, []). - %% ^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message "#, ) } @@ -836,13 +875,13 @@ mod tests { erlang:spawn(fun() -> ok end), spawn(fun() -> ok end), erlang:spawn(Node, fun() -> ok end), - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message spawn(Node, fun() -> ok end), - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message erlang:spawn(Node, mod, fff, []), - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message spawn(Node, mod, fff, []). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message "#, ) } @@ -857,7 +896,7 @@ mod tests { bar() -> erlang:spawn(), - %% ^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message spawn(). "#, ) @@ -872,11 +911,11 @@ mod tests { bar() -> foo:bar(), - %% ^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message foo:bar(x), - %% ^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message foo:bar(x,y), - %% ^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message baz:bar(). "#, ) @@ -891,10 +930,10 @@ mod tests { bar() -> foo:bar(), - %% ^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message baz:bar(x), foo:florgle(x,y). - %% ^^^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message "#, ) } @@ -908,11 +947,11 @@ mod tests { bar() -> foo:bar(), - %% ^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message baz:bar(x), - %% ^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message local(x,y). - %% ^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message local(A,B) -> {A,B}. "#, ) @@ -927,7 +966,7 @@ mod tests { bar() -> fo~o:bar(). - %% ^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message "#, expect![[r#" -module(main). @@ -947,7 +986,7 @@ mod tests { -module(main). foo(Node, M,F,A) -> rpc:c~all(Node, M, F, A). - %% ^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message "#, expect![[r#" -module(main). @@ -966,7 +1005,7 @@ mod tests { -module(main). foo(Node, M,F,A) -> baz(rpc:c~all(Node, M, F, A)). - %% ^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Diagnostic Message + %% ^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: ad-hoc: test: Diagnostic Message "#, expect![[r#" -module(main). diff --git a/crates/ide/src/common_test.rs b/crates/ide/src/common_test.rs index eea87c4422..a5441efd28 100644 --- a/crates/ide/src/common_test.rs +++ b/crates/ide/src/common_test.rs @@ -346,7 +346,7 @@ mod tests { a(_Config) -> ok. b(_Config) -> -%% ^ 💡 error: Unreachable test (b/1) +%% ^ 💡 error: W0008: Unreachable test (b/1) ok. "#, ); @@ -368,7 +368,7 @@ mod tests { a(_Config) -> ok. b(_Config) -> -%% ^ 💡 error: Unreachable test (b/1) +%% ^ 💡 error: W0008: Unreachable test (b/1) ok. "#, ); @@ -391,7 +391,7 @@ mod tests { a(_Config) -> ok. b(_Config) -> -%% ^ 💡 error: Unreachable test (b/1) +%% ^ 💡 error: W0008: Unreachable test (b/1) ok. "#, ); @@ -413,7 +413,7 @@ mod tests { b(_Config) -> ok. c(_Config) -> -%% ^ 💡 error: Unreachable test (c/1) +%% ^ 💡 error: W0008: Unreachable test (c/1) ok. "#, ); @@ -434,7 +434,7 @@ mod tests { b(_Config) -> ok. c(_Config) -> -%% ^ 💡 error: Unreachable test (c/1) +%% ^ 💡 error: W0008: Unreachable test (c/1) ok. "#, ); @@ -453,10 +453,10 @@ mod tests { a(_Config) -> ok. b(_Config) -> - %% ^ 💡 error: Unreachable test (b/1) + %% ^ 💡 error: W0008: Unreachable test (b/1) ok. c(_Config) -> - %% ^ 💡 error: Unreachable test (c/1) + %% ^ 💡 error: W0008: Unreachable test (c/1) ok. "#, ); @@ -501,7 +501,7 @@ c(_Config) -> -export([all/0]). -export([a/1, b/1, c/1]). all() -> my_external_helper:all(). -%% ^^^ warning: Could not evaluate function. No code lenses for tests will be available. +%% ^^^ warning: W0021: Could not evaluate function. No code lenses for tests will be available. a(_Config) -> ok. b(_Config) -> @@ -522,9 +522,9 @@ c(_Config) -> -export([all/0, groups/0]). -export([a/1, b/1, c/1]). all() -> [a]. -%% ^^^ warning: Could not evaluate function. No code lenses for tests will be available. +%% ^^^ warning: W0021: Could not evaluate function. No code lenses for tests will be available. groups() -> my_external_helper:groups(). -%% ^^^^^^ warning: Could not evaluate function. No code lenses for tests will be available. +%% ^^^^^^ warning: W0021: Could not evaluate function. No code lenses for tests will be available. a(_Config) -> ok. b(_Config) -> @@ -550,7 +550,7 @@ c(_Config) -> a(_Config) -> ok. b(_Config) -> -%% ^ 💡 error: Unreachable test (b/1) +%% ^ 💡 error: W0008: Unreachable test (b/1) ok. //- /my_app/src/my_behaviour.erl -module(my_behaviour). diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 22edc1205e..eb6bae611b 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs @@ -11,6 +11,7 @@ use std::borrow::Cow; use std::collections::BTreeSet; use std::fmt; +use std::path::Path; use std::sync::Arc; use anyhow::Result; @@ -38,15 +39,18 @@ 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; @@ -63,11 +67,12 @@ 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; @@ -92,13 +97,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; @@ -108,12 +113,14 @@ 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 +// @fb-only: mod meta_only; mod missing_compile_warn_missing_spec; +mod missing_module; mod missing_separator; mod misspelled_attribute; mod module_mismatch; @@ -125,6 +132,7 @@ 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; @@ -132,6 +140,7 @@ 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; @@ -149,6 +158,7 @@ mod unused_record_field; pub use elp_ide_db::DiagnosticCode; pub use from_config::Lint; pub use from_config::LintsFromConfig; +pub use from_config::MatchSsr; pub use from_config::ReplaceCall; pub use from_config::ReplaceCallAction; pub use replace_call::Replacement; @@ -223,8 +233,9 @@ impl Diagnostic { self } - pub(crate) fn as_related(&self) -> RelatedInformation { + pub(crate) fn as_related(&self, file_id: FileId) -> RelatedInformation { RelatedInformation { + file_id, range: self.range, message: self.message.clone(), } @@ -375,10 +386,10 @@ impl Diagnostic { format!( "{}:{}-{}:{}::[{:?}] [{}] {}", - start.line, - start.col_utf16, - end.line, - end.col_utf16, + start.line + 1, + start.col_utf16 + 1, + end.line + 1, + end.col_utf16 + 1, self.severity(use_cli_severity), self.code, self.message @@ -443,6 +454,7 @@ impl Diagnostic { #[derive(Debug, Clone)] pub struct RelatedInformation { + pub file_id: FileId, pub range: TextRange, pub message: String, } @@ -457,9 +469,10 @@ impl fmt::Display for Diagnostic { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] 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 @@ -469,12 +482,6 @@ 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, @@ -504,13 +511,13 @@ pub(crate) trait Linter { fn description(&self) -> &'static str; // The severity for the lint issue. It defaults to `Warning`. - fn severity(&self) -> Severity { + fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { Severity::Warning } // For CLI, when using the --use-cli-severity flag. It defaults to `severity()` - fn cli_severity(&self) -> Severity { - self.severity() + fn cli_severity(&self, sema: &Semantic, file_id: FileId) -> Severity { + self.severity(sema, file_id) } // Specify if the linter issues can be suppressed via a `% elp:ignore` comment. @@ -544,12 +551,48 @@ 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()) + .unwrap_or_else(|| linter.is_enabled()) + } else { + linter.is_enabled() + }; + if !is_enabled { + return false; + } + let include_tests = if let Some(lint_config) = config.lint_config.as_ref() { lint_config .get_include_tests_override(&linter.id()) @@ -849,6 +892,7 @@ pub(crate) trait GenericLinter: Linter { fn fixes( &self, _context: &Self::Context, + _range: TextRange, _sema: &Semantic, _file_id: FileId, ) -> Option> { @@ -882,7 +926,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, sema, file_id); + let fixes = self.fixes(&matched.context, matched.range, sema, file_id); let tag = self.tag(&matched.context); let mut d = Diagnostic::new(self.id(), message, matched.range) .with_fixes(fixes) @@ -1037,7 +1081,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); + allowed_diagnostics.insert(diagnostic_filter.clone()); } // Make sure the enabled ones win out over disabled if a lint appears in both @@ -1055,6 +1099,13 @@ 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) } @@ -1091,15 +1142,31 @@ impl DiagnosticsConfig { } pub fn enable(mut self, code: DiagnosticCode) -> DiagnosticsConfig { - self.enabled.enable(code); + self.enabled.enable(code.clone()); + self.set_linter_enabled(code, true); self } pub fn disable(mut self, code: DiagnosticCode) -> DiagnosticsConfig { - self.disabled.insert(code); + self.disabled.insert(code.clone()); + self.set_linter_enabled(code, false); 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, @@ -1129,6 +1196,34 @@ 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 + } + /// Get the severity override for a linter based on its diagnostic code pub fn get_severity_override(&self, diagnostic_code: &DiagnosticCode) -> Option { self.linters.get(diagnostic_code)?.severity @@ -1149,6 +1244,16 @@ 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, @@ -1200,9 +1305,43 @@ 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 { @@ -1210,17 +1349,61 @@ 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 { + #[serde(rename = "enabled")] + pub is_enabled: Option, pub severity: Option, 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 @@ -1372,14 +1555,8 @@ 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() @@ -1387,7 +1564,7 @@ pub fn native_diagnostics( config .lints_from_config .get_diagnostics(&mut res, &sema, file_id); - // @fb-only + // @fb-only: meta_only::diagnostics(&mut res, &sema, file_id, file_kind, config); syntax_diagnostics(&sema, &parse, &mut res, file_id); diagnostics_from_descriptors( &mut res, @@ -1416,6 +1593,7 @@ 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 @@ -1424,6 +1602,7 @@ 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 { @@ -1452,22 +1631,12 @@ 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, ] } @@ -1484,20 +1653,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) { - 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); - } + 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); } - } else { - (descriptor.checker)(res, sema, file_id, file_kind); } } }); @@ -1539,10 +1708,28 @@ 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]; +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, +]; /// Unified registry for all types of linters pub(crate) fn linters() -> Vec { @@ -1570,7 +1757,7 @@ pub(crate) fn linters() -> Vec { ); // Add meta-only linters - // @fb-only + // @fb-only: all_linters.extend(meta_only::linters()); all_linters } @@ -1587,25 +1774,26 @@ 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, is_generated, is_test) + && should_run(linter, config, &app_name, 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()) + .unwrap_or_else(|| linter.severity(sema, file_id)) } else { - linter.severity() + linter.severity(sema, file_id) }; 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()) + .unwrap_or_else(|| linter.cli_severity(sema, file_id)) } else { - linter.cli_severity() + linter.cli_severity(sema, file_id) }; match l { DiagnosticLinter::FunctionCall(function_linter) => { @@ -1705,13 +1893,12 @@ fn widen_range(range: TextRange) -> TextRange { } } -pub fn syntax_diagnostics( +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); @@ -1722,32 +1909,180 @@ pub fn filter_diagnostics(diagnostics: Vec, code: DiagnosticCode) -> diagnostics.into_iter().filter(|d| d.code == code).collect() } -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 +/// 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) } - ast::Form::FileAttribute(_) => { - continue; // skip + 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::ModuleAttribute(_) => { - break; + FormIdx::Spec(spec_id) => { + let (_, body_map) = sema + .db + .spec_body_with_source(InFile::new(file_id, *spec_id)); + Some(body_map) } - other_form => { - report(other_form.syntax().text_range()); - break; + FormIdx::Callback(callback_id) => { + let (_, body_map) = sema + .db + .callback_body_with_source(InFile::new(file_id, *callback_id)); + Some(body_map) } + 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 { @@ -1868,6 +2203,47 @@ pub(crate) fn make_unexpected_diagnostic( .with_severity(Severity::Warning) } +/// Deduplicate diagnostics by line start and add ignore fix only to the first diagnostic on each line. +/// This prevents duplicate ignore fix suggestions when multiple diagnostics occur on the same line. +pub(crate) fn add_ignore_fix_deduplicated( + diagnostics: &mut Vec, + temp_diagnostics: Vec, + sema: &Semantic, + file_id: FileId, +) { + let parsed = sema.parse(file_id); + let mut diagnostics_by_line_start: FxHashMap> = FxHashMap::default(); + + for diagnostic in temp_diagnostics { + let line_start_offset = if let Some(token) = parsed + .value + .syntax() + .token_at_offset(diagnostic.range.start()) + .right_biased() + { + start_of_line(&token).into() + } else { + diagnostic.range.start().into() + }; + + diagnostics_by_line_start + .entry(line_start_offset) + .or_default() + .push(diagnostic); + } + + for (_, mut diags_on_line) in diagnostics_by_line_start { + if let Some(first_diag) = diags_on_line.first_mut() { + *first_diag = std::mem::replace( + first_diag, + Diagnostic::new(DiagnosticCode::default(), "", TextRange::default()), + ) + .with_ignore_fix(sema, file_id); + } + diagnostics.extend(diags_on_line); + } +} + #[derive(Debug, PartialEq, Eq)] pub enum RemoveElpReported { Yes, @@ -1901,51 +2277,54 @@ 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)) + .filter_map(|d| parse_error_to_diagnostic_info(db, file_id, d, &mut related_info_map)) .for_each(|val| { error_info.insert(val); }); res.warnings .iter() - .filter_map(|d| parse_error_to_diagnostic_info(db, file_id, d)) + .filter_map(|d| parse_error_to_diagnostic_info(db, file_id, d, &mut related_info_map)) .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)| { - ( - file_id, - tag_erlang_service_diagnostic( - Diagnostic::new( - DiagnosticCode::ErlangService(code), - msg, - TextRange::new(start, end), - ) - .with_severity(Severity::Error), - ), - ) + to_diagnostic(file_id, start, end, code, msg, Severity::Error) }) .chain( warning_info .into_iter() .map(|(file_id, start, end, code, msg)| { - ( - file_id, - tag_erlang_service_diagnostic( - Diagnostic::new( - DiagnosticCode::ErlangService(code), - msg, - TextRange::new(start, end), - ) - .with_severity(warning_severity), - ), - ) + to_diagnostic(file_id, start, end, code, msg, warning_severity) }), ) .collect(); @@ -1962,11 +2341,14 @@ 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) + !d.should_be_suppressed(&metadata, config) + && !config.disabled.contains(&d.code) + && should_process_app(&app_name, config, &d.code) }) .map(|(file_id, d)| { ( @@ -2257,7 +2639,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 + // @fb-only: meta_only::ct_diagnostics(&mut res, &sema, file_id, testcases); } CommonTestInfo::EvalError(_error) => { // The error currently does not contain anything useful, so we ignore it @@ -2334,20 +2716,68 @@ 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 { - directive_location, + file_attribute_location, + error_path, error_location, - }) => 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(), - ) - }), + }) => { + // 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(), + ) + }, + ) + } + } Some(DiagnosticLocation::Normal(range)) => { let default_range = ( file_id, @@ -2357,11 +2787,13 @@ 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(), @@ -2374,7 +2806,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(), @@ -2385,7 +2817,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(), @@ -2395,7 +2827,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(), @@ -2405,7 +2837,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(), @@ -2415,7 +2847,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(), @@ -2438,6 +2870,22 @@ 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, @@ -2522,13 +2970,13 @@ fn type_alias_name_range( pub fn included_file_file_id( db: &RootDatabase, file_id: FileId, - directive_range: TextRange, + file_attribute_location: 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().contains(directive_range.start()) { + if form.syntax().text_range().start() >= file_attribute_location.start() { db.resolve_include(InFile::new(file_id, idx)) } else { None @@ -2537,6 +2985,30 @@ 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 @@ -2559,6 +3031,7 @@ 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 { @@ -2594,7 +3067,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()).collect_vec(); + let related_info = related.iter().map(|d| d.as_related(file_id)).collect_vec(); syntax_error_diags .iter() .map(|d| d.clone().with_related(Some(related_info.clone()))) @@ -2615,10 +3088,90 @@ pub fn attach_related_diagnostics( .filter(|(k, _)| !undefineds_to_remove.contains(k)) .flat_map(|(_, v)| v); - native - .normal - .into_iter() - .chain(erlang_service.normal) + // 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) .chain(syntax_errors_with_related) .chain(erlang_service_undefined_not_related.cloned()) // TODO:AZ: consider returning an iterator @@ -2683,9 +3236,10 @@ mod tests { fn syntax_error() { check_diagnostics( r#" +//- expect_parse_errors -module(main). foo() -> XX 3.0. - %% ^^ error: Syntax Error + %% ^^ error: P1711: Syntax Error "#, ); } @@ -2696,7 +3250,7 @@ foo() -> XX 3.0. r#" -module(main). -export([foo/0 bar/1]). - %% ^ warning: Missing ',' + %% ^ warning: W0004: Missing ',' "#, ); } @@ -2707,7 +3261,7 @@ foo() -> XX 3.0. r#" -module(main). -export_type([foo/0 bar/1]). - %% ^ warning: Missing ',' + %% ^ warning: W0004: Missing ',' "#, ); } @@ -2718,7 +3272,7 @@ foo() -> XX 3.0. r#" -module(main). -import(bb, [foo/0 bar/1]). - %% ^ warning: Missing ',' + %% ^ warning: W0004: Missing ',' "#, ); } @@ -2729,7 +3283,7 @@ foo() -> XX 3.0. r#" -module(main). -type foo(A B) :: [A,B]. - %% ^ warning: Missing ',' + %% ^ warning: W0004: Missing ',' "#, ); } @@ -2740,7 +3294,7 @@ foo() -> XX 3.0. r#" -module(main). -record(foo {f1, f2 = 3}). - %% ^^^ warning: Missing ',' + %% ^^^ warning: W0004: Missing ',' main(X) -> {X#foo.f1, X#foo.f2}. "#, @@ -2772,53 +3326,6 @@ 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: no module definition -"#, - ); - } - - #[test] - fn fun_decl_module_decl_missing_2() { - check_diagnostics( - r#" - baz(1)->4. -%%^^^^^^^^^^ error: 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()); @@ -2881,7 +3388,7 @@ baz(1)->4. do_foo() -> X = foo:bar(), - %% ^^^^^^^^^ 💡 weak: 'foo:bar/0' called + %% ^^^^^^^^^ 💡 weak: ad-hoc: foo:bar/0: 'foo:bar/0' called X. //- /src/foo.erl -module(foo). @@ -2907,10 +3414,11 @@ baz(1)->4. #[test] fn label_syntax_error_not_function() { let fixture_str = r#" - -module(main). - -record(person, {(name + XXX)}). -%% ^^^^^^^ error: Syntax Error -%% ^ error: Syntax Error + //- expect_parse_errors + -module(main). + -record(person, {(name + XXX)}). + %% ^^^^^^^ error: P1711: Syntax Error + %% ^ error: P1711: Syntax Error "#; check_diagnostics(fixture_str); let diagnostic = Diagnostic::error( @@ -2922,7 +3430,7 @@ baz(1)->4. expect![[r#" Some( Range( - 20..52, + 5..45, ), ) "#]] @@ -2934,7 +3442,7 @@ baz(1)->4. check_diagnostics( r#" baz(1)->4. -%%^^^^^^^^^^ error: no module definition +%%^^^^^^^^^^ 💡 error: L1201: no module definition foo(2)->3. "#, ); @@ -2958,7 +3466,7 @@ baz(1)->4. %% elp:ignore L1201 baz(1)->4. -%%^^^^^^^^^^ error: no module definition +%%^^^^^^^^^^ 💡 error: L1201: no module definition foo(2)->3. "#, ); @@ -2972,7 +3480,7 @@ baz(1)->4. baz()-> Foo = 1, - %%^^^ 💡 warning: match is redundant + %%^^^ 💡 warning: W0007: match is redundant % elp:ignore W0007 Bar = 2, ok. @@ -2988,11 +3496,11 @@ baz(1)->4. baz()-> Foo = 1, - %%^^^ 💡 warning: match is redundant + %%^^^ 💡 warning: W0007: match is redundant % elp:ignore W0007 Bar = 2, - %%^^^ 💡 warning: match is redundant + %%^^^ 💡 warning: W0007: match is redundant ok. "#, ); @@ -3005,7 +3513,7 @@ baz(1)->4. //- edoc //- /main/src/main_edoc.erl app:main % @unknown - %%<^^^^^^^^ warning: tag @unknown not recognized. + %%<^^^^^^^^ warning: O0039: tag @unknown not recognized. -module(main_edoc). "#, @@ -3081,6 +3589,7 @@ baz(1)->4. config, &extra_diags, r#" + //- expect_parse_errors -module(main). -export([foo/0,bar/0]). @@ -3090,7 +3599,10 @@ baz(1)->4. -spec foo() -> ok. foo( -> ok. %% - %% ^ error: Missing ')' + %% ^ 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 "#, ); } @@ -3098,7 +3610,7 @@ baz(1)->4. #[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_projects/diagnostics/app_a/src/syntax.erl + // spec, same code as in test/test_projects/diagnostics/app_a/src/syntax.erl check_diagnostics( r#" -module(main). @@ -3115,12 +3627,14 @@ baz(1)->4. 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: syntax error before: error + %% ^^^^^ error: P1711: syntax error before: error + %% | Related info: 0:25-30 function foo/0 undefined "#, ); } @@ -3132,6 +3646,7 @@ baz(1)->4. check_diagnostics( r#" //- erlang_service + //- expect_parse_errors //- native //- /src/a_mod.erl app:app_a -module(a_mod). @@ -3139,10 +3654,10 @@ baz(1)->4. foo() -> bar(). - %% ^^^^^ error: function bar/0 undefined + %% ^^^^^ error: L1227: function bar/0 undefined bar() -> !!! %% syntax error - %%<^^^^^^^^^ error: Syntax Error + %%<^^^^^^^^^ error: P1711: Syntax Error "#, ); } @@ -3156,7 +3671,7 @@ baz(1)->4. baz()-> Fo~o = 1. - %%^^^ 💡 warning: match is redundant + %%^^^ 💡 warning: W0007: match is redundant "#, expect![[r#" -module(main). @@ -3200,7 +3715,7 @@ baz(1)->4. -spec baz() -> ok. baz() -> something_else. - %% ^^^^^^^^^^^^^^ 💡 error: eqwalizer: incompatible_types + %% ^^^^^^^^^^^^^^ 💡 error: eqwalizer: incompatible_types: eqwalizer: incompatible_types "#, ); } @@ -3210,6 +3725,7 @@ baz(1)->4. fn test_nested_syntax_errors() { check_diagnostics( r#" + //- expect_parse_errors -module(main). run() -> ExitCode = @@ -3218,9 +3734,9 @@ baz(1)->4. to_exit_code(run1(Root)), catch _:Reason -> to_exit_code(Reason) - %% ^^^^^^^^^^^ error: Syntax Error + %% ^^^^^^^^^^^ error: P1711: Syntax Error end, - %% ^^^ error: Syntax Error + %% ^^^ error: P1711: Syntax Error erlang:halt(ExitCode). "#, @@ -3234,7 +3750,7 @@ baz(1)->4. //- erlang_service -module(main). -export([foo/0, bar/0]). -%% ^^^^^ error: function bar/0 undefined +%% ^^^^^ error: L1227: function bar/0 undefined foo() -> ok. "#, ); @@ -3247,7 +3763,7 @@ baz(1)->4. //- erlang_service -module(main). -export_type([foo/0, bar/3]). -%% ^^^^^ error: type bar/3 undefined +%% ^^^^^ error: L1295: type bar/3 undefined -type foo() :: integer(). "#, ); @@ -3261,7 +3777,7 @@ baz(1)->4. -module(main). -export([foo/0]). -spec bar() -> ok. -%% ^^^ error: spec for undefined function bar/0 +%% ^^^ error: L1308: spec for undefined function bar/0 foo() -> ok. "#, ); @@ -3275,7 +3791,7 @@ baz(1)->4. -module(main). -type foo() :: ok. -%% ^^^ warning: type foo() is unused +%% ^^^ warning: L1296: type foo() is unused "#, ); @@ -3285,7 +3801,7 @@ baz(1)->4. -module(main). -type foo(A, B) :: {A, B}. -%% ^^^ warning: type foo(_,_) is unused +%% ^^^ warning: L1296: type foo(_,_) is unused "#, ); } @@ -3353,7 +3869,7 @@ baz(1)->4. -module(a_file). -doc {file,"../../doc/src/info.md"}. - %% ^^^^^^^^^^^^^^^^^^^^^^^ warning: can't find doc file "../../doc/src/info.md" + %% ^^^^^^^^^^^^^^^^^^^^^^^ warning: E1599: can't find doc file "../../doc/src/info.md" "#, ); @@ -3369,7 +3885,7 @@ baz(1)->4. -module(erlang). -doc {file,"../../doc/src/info.md"}. - %% ^^^^^^^^^^^^^^^^^^^^^^^ warning: can't find doc file "../../doc/src/info.md" + %% ^^^^^^^^^^^^^^^^^^^^^^^ warning: E1599: can't find doc file "../../doc/src/info.md" "#, ); } @@ -3392,6 +3908,37 @@ baz(1)->4. ); } + #[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( @@ -3423,7 +3970,8 @@ baz(1)->4. foo() -> \~"\"\\µA\"" = \~/"\\µA"/ X = 3. - %% ^ error: syntax error before: X + %% ^ error: P1711: syntax error before: X + %% | Related info: 0:32-37 function foo/0 undefined "#, ); } @@ -3459,7 +4007,7 @@ baz(1)->4. -export([foo/0]). % @docc - %%<^^^^^ warning: tag @docc not recognized. + %%<^^^^^ warning: O0039: tag @docc not recognized. foo() -> \~"foo". "#, ); @@ -3486,10 +4034,12 @@ baz(1)->4. lint_config.linters.insert( DiagnosticCode::NoGarbageCollect, LinterConfig { + is_enabled: None, severity: Some(Severity::Error), include_tests: None, include_generated: None, experimental: None, + exclude_apps: None, config: None, }, ); @@ -3512,7 +4062,7 @@ baz(1)->4. -spec error() -> ok. error() -> erlang:garbage_collect(). - %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 error: Avoid forcing garbage collection. + %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 error: 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]). @@ -3527,10 +4077,12 @@ baz(1)->4. lint_config.linters.insert( DiagnosticCode::NoGarbageCollect, LinterConfig { + is_enabled: None, severity: None, include_tests: Some(true), include_generated: None, experimental: None, + exclude_apps: None, config: None, }, ); @@ -3552,7 +4104,7 @@ baz(1)->4. warning() -> erlang:garbage_collect(). - %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Avoid forcing garbage collection. + %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 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]). @@ -3567,10 +4119,12 @@ baz(1)->4. lint_config.linters.insert( DiagnosticCode::NoGarbageCollect, LinterConfig { + is_enabled: None, severity: None, include_tests: None, include_generated: Some(true), experimental: None, + exclude_apps: None, config: None, }, ); @@ -3593,7 +4147,7 @@ baz(1)->4. warning() -> erlang:garbage_collect(). - %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Avoid forcing garbage collection. + %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 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]). @@ -3608,10 +4162,12 @@ baz(1)->4. lint_config.linters.insert( DiagnosticCode::NoGarbageCollect, LinterConfig { + is_enabled: None, severity: None, include_tests: None, include_generated: None, experimental: Some(true), + exclude_apps: None, config: None, }, ); @@ -3644,4 +4200,245 @@ baz(1)->4. ), ); } + + #[test] + fn test_linter_is_enabled_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: None, + 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 + -module(main). + -export([warning/0]). + + 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]). + garbage_collect() -> ok. + "#, + ); + } + + #[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 dac88b260c..615b7801f9 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 +// @fb-only: use crate::diagnostics; 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: true, + include_tests: false, 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 + // @fb-only: diagnostics::meta_only::application_env_bad_matches(), ] .into_iter() .flatten() @@ -265,11 +265,11 @@ mod tests { get_mine() -> application:get_env(misc, key). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: module `main` belongs to app `my_app`, but reads env for `misc` + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0011: module `main` belongs to app `my_app`, but reads env for `misc` get_mine3() -> application:get_env(misc, key, def). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: module `main` belongs to app `my_app`, but reads env for `misc` + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0011: module `main` belongs to app `my_app`, but reads env for `misc` //- /my_app/src/application.erl -module(application). @@ -302,7 +302,7 @@ mod tests { steal() -> application:get_env(debug, key). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: module `app_env` belongs to app `misc`, but reads env for `debug` + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0011: module `app_env` belongs to app `misc`, but reads env for `debug` //- /misc/src/application.erl app:misc -module(application). @@ -324,7 +324,7 @@ mod tests { get_mine() -> ?get(misc, key). - %% ^^^^^^^^^^^^^^^ 💡 warning: module `main` belongs to app `my_app`, but reads env for `misc` + %% ^^^^^^^^^^^^^^^ 💡 warning: W0011: module `main` belongs to app `my_app`, but reads env for `misc` //- /my_app/include/my_header.hrl app:my_app -define(get(K,V), application:get_env(K,V)). diff --git a/crates/ide/src/diagnostics/atoms_exhaustion.rs b/crates/ide/src/diagnostics/atoms_exhaustion.rs index bb15bebc2c..56a43a50ca 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 +// @fb-only: use crate::diagnostics; 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 + // @fb-only: fn should_process_file_id(&self, sema: &Semantic, file_id: FileId) -> bool { fn should_process_file_id(&self, _sema: &Semantic, _file_id: FileId) -> bool { // @oss-only - // @fb-only + // @fb-only: diagnostics::meta_only::is_relevant_file(sema.db.upcast(), file_id) true // @oss-only } } @@ -56,19 +56,19 @@ impl FunctionCallLinter for AtomsExhaustionLinter { // FunctionMatch::mfa("erlang", "binary_to_term", 2), ] .into_iter() - // @fb-only + // @fb-only: .chain(diagnostics::meta_only::atoms_exhaustion_matches().into_iter()) .collect::>() ] } fn check_match(&self, context: &CheckCallCtx<'_, ()>) -> Option { #[rustfmt::skip] - // @fb-only - // @fb-only - // @fb-only + // @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); let is_safe = false; // @oss-only if !is_safe { - match context.args.as_vec()[..] { + match context.args.as_slice() { [_, options] => { let body = context.in_clause.body(); match &body[options].literal_list_contains_atom(context.in_clause, "safe") { @@ -100,9 +100,9 @@ mod tests { -export([main/0]). main() -> erlang:list_to_atom(foo), -%% ^^^^^^^^^^^^^^^^^^^ 💡 warning: Risk of atoms exhaustion. +%% ^^^^^^^^^^^^^^^^^^^ 💡 warning: W0023: Risk of atoms exhaustion. list_to_atom(foo). -%% ^^^^^^^^^^^^ 💡 warning: Risk of atoms exhaustion. +%% ^^^^^^^^^^^^ 💡 warning: W0023: Risk of atoms exhaustion. //- /opt/lib/stdlib-3.17/src/erlang.erl otp_app:/opt/lib/stdlib-3.17 -module(erlang). @@ -121,9 +121,9 @@ mod tests { -export([main/0]). main() -> erlang:binary_to_atom(foo), -%% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Risk of atoms exhaustion. +%% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0023: Risk of atoms exhaustion. binary_to_atom(foo). -%% ^^^^^^^^^^^^^^ 💡 warning: Risk of atoms exhaustion. +%% ^^^^^^^^^^^^^^ 💡 warning: W0023: Risk of atoms exhaustion. //- /opt/lib/stdlib-3.17/src/erlang.erl otp_app:/opt/lib/stdlib-3.17 -module(erlang). diff --git a/crates/ide/src/diagnostics/binary_string_to_sigil.rs b/crates/ide/src/diagnostics/binary_string_to_sigil.rs index d87d206583..91b08f9d1d 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) -> Severity { + fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { Severity::WeakWarning } @@ -143,7 +143,7 @@ mod tests { -module(binary_string_to_sigil). fn() -> <<"hello">>. - %% ^^^^^^^^^^^ 💡 weak: Binary string can be written using sigil syntax. + %% ^^^^^^^^^^^ 💡 weak: W0051: Binary string can be written using sigil syntax. "#, ) } diff --git a/crates/ide/src/diagnostics/boolean_precedence.rs b/crates/ide/src/diagnostics/boolean_precedence.rs index 86650651f7..f8f7851f8a 100644 --- a/crates/ide/src/diagnostics/boolean_precedence.rs +++ b/crates/ide/src/diagnostics/boolean_precedence.rs @@ -15,6 +15,7 @@ // 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; @@ -24,11 +25,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; @@ -45,29 +46,107 @@ use hir::fold::MacroStrategy; use hir::fold::ParenStrategy; use hir::fold::ParentId; -use super::Diagnostic; -use super::DiagnosticConditions; -use super::DiagnosticDescriptor; -use super::Severity; +use super::GenericLinter; +use super::GenericLinterMatchContext; +use super::Linter; +use crate::Assist; use crate::fix; -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); - }, -}; +pub(crate) struct BooleanPrecedenceLinter; -fn boolean_precedence(diagnostics: &mut Vec, sema: &Semantic, file_id: FileId) { - sema.for_each_function(file_id, |def| check_function(diagnostics, sema, def)); +impl Linter for BooleanPrecedenceLinter { + fn id(&self) -> DiagnosticCode { + DiagnosticCode::BooleanPrecedence + } + + fn description(&self) -> &'static str { + "boolean precedence" + } } -fn check_function(diagnostics: &mut Vec, sema: &Semantic, def: &FunctionDef) { +#[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, +) { let def_fb = def.in_function_body(sema, def); def_fb.clone().fold_function( Strategy { @@ -91,28 +170,20 @@ fn check_function(diagnostics: &mut Vec, sema: &Semantic, def: &Func _ => None, }; if let Some(op) = op { - report( - sema, - &def_fb, - def.file.file_id, - clause_id, - ctx, - op, - diagnostics, - ); + collect_match(matches, sema, &def_fb, def.file.file_id, clause_id, ctx, op); } }, ) } -fn report( +fn collect_match( + matches: &mut Vec>, 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) @@ -156,39 +227,25 @@ fn report( let (_op, token) = binop_ast.op()?; let range = token.text_range(); let preceding_ws_range = include_preceding_whitespace(&token); - 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); + + matches.push(GenericLinterMatchContext { + range, + context: Context { + preceding_ws_range, + op: binop, + lhs_complex, + rhs_complex, + add_parens_range, + }, + }); } }; Some(()) } -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)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] enum Op { + #[default] And, AndInGuard, Or, @@ -223,31 +280,7 @@ impl Op { } } -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, - )])) -} +pub static LINTER: BooleanPrecedenceLinter = BooleanPrecedenceLinter; #[cfg(test)] mod tests { @@ -275,7 +308,7 @@ mod tests { foo() -> F = fun(X) -> my_is_integer(X) and X > 0 end, - %% ^^^ 💡 warning: Consider using the short-circuit expression 'andalso' instead of 'and'. + %% ^^^ 💡 warning: W0025: Consider using the short-circuit expression 'andalso' instead of 'and'. %% | Or add parentheses to avoid potential ambiguity. F. @@ -317,7 +350,7 @@ mod tests { -module(main). foo(X) -> predicate(X) or X > 10. - %% ^^ 💡 warning: Consider using the short-circuit expression 'orelse' instead of 'or'. + %% ^^ 💡 warning: W0025: Consider using the short-circuit expression 'orelse' instead of 'or'. %% | Or add parentheses to avoid potential ambiguity. predicate(_X) -> false. @@ -332,7 +365,7 @@ mod tests { -module(main). foo(S,P) -> (S or P > 3). - %% ^^ 💡 warning: Consider using the short-circuit expression 'orelse' instead of 'or'. + %% ^^ 💡 warning: W0025: Consider using the short-circuit expression 'orelse' instead of 'or'. %% | Or add parentheses to avoid potential ambiguity. "#, ) @@ -345,7 +378,7 @@ mod tests { -module(main). foo(S,P) -> ((S or P > 3)). - %% ^^ 💡 warning: Consider using the short-circuit expression 'orelse' instead of 'or'. + %% ^^ 💡 warning: W0025: Consider using the short-circuit expression 'orelse' instead of 'or'. %% | Or add parentheses to avoid potential ambiguity. "#, ) @@ -360,7 +393,7 @@ mod tests { foo() -> F = fun(X) -> my_is_integer(X) a~nd X > 0 end, - %% ^^^ 💡 warning: Consider using the short-circuit expression 'andalso' instead of 'and'. + %% ^^^ 💡 warning: W0025: Consider using the short-circuit expression 'andalso' instead of 'and'. %% | Or add parentheses to avoid potential ambiguity. F. @@ -388,7 +421,7 @@ mod tests { foo() -> F = fun(X) -> my_is_integer(X) a~nd X > 0 end, - %% ^^^ 💡 warning: Consider using the short-circuit expression 'andalso' instead of 'and'. + %% ^^^ 💡 warning: W0025: Consider using the short-circuit expression 'andalso' instead of 'and'. %% | Or add parentheses to avoid potential ambiguity. F. @@ -412,7 +445,7 @@ mod tests { -module(main). foo(X) when X < 10 a~nd X > 0 -> X + 1. - %% ^^^ 💡 warning: Consider using the short-circuit expression ',' instead of 'and'. + %% ^^^ 💡 warning: W0025: Consider using the short-circuit expression ',' instead of 'and'. %% | Or add parentheses to avoid potential ambiguity. "#, expect![[r#" @@ -432,7 +465,7 @@ mod tests { foo() -> F = fun(X) -> my_is_integer(X) a~nd X > 0 end, - %% ^^^ 💡 warning: Consider using the short-circuit expression 'andalso' instead of 'and'. + %% ^^^ 💡 warning: W0025: Consider using the short-circuit expression 'andalso' instead of 'and'. %% | Or add parentheses to avoid potential ambiguity. F. @@ -457,7 +490,7 @@ mod tests { foo() -> F = fun(X) -> X < 0 o~r X > 10 end, - %% ^^ 💡 warning: Consider using the short-circuit expression 'orelse' instead of 'or'. + %% ^^ 💡 warning: W0025: Consider using the short-circuit expression 'orelse' instead of 'or'. %% | Or add parentheses to avoid potential ambiguity. F. @@ -481,7 +514,7 @@ mod tests { -module(main). foo(X) -> predicate(X) o~r X > 10. - %% ^^ 💡 warning: Consider using the short-circuit expression 'orelse' instead of 'or'. + %% ^^ 💡 warning: W0025: Consider using the short-circuit expression 'orelse' instead of 'or'. %% | Or add parentheses to avoid potential ambiguity. predicate(_X) -> false."#, diff --git a/crates/ide/src/diagnostics/bound_variable.rs b/crates/ide/src/diagnostics/bound_variable.rs new file mode 100644 index 0000000000..92f0edadfa --- /dev/null +++ b/crates/ide/src/diagnostics/bound_variable.rs @@ -0,0 +1,178 @@ +/* + * 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 73b596e0c9..03ea0e6274 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) -> Severity { + fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { Severity::Information } } @@ -265,7 +265,7 @@ mod tests { -module(main). fn() -> list_to_binary("foo"). - %% ^^^^^^^^^^^^^^^^^^^^^ 💡 information: Could be rewritten as a binary string literal. + %% ^^^^^^^^^^^^^^^^^^^^^ 💡 information: W0055: Could be rewritten as a binary string literal. //- /src/erlang.erl -module(erlang). @@ -293,7 +293,7 @@ mod tests { -module(main). fn() -> ~"foo". - + "#]], ) } @@ -306,7 +306,7 @@ mod tests { -module(main). fn() -> erlang:list_to_binary("foo"). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 information: Could be rewritten as a binary string literal. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 information: W0055: Could be rewritten as a binary string literal. //- /src/erlang.erl -module(erlang). @@ -347,7 +347,7 @@ mod tests { -module(main). fn() -> list_to_atom("foo"). - %% ^^^^^^^^^^^^^^^^^^^ 💡 information: Could be rewritten as an atom literal. + %% ^^^^^^^^^^^^^^^^^^^ 💡 information: W0055: Could be rewritten as an atom literal. //- /src/erlang.erl -module(erlang). @@ -388,7 +388,7 @@ mod tests { -module(main). fn() -> erlang:list_to_atom("foo"). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 information: Could be rewritten as an atom literal. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 information: W0055: Could be rewritten as an atom literal. //- /src/erlang.erl -module(erlang). @@ -429,7 +429,7 @@ mod tests { -module(main). fn() -> atom_to_binary(foo). - %% ^^^^^^^^^^^^^^^^^^^ 💡 information: Could be rewritten as a binary string literal. + %% ^^^^^^^^^^^^^^^^^^^ 💡 information: W0055: Could be rewritten as a binary string literal. //- /src/erlang.erl -module(erlang). @@ -470,7 +470,7 @@ mod tests { -module(main). fn() -> erlang:atom_to_binary(foo). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 information: Could be rewritten as a binary string literal. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 information: W0055: Could be rewritten as a binary string literal. //- /src/erlang.erl -module(erlang). @@ -511,7 +511,7 @@ mod tests { -module(main). fn() -> atom_to_list(foo). - %% ^^^^^^^^^^^^^^^^^ 💡 information: Could be rewritten as a string literal. + %% ^^^^^^^^^^^^^^^^^ 💡 information: W0055: Could be rewritten as a string literal. //- /src/erlang.erl -module(erlang). @@ -552,7 +552,7 @@ mod tests { -module(main). fn() -> erlang:atom_to_list(foo). - %% ^^^^^^^^^^^^^^^^^^^^^^^^ 💡 information: Could be rewritten as a string literal. + %% ^^^^^^^^^^^^^^^^^^^^^^^^ 💡 information: W0055: Could be rewritten as a string literal. //- /src/erlang.erl -module(erlang). diff --git a/crates/ide/src/diagnostics/cross_node_eval.rs b/crates/ide/src/diagnostics/cross_node_eval.rs index a61c058a40..f50ca663e3 100644 --- a/crates/ide/src/diagnostics/cross_node_eval.rs +++ b/crates/ide/src/diagnostics/cross_node_eval.rs @@ -12,6 +12,9 @@ //! //! 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; @@ -28,7 +31,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) -> Severity { + fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { Severity::Error } fn should_process_test_files(&self) -> bool { @@ -111,7 +114,7 @@ mod tests { foo(Node) -> erlang:spawn(Node, fun() -> ok end). - %% ^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) } @@ -124,7 +127,7 @@ mod tests { foo(Node) -> spawn(Node, fun() -> ok end). - %% ^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -138,7 +141,7 @@ mod tests { foo(Node) -> erlang:spawn(Node, modu, ff, []). - %% ^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -152,7 +155,7 @@ mod tests { foo(Node) -> spawn(Node, modu, ff, []). - %% ^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -168,7 +171,7 @@ mod tests { foo(Node) -> erlang:spawn_link(Node, fun() -> ok end). - %% ^^^^^^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) } @@ -181,7 +184,7 @@ mod tests { foo(Node) -> spawn_link(Node, fun() -> ok end). - %% ^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -195,7 +198,7 @@ mod tests { foo(Node) -> erlang:spawn_link(Node, modu, ff, []). - %% ^^^^^^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -209,7 +212,7 @@ mod tests { foo(Node) -> spawn_link(Node, modu, ff, []). - %% ^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -225,7 +228,7 @@ mod tests { foo(Node) -> erlang:spawn_monitor(Node, fun() -> ok end). - %% ^^^^^^^^^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) } @@ -238,7 +241,7 @@ mod tests { foo(Node) -> spawn_monitor(Node, fun() -> ok end). - %% ^^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -252,7 +255,7 @@ mod tests { foo(Node) -> erlang:spawn_monitor(Node, modu, ff, []). - %% ^^^^^^^^^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -266,7 +269,7 @@ mod tests { foo(Node) -> spawn_monitor(Node, modu, ff, []). - %% ^^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -282,7 +285,7 @@ mod tests { foo(Node) -> erlang:spawn_opt(Node, fun() -> ok end, []). - %% ^^^^^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) } @@ -295,7 +298,7 @@ mod tests { foo(Node) -> spawn_opt(Node, fun() -> ok end, []). - %% ^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -309,7 +312,7 @@ mod tests { foo(Node) -> erlang:spawn_opt(Node, modu, ff, [], []). - %% ^^^^^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -323,7 +326,7 @@ mod tests { foo(Node) -> spawn_opt(Node, modu, ff, [], []). - %% ^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -337,9 +340,9 @@ mod tests { foo(Node) -> erts_internal_dist:dist_spawn_request(Node, fun() -> ok end), - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) erts_internal_dist:dist_spawn_request(Node, modu, ff, [], []). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -353,9 +356,9 @@ mod tests { foo(Node) -> rpc:call(Node, mod, func, []), - %% ^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) rpc:multicall([Node], mod, func, []). - %% ^^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -369,9 +372,9 @@ mod tests { foo(Name, FuncSpec) -> sys:install(Name, FuncSpec), - %% ^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) sys:install(Name, FuncSpec, 500). - %% ^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, ) @@ -401,7 +404,7 @@ mod tests { foo(Name, FuncSpec) -> sys:inst~all(Name, FuncSpec). - %% ^^^^^^^^^^^^^ 💡 error: Production code must not use cross node eval (e.g. `rpc:call()`) + %% ^^^^^^^^^^^^^ 💡 error: W0014: Production code must not use cross node eval (e.g. `rpc:call()`) "#, expect![[r#" diff --git a/crates/ide/src/diagnostics/debugging_function.rs b/crates/ide/src/diagnostics/debugging_function.rs index cdeb147754..1f0099781d 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_text_edit::TextRange; +use elp_ide_db::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 +// @fb-only: use crate::diagnostics::meta_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) -> Severity { + fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { Severity::WeakWarning } - fn cli_severity(&self) -> Severity { + fn cli_severity(&self, _sema: &Semantic, _file_id: FileId) -> 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 + // @fb-only: .chain(meta_only::debugging_function_matches().into_iter()) .collect::>() ] } @@ -113,9 +113,9 @@ mod tests { error() -> redbug:start("io:format/2->return", []), -%% ^^^^^^^^^^^^ 💡 weak: Debugging functions should only be used during local debugging and usages should not be checked in. +%% ^^^^^^^^^^^^ 💡 weak: W0041: Debugging functions should only be used during local debugging and usages should not be checked in. redbug:stop(). -%% ^^^^^^^^^^^ 💡 weak: Debugging functions should only be used during local debugging and usages should not be checked in. +%% ^^^^^^^^^^^ 💡 weak: W0041: Debugging functions should only be used during local debugging and usages should not be checked in. noerror() -> redbug(), @@ -127,7 +127,7 @@ redbug() -> start(_) -> ok. - + //- /src/redbug.erl -module(redbug). -export([start/2, stop/0]). @@ -159,7 +159,7 @@ redbug(_) -> main() -> re~dbug:start("io:format/2->return", []). -%% ^^^^^^^^^^^^ 💡 weak: Debugging functions should only be used during local debugging and usages should not be checked in. +%% ^^^^^^^^^^^^ 💡 weak: W0041: Debugging functions should only be used during local debugging and usages should not be checked in. //- /src/redbug.erl -module(redbug). -export([start/2]). @@ -191,7 +191,7 @@ main() -> main() -> re~dbug:start("io:format/2->return", []), -%% ^^^^^^^^^^^^ 💡 weak: Debugging functions should only be used during local debugging and usages should not be checked in. +%% ^^^^^^^^^^^^ 💡 weak: W0041: Debugging functions should only be used during local debugging and usages should not be checked in. ok. //- /src/redbug.erl -module(redbug). diff --git a/crates/ide/src/diagnostics/dependent_header.rs b/crates/ide/src/diagnostics/dependent_header.rs index d3b786e240..4729f05872 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; @@ -119,7 +119,7 @@ mod tests { r#" //- /include/main.hrl -define(MY_MACRO, #my_record{}). -%% ^^^^^^^^^^ warning: Record 'my_record' not defined in this context +%% ^^^^^^^^^^ warning: W0015: Record 'my_record' not defined in this context "#, ) } @@ -154,7 +154,7 @@ mod tests { r#" //- /include/main.hrl -define(MY_MACRO(Record), Record#my_record.my_field). -%% ^^^^^^^^^^ warning: Record 'my_record' not defined in this context +%% ^^^^^^^^^^ warning: W0015: Record 'my_record' not defined in this context "#, ) } @@ -165,7 +165,7 @@ mod tests { r#" //- /include/main.hrl -define(MY_MACRO, #my_record.my_field). -%% ^^^^^^^^^^ warning: Record 'my_record' not defined in this context +%% ^^^^^^^^^^ warning: W0015: Record 'my_record' not defined in this context "#, ) } @@ -176,7 +176,7 @@ mod tests { r#" //- /include/main.hrl -define(MY_MACRO(Record), Record#my_record{my_field = 42}). -%% ^^^^^^^^^^ warning: Record 'my_record' not defined in this context +%% ^^^^^^^^^^ warning: W0015: Record 'my_record' not defined in this context "#, ) } diff --git a/crates/ide/src/diagnostics/deprecated_function.rs b/crates/ide/src/diagnostics/deprecated_function.rs index 3162a95954..b353d824d2 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 +// @fb-only: use crate::diagnostics; 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 + // @fb-only: diagnostics::meta_only::deprecated_function_matches(), ]; matches.into_iter() .flatten() @@ -134,14 +134,21 @@ 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(expr_id) = ctx.in_macro { - expr_id.idx + let expr_id = if let Some((hir_idx, _macro_def)) = ctx.in_macro { + hir_idx.idx } else { ctx.item_id }; if let Some(range) = def_fb.range_for_any(clause_id, expr_id) && def.file.file_id == range.file_id { + let range_mf = if ctx.in_macro.is_none() { + let in_clause = &def_fb.in_clause(clause_id); + target.range(in_clause) + } else { + None + }; + let range = range_mf.unwrap_or(range); let d = make_diagnostic(range.range, &target_def, details) .with_fixes(Some(vec![fix_xref_ignore( sema, @@ -192,7 +199,6 @@ fn make_diagnostic( .with_severity(severity) .deprecated() .with_uri(uri) - .experimental() } fn strip_quotes(s: &str) -> &str { @@ -256,7 +262,7 @@ mod tests { ok. main() -> not_ok_to_use(). -%% ^^^^^^^^^^^^^^^ 💡 warning: Function 'not_ok_to_use/0' is deprecated. +%% ^^^^^^^^^^^^^ 💡 warning: W0016: Function 'not_ok_to_use/0' is deprecated. "#, ) } @@ -276,7 +282,7 @@ mod tests { main() -> b:not_ok_to_use(). -%% ^^^^^^^^^^^^^^^^^ 💡 warning: Function 'not_ok_to_use/0' is deprecated. +%% ^^^^^^^^^^^^^^^ 💡 warning: W0016: Function 'not_ok_to_use/0' is deprecated. "#, ) } @@ -290,9 +296,9 @@ mod tests { -deprecated({do, 0}). main() -> do(), -%% ^^^^ 💡 warning: Function 'do/0' is deprecated. +%% ^^ 💡 warning: W0016: Function 'do/0' is deprecated. ?LAZY(do()). -%% ^^^^^^^^^^^ 💡 warning: Function 'do/0' is deprecated. +%% ^^^^^^^^^^^ 💡 warning: W0016: Function 'do/0' is deprecated. do() -> ok. "#, @@ -314,8 +320,8 @@ mod tests { main() -> b:not_ok_to_use(). -%% ^^^^^^^^^^^^^^^^^ 💡 warning: Function 'not_ok_to_use/0' is deprecated. -%% | Cause I said so. +%% ^^^^^^^^^^^^^^^ 💡 warning: W0016: Function 'not_ok_to_use/0' is deprecated. +%% | Cause I said so. "#, ) } diff --git a/crates/ide/src/diagnostics/duplicate_module.rs b/crates/ide/src/diagnostics/duplicate_module.rs index de4009cfb8..09eb548b31 100644 --- a/crates/ide/src/diagnostics/duplicate_module.rs +++ b/crates/ide/src/diagnostics/duplicate_module.rs @@ -12,51 +12,58 @@ // // 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 super::Diagnostic; -use super::DiagnosticConditions; -use super::DiagnosticDescriptor; -use crate::diagnostics::Severity; +use crate::diagnostics::DiagnosticCode; +use crate::diagnostics::GenericLinter; +use crate::diagnostics::GenericLinterMatchContext; +use crate::diagnostics::Linter; -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); - }, -}; +pub(crate) struct DuplicateModuleLinter; -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), - ); +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 } - 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; @@ -67,11 +74,11 @@ mod test { r#" //- /src/dup_mod.erl -module(dup_mod). - %% ^^^^^^^ warning: Duplicate module name + %% ^^^^^^^ 💡 warning: W0045: A module with this name exists elsewhere //- /src/sub/dup_mod.erl -module(dup_mod). - %% ^^^^^^^ warning: Duplicate module name + %% ^^^^^^^ 💡 warning: W0045: A module with this name exists elsewhere "#, ) } diff --git a/crates/ide/src/diagnostics/effect_free_statement.rs b/crates/ide/src/diagnostics/effect_free_statement.rs index a5a1a138a9..9aec815fbb 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; @@ -275,10 +275,10 @@ mod tests { test_foo(_Config) -> do_something(), ok, - %% ^^ 💡 warning: this statement has no effect + %% ^^ 💡 warning: W0006: this statement has no effect do_something_else(), bar, - %% ^^^ 💡 warning: this statement has no effect + %% ^^^ 💡 warning: W0006: this statement has no effect ok. do_something() -> ok. "#, @@ -293,7 +293,7 @@ mod tests { test_foo(_Config) -> X = 42, X, - %% ^ 💡 warning: this statement has no effect + %% ^ 💡 warning: W0006: this statement has no effect ok. "#, ); @@ -307,16 +307,16 @@ mod tests { test_foo(_Config) -> do_something(), 42, - %% ^^ 💡 warning: this statement has no effect + %% ^^ 💡 warning: W0006: this statement has no effect 41.9999, - %% ^^^^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^ 💡 warning: W0006: this statement has no effect do_something_else(), "foo", - %% ^^^^^ 💡 warning: this statement has no effect + %% ^^^^^ 💡 warning: W0006: this statement has no effect <<"foo">>, - %% ^^^^^^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^^^ 💡 warning: W0006: this statement has no effect 'A', - %% ^^^ 💡 warning: this statement has no effect + %% ^^^ 💡 warning: W0006: this statement has no effect ok. do_something() -> 42. "#, @@ -332,13 +332,13 @@ mod tests { test_foo(_Config) -> do_something(), fun() -> do_something() end, - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0006: this statement has no effect F = fun() -> do_something() end, F(), fun do_something/0, - %% ^^^^^^^^^^^^^^^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^^^^^^^^^^^^ 💡 warning: W0006: this statement has no effect fun erlang:length/1, - %% ^^^^^^^^^^^^^^^^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^^^^^^^^^^^^^ 💡 warning: W0006: this statement has no effect ok. do_something() -> 42. //- /src/erlang.erl @@ -357,7 +357,7 @@ mod tests { test_foo(_Config) -> (do_something()), (blah), - %% ^^^^^^ 💡 warning: this statement has no effect + %% ^^^^^^ 💡 warning: W0006: this statement has no effect ok. do_something() -> (abc). "#, @@ -372,13 +372,13 @@ mod tests { test_foo(_Config) -> do_something(), begin abc, blah, ("foo") end, - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: this statement has no effect - %% ^^^ 💡 warning: this statement has no effect - %% ^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0006: this statement has no effect + %% ^^^ 💡 warning: W0006: this statement has no effect + %% ^^^^ 💡 warning: W0006: this statement has no effect begin do_something(), blah, - %% ^^^^ 💡 warning: this statement has no effect + %% ^^^^ 💡 warning: W0006: this statement has no effect ok end, ok. @@ -395,10 +395,10 @@ mod tests { test_foo(_Config) -> do_something(), [42, blah, ("foo")], - %% ^^^^^^^^^^^^^^^^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^^^^^^^^^^^^^ 💡 warning: W0006: this statement has no effect [42, do_something(), blah], [], - %% ^^ 💡 warning: this statement has no effect + %% ^^ 💡 warning: W0006: this statement has no effect ok. do_something() -> []. "#, @@ -413,10 +413,10 @@ mod tests { test_foo(_Config) -> do_something(), {42, [blah], {"foo"}}, - %% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0006: this statement has no effect {42, do_something(), blah}, {}, - %% ^^ 💡 warning: this statement has no effect + %% ^^ 💡 warning: W0006: this statement has no effect ok. do_something() -> []. "#, @@ -432,11 +432,11 @@ mod tests { test_foo(P) -> do_something(), #person{name="Bob", age=42}, - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0006: this statement has no effect #person{name=get_name(), age=42}, P#person{name="Alice"}, #person.name, - %% ^^^^^^^^^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^^^^^^ 💡 warning: W0006: this statement has no effect P#person.name, ok. get_name() -> "bob". @@ -452,7 +452,7 @@ mod tests { test_foo(P) -> do_something(), #{name => "Bob", age => 42}, - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0006: this statement has no effect #{name => get_name(), age => 42}, #{get_key() => "Bob", age => 42}, P#{name=>"Alice"}, @@ -471,10 +471,10 @@ mod tests { test_foo(_P) -> catch do_something(), catch ok, - %% ^^^^^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^^ 💡 warning: W0006: this statement has no effect try does, nothing catch _ -> do_stuff() end, - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: this statement has no effect - %% ^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0006: this statement has no effect + %% ^^^^ 💡 warning: W0006: this statement has no effect try does_nothing of _ -> ok @@ -486,20 +486,20 @@ mod tests { ok end, try does, nothing after blah, ok end, - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: this statement has no effect - %% ^^^^ 💡 warning: this statement has no effect - %% ^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0006: this statement has no effect + %% ^^^^ 💡 warning: W0006: this statement has no effect + %% ^^^^ 💡 warning: W0006: this statement has no effect try does, nothing - %% ^^^^ 💡 warning: this statement has no effect + %% ^^^^ 💡 warning: W0006: this statement has no effect of _ -> foo, bar - %% ^^^ 💡 warning: this statement has no effect + %% ^^^ 💡 warning: W0006: this statement has no effect catch _ -> 42, not_ok - %% ^^ 💡 warning: this statement has no effect + %% ^^ 💡 warning: W0006: this statement has no effect after [1,2,3], - %% ^^^^^^^ 💡 warning: this statement has no effect + %% ^^^^^^^ 💡 warning: W0006: this statement has no effect ok end, ok. @@ -522,7 +522,7 @@ mod tests { blah() -> noop, - %% ^^^^ 💡 warning: this statement has no effect + %% ^^^^ 💡 warning: W0006: this statement has no effect do_something(), ?included_noop(42), do_something(), diff --git a/crates/ide/src/diagnostics/equality_check_with_unnecessary_operator.rs b/crates/ide/src/diagnostics/equality_check_with_unnecessary_operator.rs index 803f89b886..92f205f894 100644 --- a/crates/ide/src/diagnostics/equality_check_with_unnecessary_operator.rs +++ b/crates/ide/src/diagnostics/equality_check_with_unnecessary_operator.rs @@ -619,7 +619,7 @@ mod tests { fn(A, Same, Diff) -> case A =:= b of true -> Same; false -> Diff end. - %% ^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ) } @@ -633,7 +633,7 @@ mod tests { fn(A, Same, Diff) -> case A =:= b of false -> Diff; true -> Same end. - %% ^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ) } @@ -724,7 +724,7 @@ mod tests { fn(B, Same, Diff) -> case a =:= B of true -> Same; _ -> Diff end. - %% ^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ) } @@ -740,7 +740,7 @@ mod tests { fn(Same, Diff) -> case get_a() =:= foo of true -> Same; _ -> Diff end. - %% ^^^^^^^^^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^^^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ) } @@ -756,7 +756,7 @@ mod tests { fn(Same, Diff) -> case foo =:= get_b() of true -> Same; _ -> Diff end. - %% ^^^^^^^^^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^^^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ) } @@ -908,7 +908,7 @@ mod tests { fn(A, Same, Diff) -> case A =/= b of false -> Same; true -> Diff end. - %% ^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ); check_diagnostics( @@ -918,7 +918,7 @@ mod tests { fn(B, Same, Diff) -> case a =/= B of false -> Same; true -> Diff end. - %% ^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ) } @@ -932,7 +932,7 @@ mod tests { fn(A, Same, Diff) -> case A =/= b of true -> Diff; false -> Same end. - %% ^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ); check_diagnostics( @@ -942,7 +942,7 @@ mod tests { fn(B, Same, Diff) -> case a =/= B of true -> Diff; false -> Same end. - %% ^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ) } @@ -956,7 +956,7 @@ mod tests { fn(A, Same, Diff) -> case A =/= b of false -> Same; _ -> Diff end. - %% ^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ); check_diagnostics( @@ -966,7 +966,7 @@ mod tests { fn(B, Same, Diff) -> case a =/= B of false -> Same; _ -> Diff end. - %% ^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ); } @@ -982,7 +982,7 @@ mod tests { fn(Same, Diff) -> case get_a() =/= bar of false -> Same; _ -> Diff end. - %% ^^^^^^^^^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^^^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ) } @@ -998,7 +998,7 @@ mod tests { fn(Same, Diff) -> case bar =/= get_b() of false -> Same; _ -> Diff end. - %% ^^^^^^^^^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^^^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ) } @@ -1504,7 +1504,7 @@ mod tests { fn(A, Same, Diff) -> if A =:= b -> Same; true -> Diff end. - %% ^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ); check_diagnostics( @@ -1514,7 +1514,7 @@ mod tests { fn(B, Same, Diff) -> if a =:= B -> Same; true -> Diff end. - %% ^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ); } @@ -1528,7 +1528,7 @@ mod tests { fn(A, Same, Diff) -> if A =/= b -> Diff; true -> Same end. - %% ^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ); check_diagnostics( @@ -1538,7 +1538,7 @@ mod tests { fn(B, Same, Diff) -> if a =/= B -> Diff; true -> Same end. - %% ^^^^^^^💡 information: Consider rewriting to an equality match. + %% ^^^^^^^💡 information: W0042: Consider rewriting to an equality match. "#, ) } diff --git a/crates/ide/src/diagnostics/eqwalizer_assists/expected_type.rs b/crates/ide/src/diagnostics/eqwalizer_assists/expected_type.rs index ff8226b611..081f6e43ae 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_text_edit::TextEdit; -use elp_text_edit::TextSize; +use elp_ide_db::text_edit::TextEdit; +use elp_ide_db::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; @@ -192,7 +192,7 @@ mod tests { -spec baz() -> spec_atom. baz() -> something_else. - %%% ^^^^^^^^^^^^^^ 💡 error: eqwalizer: incompatible_types + %%% ^^^^^^^^^^^^^^ 💡 error: eqwalizer: incompatible_types: eqwalizer: incompatible_types "#, ) } @@ -210,7 +210,7 @@ mod tests { -spec baz() -> spec_atom. baz() -> somet~hing_else. - %% ^^^^^^^^^^^^^^ 💡 error: eqwalizer: incompatible_types + %% ^^^^^^^^^^^^^^ 💡 error: eqwalizer: incompatible_types: eqwalizer: incompatible_types "#, expect![[r#" -module(bar3e). @@ -234,7 +234,7 @@ mod tests { -spec baz() -> spec_atom. baz() -> somethin~g_else. - %% ^^^^^^^^^^^^^^ 💡 error: eqwalizer: incompatible_types + %% ^^^^^^^^^^^^^^ 💡 error: eqwalizer: incompatible_types: eqwalizer: incompatible_types "#, expect![[r#" -module(bar4e). @@ -258,7 +258,7 @@ mod tests { -spec baz() -> {ok, number()}. baz() -> 5~3. - %% ^^ 💡 error: eqwalizer: incompatible_types + %% ^^ 💡 error: eqwalizer: incompatible_types: eqwalizer: incompatible_types "#, expect![[r#" -module(bar5e). @@ -282,7 +282,7 @@ mod tests { -spec baz() -> {ok, number()}. baz() -> 5~3. - %% ^^ 💡 error: eqwalizer: incompatible_types + %% ^^ 💡 error: eqwalizer: incompatible_types: eqwalizer: incompatible_types "#, expect![[r#" -module(bar6e). @@ -306,7 +306,7 @@ mod tests { -spec foo() -> integer(). foo() -> o~k. - %% ^^ 💡 error: eqwalizer: incompatible_types + %% ^^ 💡 error: eqwalizer: incompatible_types: eqwalizer: incompatible_types "#, expect![[r#" -module(bar). diff --git a/crates/ide/src/diagnostics/eqwalizer_assists/unexported_type.rs b/crates/ide/src/diagnostics/eqwalizer_assists/unexported_type.rs index 61b4bfee32..f83361eaf0 100644 --- a/crates/ide/src/diagnostics/eqwalizer_assists/unexported_type.rs +++ b/crates/ide/src/diagnostics/eqwalizer_assists/unexported_type.rs @@ -92,7 +92,7 @@ mod tests { -module(bar). -spec baz() -> other:a_type(). - %% ^^^^^^^^^^^^^^ 💡 error: eqwalizer: non_exported_id + %% ^^^^^^^^^^^^^^ 💡 error: eqwalizer: non_exported_id: eqwalizer: non_exported_id baz() -> ok. //- /play/src/other.erl app:play diff --git a/crates/ide/src/diagnostics/expression_can_be_simplified.rs b/crates/ide/src/diagnostics/expression_can_be_simplified.rs index f941ff1738..4c9144e5c0 100644 --- a/crates/ide/src/diagnostics/expression_can_be_simplified.rs +++ b/crates/ide/src/diagnostics/expression_can_be_simplified.rs @@ -261,10 +261,19 @@ 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; + 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); + } #[test] fn test_generates_diagnostics() { @@ -273,32 +282,32 @@ mod tests { -module(main). list_ops(X) -> f([] ++ [1]), - %% ^^^^^^^^^ 💡 warning: Can be simplified to `[1]`. + %% ^^^^^^^^^ 💡 warning: W0019: Can be simplified to `[1]`. f([2] ++ [1]), f(X ++ [1]), ok. arith_ops(X) -> f(0 + 42), - %% ^^^^^^ 💡 warning: Can be simplified to `42`. + %% ^^^^^^ 💡 warning: W0019: Can be simplified to `42`. f(40 + 2), f(X + 42), ok. short_circuit_boolean_ops(X) -> f(true andalso X), - %% ^^^^^^^^^^^^^^ 💡 warning: Can be simplified to `X`. + %% ^^^^^^^^^^^^^^ 💡 warning: W0019: Can be simplified to `X`. f(false orelse X), - %% ^^^^^^^^^^^^^^ 💡 warning: Can be simplified to `X`. + %% ^^^^^^^^^^^^^^ 💡 warning: W0019: Can be simplified to `X`. f(not false), - %% ^^^^^^^^^ 💡 warning: Can be simplified to `true`. + %% ^^^^^^^^^ 💡 warning: W0019: Can be simplified to `true`. f(not true), - %% ^^^^^^^^ 💡 warning: Can be simplified to `false`. + %% ^^^^^^^^ 💡 warning: W0019: Can be simplified to `false`. true andalso X, - %% ^^^^^^^^^^^^^^ 💡 warning: Can be simplified to `X`. + %% ^^^^^^^^^^^^^^ 💡 warning: W0019: Can be simplified to `X`. ok. - + f(X) -> X. "#, diff --git a/crates/ide/src/diagnostics/from_config.rs b/crates/ide/src/diagnostics/from_config.rs index f40a8e769e..250fa4422d 100644 --- a/crates/ide/src/diagnostics/from_config.rs +++ b/crates/ide/src/diagnostics/from_config.rs @@ -10,12 +10,21 @@ //! Read a section of the config file and generate diagnostics from it. +use elp_ide_db::DiagnosticCode; +use elp_ide_db::RootDatabase; use elp_ide_db::elp_base_db::FileId; +use elp_ide_ssr::SsrRule; +use elp_ide_ssr::SsrSearchScope; +use elp_ide_ssr::match_pattern; use hir::Semantic; +use hir::Strategy; +use hir::fold::MacroStrategy; +use hir::fold::ParenStrategy; use serde::Deserialize; use serde::Serialize; use super::Diagnostic; +use super::Severity; use super::TypeReplacement; use super::replace_call; use super::replace_call::Replacement; @@ -41,6 +50,7 @@ impl LintsFromConfig { pub enum Lint { ReplaceCall(ReplaceCall), ReplaceInSpec(ReplaceInSpec), + LintMatchSsr(MatchSsr), } impl Lint { @@ -48,6 +58,7 @@ impl Lint { match self { Lint::ReplaceCall(l) => l.get_diagnostics(acc, sema, file_id), Lint::ReplaceInSpec(l) => l.get_diagnostics(acc, sema, file_id), + Lint::LintMatchSsr(l) => l.get_diagnostics(acc, sema, file_id), } } } @@ -115,12 +126,167 @@ impl ReplaceInSpec { // --------------------------------------------------------------------- +#[derive(Debug, Clone)] +pub struct MatchSsr { + pub ssr_pattern: String, + pub message: Option, + pub strategy: Option, + pub severity: Option, +} + +impl Serialize for MatchSsr { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + + let mut state = serializer.serialize_struct("MatchSsr", 5)?; + 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 + && strategy.parens == ParenStrategy::InvisibleParens; + + // Only serialize strategy if it's not the default + if !is_default { + // Serialize macro strategy + let macro_strategy = match strategy.macros { + MacroStrategy::DoNotExpand => "no-expand", + MacroStrategy::Expand => "expand", + MacroStrategy::ExpandButIncludeMacroCall => "visible-expand", + }; + state.serialize_field("macro_strategy", macro_strategy)?; + + // Serialize paren strategy + let paren_strategy = match strategy.parens { + ParenStrategy::VisibleParens => "visible", + ParenStrategy::InvisibleParens => "invisible", + }; + state.serialize_field("paren_strategy", paren_strategy)?; + } + } + state.end() + } +} + +impl<'de> Deserialize<'de> for MatchSsr { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + use serde::de::Error; + + #[derive(Deserialize)] + struct MatchSsrHelper { + ssr_pattern: String, + #[serde(default)] + message: Option, + #[serde(default)] + severity: Option, + #[serde(default)] + macro_strategy: Option, + #[serde(default)] + paren_strategy: Option, + } + + let helper = MatchSsrHelper::deserialize(deserializer)?; + + // Validate the SSR pattern by trying to parse it + // Use a minimal database for validation + let db = RootDatabase::default(); + SsrRule::parse_str(&db, &helper.ssr_pattern).map_err(|e| { + D::Error::custom(format!( + "invalid SSR pattern '{}': {}", + helper.ssr_pattern, e + )) + })?; + + // Parse strategy from strings if provided + let strategy = if helper.macro_strategy.is_some() || helper.paren_strategy.is_some() { + let macros = match helper.macro_strategy.as_deref() { + Some("no-expand") => MacroStrategy::DoNotExpand, + Some("expand") | None => MacroStrategy::Expand, + Some("visible-expand") => MacroStrategy::ExpandButIncludeMacroCall, + Some(s) => { + return Err(D::Error::custom(format!( + "invalid macro strategy '{}'. Valid options are: expand, no-expand, visible-expand", + s + ))); + } + }; + + let parens = match helper.paren_strategy.as_deref() { + Some("visible") => ParenStrategy::VisibleParens, + Some("invisible") | None => ParenStrategy::InvisibleParens, + Some(s) => { + return Err(D::Error::custom(format!( + "invalid paren strategy '{}'. Valid options are: visible, invisible", + s + ))); + } + }; + + Some(Strategy { macros, parens }) + } else { + None + }; + + Ok(MatchSsr { + ssr_pattern: helper.ssr_pattern, + message: helper.message, + strategy, + severity: helper.severity, + }) + } +} + +impl MatchSsr { + pub fn get_diagnostics(&self, acc: &mut Vec, sema: &Semantic, file_id: FileId) { + let strategy = self.strategy.unwrap_or(Strategy { + macros: MacroStrategy::Expand, + parens: ParenStrategy::InvisibleParens, + }); + + let scope = SsrSearchScope::WholeFile(file_id); + let matches = match_pattern(sema, strategy, &self.ssr_pattern, scope); + + for matched in matches.matches { + let message = self + .message + .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); + acc.push(diag); + } + } +} + +// --------------------------------------------------------------------- + #[cfg(test)] mod tests { use expect_test::expect; + use hir::Strategy; + use hir::fold::MacroStrategy; + use hir::fold::ParenStrategy; use super::Lint; use super::LintsFromConfig; + use super::MatchSsr; use super::ReplaceCall; use super::ReplaceCallAction; use super::ReplaceInSpec; @@ -492,4 +658,326 @@ mod tests { "#]] .assert_eq(&result); } + + #[test] + fn serde_serialize_match_ssr() { + let result = toml::to_string::(&MatchSsr { + ssr_pattern: "ssr: _@A = 10.".to_string(), + message: Some("Found pattern".to_string()), + strategy: None, + severity: None, + }) + .unwrap(); + expect![[r#" + ssr_pattern = "ssr: _@A = 10." + message = "Found pattern" + "#]] + .assert_eq(&result); + } + + #[test] + fn serde_deserialize_match_ssr() { + let match_ssr: MatchSsr = toml::from_str( + r#" + ssr_pattern = "ssr: _@A = 10." + message = "Found pattern" + "#, + ) + .unwrap(); + + expect![[r#" + MatchSsr { + ssr_pattern: "ssr: _@A = 10.", + message: Some( + "Found pattern", + ), + strategy: None, + severity: None, + } + "#]] + .assert_debug_eq(&match_ssr); + } + + #[test] + fn serde_serialize_lint_match_ssr() { + 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: None, + severity: None, + })], + }) + .unwrap(); + expect![[r#" + [[lints]] + type = "LintMatchSsr" + ssr_pattern = "ssr: _@A = 10." + message = "Found pattern" + "#]] + .assert_eq(&result); + } + + #[test] + fn serde_serialize_lint_match_ssr_with_strategy() { + 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::Expand, + parens: ParenStrategy::InvisibleParens, + }), + severity: None, + })], + }) + .unwrap(); + expect![[r#" + [[lints]] + type = "LintMatchSsr" + ssr_pattern = "ssr: _@A = 10." + message = "Found pattern" + "#]] + .assert_eq(&result); + } + + #[test] + fn serde_serialize_lint_match_ssr_with_non_default_strategy() { + 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: None, + })], + }) + .unwrap(); + expect![[r#" + [[lints]] + type = "LintMatchSsr" + ssr_pattern = "ssr: _@A = 10." + message = "Found pattern" + macro_strategy = "no-expand" + paren_strategy = "visible" + "#]] + .assert_eq(&result); + } + + #[test] + fn serde_deserialize_lint_match_ssr_with_strategy() { + let match_ssr: LintsFromConfig = toml::from_str( + r#" + [[lints]] + type = "LintMatchSsr" + ssr_pattern = "ssr: _@A = 10." + message = "Found pattern" + macro_strategy = "visible-expand" + paren_strategy = "visible" + "#, + ) + .unwrap(); + + expect![[r#" + LintsFromConfig { + lints: [ + LintMatchSsr( + MatchSsr { + ssr_pattern: "ssr: _@A = 10.", + message: Some( + "Found pattern", + ), + strategy: Some( + Strategy { + macros: ExpandButIncludeMacroCall, + parens: VisibleParens, + }, + ), + severity: None, + }, + ), + ], + } + "#]] + .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 259ed2853c..edfb1d8518 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,6 +270,7 @@ impl Validate for Name { attr_loc, ) .with_related(Some(vec![RelatedInformation { + file_id, range: ref_loc, message: "Mismatched clause name".to_string(), }])) @@ -293,7 +294,7 @@ impl Validate for Arity { fn make_diagnostic( self, - _file_id: FileId, + file_id: FileId, attr: &usize, hattr: &usize, attr_loc: TextRange, @@ -305,6 +306,7 @@ impl Validate for Arity { attr_loc, ) .with_related(Some(vec![RelatedInformation { + file_id, range: ref_loc, message: "Mismatched clause".to_string(), }])) @@ -393,7 +395,8 @@ mod tests { -module(main). foo(0) -> 1; boo(1) -> 2. - %% ^^^ 💡 error: head mismatch 'boo' vs 'foo' + %% ^^^ 💡 error: P1700: head mismatch 'boo' vs 'foo' + %% | Related info: 0:21-24 Mismatched clause name "#, ); check_fix( @@ -418,7 +421,8 @@ mod tests { food(0) -> ok; fooX(_X) -> - %% ^^^^ 💡 error: head mismatch 'fooX' vs 'food' + %% ^^^^ 💡 error: P1700: head mismatch 'fooX' vs 'food' + %% | Related info: 0:21-25 Mismatched clause name no. bar() -> @@ -447,7 +451,8 @@ mod tests { r#" -module(main). foo(0) -> 1; - %% ^^^ 💡 error: head mismatch 'foo' vs 'boo' + %% ^^^ 💡 error: P1700: head mismatch 'foo' vs 'boo' + %% | Related info: 0:37-40 Mismatched clause name boo(1) -> 2; boo(2) -> 3. "#, @@ -475,7 +480,8 @@ mod tests { -module(main). foo(0) -> 1; foo(1,0) -> 2. - %% ^^^^^^^^^^^^^ error: head arity mismatch 2 vs 1 + %% ^^^^^^^^^^^^^ error: P1700: head arity mismatch 2 vs 1 + %% | Related info: 0:21-32 Mismatched clause "#, ); } @@ -487,7 +493,8 @@ mod tests { -module(main). foo(2,0) -> 3; foo(0) -> 1; - %% ^^^^^^^^^^^ error: head arity mismatch 1 vs 2 + %% ^^^^^^^^^^^ error: P1700: head arity mismatch 1 vs 2 + %% | Related info: 0:21-34 Mismatched clause foo(1,0) -> 2. "#, ); @@ -513,7 +520,8 @@ mod tests { F = fun (0) -> ok; A(N) -> ok - %% ^ 💡 error: head mismatch 'A' vs '' + %% ^ 💡 error: P1700: head mismatch 'A' vs '' + %% | Related info: 0:44-53 Mismatched clause name end, F(). "#, diff --git a/crates/ide/src/diagnostics/inefficient_enumerate.rs b/crates/ide/src/diagnostics/inefficient_enumerate.rs index f09cffae61..01891974e3 100644 --- a/crates/ide/src/diagnostics/inefficient_enumerate.rs +++ b/crates/ide/src/diagnostics/inefficient_enumerate.rs @@ -261,7 +261,7 @@ mod tests { -module(inefficient_enumerate). fn(List) -> lists:zip(lists:seq(1,length(List)),List). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: Unnecessary intermediate list allocated. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: W0033: Unnecessary intermediate list allocated. "#, ) } @@ -305,7 +305,7 @@ mod tests { -module(inefficient_enumerate). fn(N, List) -> lists:zip(lists:seq(N,length(List)),List). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: Unnecessary intermediate list allocated. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: W0033: Unnecessary intermediate list allocated. "#, ) } @@ -337,7 +337,7 @@ mod tests { -module(inefficient_enumerate). fn(N, Step, List) -> lists:zip(lists:seq(N,Step,length(List)),List). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: Unnecessary intermediate list allocated. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: W0033: Unnecessary intermediate list allocated. "#, ) } diff --git a/crates/ide/src/diagnostics/inefficient_flatlength.rs b/crates/ide/src/diagnostics/inefficient_flatlength.rs index 29d2088ffc..7cc2dd14e7 100644 --- a/crates/ide/src/diagnostics/inefficient_flatlength.rs +++ b/crates/ide/src/diagnostics/inefficient_flatlength.rs @@ -138,7 +138,7 @@ mod tests { -module(inefficient_flatlength). fn(NestedList) -> length(lists:flatten(NestedList)). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: Unnecessary intermediate flat-list allocated. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: W0028: Unnecessary intermediate flat-list allocated. "#, ) } diff --git a/crates/ide/src/diagnostics/inefficient_last.rs b/crates/ide/src/diagnostics/inefficient_last.rs index e068ef614c..c120d7ca7f 100644 --- a/crates/ide/src/diagnostics/inefficient_last.rs +++ b/crates/ide/src/diagnostics/inefficient_last.rs @@ -38,6 +38,7 @@ 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); }, }; @@ -62,6 +63,24 @@ 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, @@ -192,7 +211,7 @@ mod tests { % elp:ignore W0017 (undefined_function) fn(List) -> hd(lists:reverse(List)). - %% ^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Unnecessary intermediate reverse list allocated. + %% ^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0029: Unnecessary intermediate reverse list allocated. "#, ) } @@ -225,7 +244,7 @@ mod tests { % elp:ignore W0017 (undefined_function) fn(List) -> [LastElem|_] = lists:reverse(List), LastElem. - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Unnecessary intermediate reverse list allocated. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0029: Unnecessary intermediate reverse list allocated. "#, ) } @@ -248,4 +267,50 @@ 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 new file mode 100644 index 0000000000..96743b6f28 --- /dev/null +++ b/crates/ide/src/diagnostics/lists_reverse_append.rs @@ -0,0 +1,187 @@ +/* + * 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 eb982359e2..6cd5fe2429 100644 --- a/crates/ide/src/diagnostics/macro_precedence_suprise.rs +++ b/crates/ide/src/diagnostics/macro_precedence_suprise.rs @@ -15,14 +15,12 @@ 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_text_edit::TextRange; +use elp_ide_db::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; @@ -30,92 +28,106 @@ use hir::fold::ParenStrategy; use hir::fold::ParentId; use hir::fold::fold_file_functions; -use super::Diagnostic; -use super::DiagnosticConditions; -use super::DiagnosticDescriptor; -use super::Severity; +use crate::diagnostics::DiagnosticCode; +use crate::diagnostics::GenericLinter; +use crate::diagnostics::GenericLinterMatchContext; +use crate::diagnostics::Linter; use crate::fix; -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); - }, -}; +#[derive(Debug, Default, Clone, PartialEq)] +pub(crate) struct MacroPrecedenceContext; -/// 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, - }; +pub(crate) struct MacroPrecedenceSupriseLinter; - 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 - { - // 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); - } - } - }; - }; - } - }); -} +impl Linter for MacroPrecedenceSupriseLinter { + fn id(&self) -> DiagnosticCode { + DiagnosticCode::MacroPrecedenceEscape + } -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])), - ); + fn description(&self) -> &'static str { + "The macro expansion can have unexpected precedence here" + } + + fn should_process_generated_files(&self) -> bool { + true } } -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, - ) +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) + { + 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, + }); + } + } + } + }; + }; + } + }); + 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, + ); + Some(vec![fix]) + } } +pub static LINTER: MacroPrecedenceSupriseLinter = MacroPrecedenceSupriseLinter; + #[cfg(test)] mod tests { @@ -126,6 +138,7 @@ mod tests { use crate::tests::check_diagnostics_with_config; use crate::tests::check_fix; + #[track_caller] fn check_diagnostics(fixture: &str) { let config = DiagnosticsConfig::default() .enable(DiagnosticCode::OldEdocSyntax) @@ -140,7 +153,7 @@ mod tests { -module(main). -define(MYOP(B,C), B + C). foo(A,B,C) -> A * ?MYOP(B,C). - %% ^^^^^^^^^^ 💡 warning: The macro expansion can have unexpected precedence here + %% ^^^^^^^^^^ 💡 warning: W0039: The macro expansion can have unexpected precedence here bar(B,C) -> ?MYOP(B,C). "#, ) @@ -177,7 +190,7 @@ mod tests { -define(MYOPB(B,C), ?MYOPA(B, C)). -define(MYOPC(B,C), ?MYOPB(B, C)). foo(A,B,C) -> A * ?MYOPC(B,C). - %% ^^^^^^^^^^^ 💡 warning: The macro expansion can have unexpected precedence here + %% ^^^^^^^^^^^ 💡 warning: W0039: The macro expansion can have unexpected precedence here "#, ) } diff --git a/crates/ide/src/diagnostics/map_find_to_syntax.rs b/crates/ide/src/diagnostics/map_find_to_syntax.rs index 2bb80e9307..0f4b9afe72 100644 --- a/crates/ide/src/diagnostics/map_find_to_syntax.rs +++ b/crates/ide/src/diagnostics/map_find_to_syntax.rs @@ -548,7 +548,7 @@ mod tests { fn(Found, NotFound, M) -> % elp:ignore W0017 (undefined_function) case maps:find(my_key,M) of {ok, V} -> Found; error -> NotFound end. - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^💡 warning: Unnecessary allocation of result tuple when the key is found. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^💡 warning: W0032: Unnecessary allocation of result tuple when the key is found. "#, ) } @@ -563,7 +563,7 @@ mod tests { fn(Found, NotFound, M) -> % elp:ignore W0017 (undefined_function) case maps:find({key_a,key_b},M) of {ok, V} -> Found; error -> NotFound end. - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^💡 warning: Unnecessary allocation of result tuple when the key is found. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^💡 warning: W0032: Unnecessary allocation of result tuple when the key is found. "#, ) } @@ -578,7 +578,7 @@ mod tests { fn(K, Found, NotFound, M) -> % elp:ignore W0017 (undefined_function) case maps:find(K,M) of {ok, V} -> Found; error -> NotFound end. - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^💡 warning: Unnecessary allocation of result tuple when the key is found. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^💡 warning: W0032: Unnecessary allocation of result tuple when the key is found. "#, ) } @@ -593,7 +593,7 @@ mod tests { fn(K, Found, NotFound, M) -> % elp:ignore W0017 (undefined_function) case maps:find(K,M) of {ok, V} -> Found; _ -> NotFound end. - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^💡 warning: Unnecessary allocation of result tuple when the key is found. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^💡 warning: W0032: Unnecessary allocation of result tuple when the key is found. "#, ) } diff --git a/crates/ide/src/diagnostics/map_insertion_to_syntax.rs b/crates/ide/src/diagnostics/map_insertion_to_syntax.rs index 20fef36dab..5f8c8a5398 100644 --- a/crates/ide/src/diagnostics/map_insertion_to_syntax.rs +++ b/crates/ide/src/diagnostics/map_insertion_to_syntax.rs @@ -234,7 +234,7 @@ mod tests { % elp:ignore W0017 (undefined_function) fn(K, V, Map) -> maps:put(K, V, Map). - %% ^^^^^^^^^^^^^^^^^^^💡 weak: Consider using map syntax rather than a function call. + %% ^^^^^^^^^^^^^^^^^^^💡 weak: W0030: Consider using map syntax rather than a function call. "#, ) } @@ -248,7 +248,7 @@ mod tests { % elp:ignore W0017 (undefined_function) fn(K, V, Map) -> maps:update(K, V, Map). - %% ^^^^^^^^^^^^^^^^^^^^^^💡 weak: Consider using map syntax rather than a function call. + %% ^^^^^^^^^^^^^^^^^^^^^^💡 weak: W0031: Consider using map syntax rather than a function call. "#, ) } diff --git a/crates/ide/src/diagnostics/meck.rs b/crates/ide/src/diagnostics/meck.rs index fb79f39b57..8919ddb770 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_text_edit::TextRange; -use elp_text_edit::TextSize; +use elp_ide_db::text_edit::TextRange; +use elp_ide_db::text_edit::TextSize; use hir::AnyExprId; use hir::Expr; use hir::FunctionDef; @@ -75,7 +75,7 @@ pub(crate) fn check_function(diags: &mut Vec, sema: &Semantic, def: if in_anonymous_fun(def_fb, parents) { return None; } - match args.as_vec()[..] { + match args.as_slice() { [_module] => Some(()), [_module, options] => { let body = def_fb.body(); @@ -96,7 +96,7 @@ pub(crate) fn check_function(diags: &mut Vec, sema: &Semantic, def: args, range, .. - }| match args.as_vec()[..] { + }| match args.as_slice()[..] { [module] => { if let Some(module_range) = def_fb.range_for_expr(module) { if def.file.file_id == range.file_id { @@ -253,7 +253,7 @@ mod tests { all() -> [a]. init_per_suite(Config) -> meck:new(my_module). -%% ^^^^^^^^^^^^^^^^^^^ 💡 warning: Missing no_link option. +%% ^^^^^^^^^^^^^^^^^^^ 💡 warning: W0022: Missing no_link option. a(_Config) -> ok. @@ -277,7 +277,7 @@ mod tests { all() -> [a]. init_per_group(_Group, Config) -> meck:new(my_module), -%% ^^^^^^^^^^^^^^^^^^^ 💡 warning: Missing no_link option. +%% ^^^^^^^^^^^^^^^^^^^ 💡 warning: W0022: Missing no_link option. Config. a(_Config) -> @@ -326,7 +326,7 @@ mod tests { all() -> [a]. init_per_suite(Config) -> meck:new(my_module, [passthrough, link]). -%% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Missing no_link option. +%% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0022: Missing no_link option. a(_Config) -> ok. 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 308d2890c6..dd0b677dce 100644 --- a/crates/ide/src/diagnostics/missing_compile_warn_missing_spec.rs +++ b/crates/ide/src/diagnostics/missing_compile_warn_missing_spec.rs @@ -1,10 +1,11 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * - * 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 + * 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. + * of this source tree. You may select, at your option, one of the + * above-listed licenses. */ //! Lint/fix: missing_compile_warn_missing_spec @@ -15,11 +16,12 @@ 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; @@ -36,94 +38,160 @@ use hir::known; use lazy_static::lazy_static; use super::DIAGNOSTIC_WHOLE_FILE_RANGE; -use super::Diagnostic; -use super::DiagnosticConditions; -use super::DiagnosticDescriptor; +use crate::diagnostics::GenericLinter; +use crate::diagnostics::GenericLinterMatchContext; +use crate::diagnostics::Linter; +use crate::diagnostics::Severity; use crate::fix; -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); - }, -}; +pub(crate) struct MissingCompileWarnMissingSpec; -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; - } - _ => {} +impl Linter for MissingCompileWarnMissingSpec { + fn id(&self) -> DiagnosticCode { + DiagnosticCode::MissingCompileWarnMissingSpec } - - 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); + 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." } - 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 - } - } - _ => 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(); - report_diagnostic(sema, Some(range), file_id, what, diags) + 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, } } } -#[derive(Debug, Clone, Copy, Eq, PartialEq)] +#[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 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 + } + } + _ => 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) + } + + 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 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)] enum Found { + #[default] No, WarnMissingSpec, WarnMissingSpecAll, @@ -146,43 +214,6 @@ 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 { @@ -197,8 +228,9 @@ mod tests { #[track_caller] pub(crate) fn check_fix(fixture_before: &str, fixture_after: Expect) { - let config = - DiagnosticsConfig::default().enable(DiagnosticCode::MissingCompileWarnMissingSpec); + let config = DiagnosticsConfig::default() + .disable(DiagnosticCode::NoNoWarnSuppressions) + .enable(DiagnosticCode::MissingCompileWarnMissingSpec); check_fix_with_config(config, fixture_before, fixture_after) } @@ -208,17 +240,17 @@ mod tests { fixture_before: &str, fixture_after: Expect, ) { - let config = - DiagnosticsConfig::default().enable(DiagnosticCode::MissingCompileWarnMissingSpec); + let config = DiagnosticsConfig::default() + .disable(DiagnosticCode::NoNoWarnSuppressions) + .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) - .disable(DiagnosticCode::UnspecificInclude); + .enable(DiagnosticCode::MissingCompileWarnMissingSpec); check_diagnostics_with_config(config, fixture) } @@ -233,7 +265,7 @@ mod tests { check_diagnostics( r#" //- /erl/my_app/src/main.erl - %% <<< 💡 error: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + %% <<< 💡 error: W0012: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. -module(main). @@ -249,7 +281,7 @@ mod tests { -module(main). -compile([export_all, nowarn_export_all]). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: W0012: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. "#, ) @@ -275,7 +307,7 @@ mod tests { -module(main). -compile(warn_missing_spec). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: W0012: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. "#, ) @@ -289,7 +321,7 @@ mod tests { -module(main). -compile(nowarn_missing_spec). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: W0012: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. "#, ) @@ -342,7 +374,7 @@ mod tests { -module(main). -compile(export_all). - %% ^^^^^^^^^^^^^^^^^^^^^ 💡 error: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + %% ^^^^^^^^^^^^^^^^^^^^^ 💡 error: W0012: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. -compile(nowarn_export_all). "#, ) @@ -367,19 +399,20 @@ mod tests { #[test] fn not_in_generated_file() { - check_diagnostics( + check_diagnostics(&format!( r#" //- /erl/my_app/src/main.erl %% -*- coding: utf-8 -*- %% Automatically generated, do not edit - %% @generated from blah + %% @{} 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] @@ -516,8 +549,8 @@ mod tests { "Ignore problem", r#" //- /erl/my_app/src/main.erl - ~%% <<< 💡 error: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. - + ~%% <<< 💡 error: W0012: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + -module(main). "#, @@ -535,7 +568,7 @@ mod tests { "Ignore problem", r#" //- /erl/my_app/src/main.erl - ~%% <<< 💡 error: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + ~%% <<< 💡 error: W0012: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. %% a comment at the %% top of the file @@ -559,7 +592,7 @@ mod tests { "Ignore problem", r#" //- /erl/my_app/src/main.erl - ~%% <<< 💡 error: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. + ~%% <<< 💡 error: W0012: Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced. %% a comment at the %% top of the file diff --git a/crates/ide/src/diagnostics/missing_module.rs b/crates/ide/src/diagnostics/missing_module.rs new file mode 100644 index 0000000000..3fcbbf0fb7 --- /dev/null +++ b/crates/ide/src/diagnostics/missing_module.rs @@ -0,0 +1,132 @@ +/* + * 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/missing_separator.rs b/crates/ide/src/diagnostics/missing_separator.rs index f5c8713cae..1783b6d3d8 100644 --- a/crates/ide/src/diagnostics/missing_separator.rs +++ b/crates/ide/src/diagnostics/missing_separator.rs @@ -148,7 +148,7 @@ mod tests { r#" -module(main). foo(1)->2 - %% ^ warning: Missing ';' + %% ^ warning: W0004: Missing ';' foo(2)->3. "#, ); @@ -161,7 +161,7 @@ mod tests { -module(main). foo(1)->2; foo(2)->3 - %% ^ warning: Missing ';' + %% ^ warning: W0004: Missing ';' foo(3)->4. "#, ); @@ -174,7 +174,7 @@ mod tests { -module(main). foo(1)->2; foo(2)->3 - %% ^ warning: Missing '.' + %% ^ warning: W0004: Missing '.' "#, ); } @@ -186,7 +186,7 @@ mod tests { -module(main). foo(1)->2; foo(2)->3. - %% ^ warning: Unexpected '.' + %% ^ warning: W0018: Unexpected '.' foo(3)->4. "#, ); @@ -199,7 +199,7 @@ mod tests { -module(main). foo(1)->2; foo(2)->3; - %% ^ warning: Unexpected ';' + %% ^ warning: W0018: Unexpected ';' "#, ); } diff --git a/crates/ide/src/diagnostics/misspelled_attribute.rs b/crates/ide/src/diagnostics/misspelled_attribute.rs index b61d3ac635..15ad1dd9d8 100644 --- a/crates/ide/src/diagnostics/misspelled_attribute.rs +++ b/crates/ide/src/diagnostics/misspelled_attribute.rs @@ -10,16 +10,18 @@ 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::Diagnostic; +use super::DiagnosticCode; +use super::GenericLinter; +use super::GenericLinterMatchContext; +use super::Linter; +use crate::Assist; use crate::TextRange; use crate::TextSize; -use crate::diagnostics::RelatedInformation; +use crate::diagnostics::Severity; use crate::fix; // Diagnostic: misspelled_attribute @@ -34,26 +36,91 @@ use crate::fix; // ``` // -include_lib("/foo/bar/baz.hrl"). // ``` -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)| { + +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); let parsed_file = sema.db.parse(file_id); - let attr_form = attr.form_id.get(&parsed_file.tree()); - diagnostics.push(make_diagnostic( - sema, - file_id, - attr, - attr_form, - suggested_rename, - )) - }) + 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, + )]) + } } const KNOWN_ATTRIBUTES: &[&str] = &[ @@ -85,7 +152,7 @@ const KNOWN_ATTRIBUTES: &[&str] = &[ "doc", ]; -fn looks_like_misspelling(attr: &Attribute) -> Option<&str> { +fn looks_like_misspelling(attr: &hir::Attribute) -> Option<&str> { let mut suggestions: Vec<(&str, f64)> = KNOWN_ATTRIBUTES .iter() .filter(|&known| &attr.name != known) @@ -103,47 +170,7 @@ fn looks_like_misspelling(attr: &Attribute) -> Option<&str> { .copied() } -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) -} +pub static LINTER: MisspelledAttributeLinter = MisspelledAttributeLinter; // To run the tests via cargo // cargo test --package elp_ide --lib @@ -162,7 +189,7 @@ mod tests { r#" -module(main). -dyalizer({nowarn_function, f/0}). - %%% ^^^^^^^^ 💡 error: misspelled attribute, saw 'dyalizer' but expected 'dialyzer' + %%% ^^^^^^^^ 💡 error: W0013: misspelled attribute, saw 'dyalizer' but expected 'dialyzer' "#, ); check_fix( @@ -222,7 +249,7 @@ mod tests { r#" -module(main). -module_doc """ -%%% ^^^^^^^^^^ 💡 error: misspelled attribute, saw 'module_doc' but expected 'moduledoc' +%%% ^^^^^^^^^^ 💡 error: W0013: misspelled attribute, saw 'module_doc' but expected 'moduledoc' Hola """. "#, @@ -235,7 +262,7 @@ mod tests { r#" -module(main). -docs """ -%%% ^^^^ 💡 error: misspelled attribute, saw 'docs' but expected 'doc' +%%% ^^^^ 💡 error: W0013: misspelled attribute, saw 'docs' but expected 'doc' Hola """. foo() -> ok. diff --git a/crates/ide/src/diagnostics/module_mismatch.rs b/crates/ide/src/diagnostics/module_mismatch.rs index f6f7a2405c..77181b55ef 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; @@ -79,7 +79,7 @@ mod tests { r#" //- /src/foo.erl -module(bar). -%% ^^^ 💡 error: Module name (bar) does not match file name (foo) +%% ^^^ 💡 error: W0001: Module name (bar) does not match file name (foo) "#, ); check_fix( diff --git a/crates/ide/src/diagnostics/mutable_variable.rs b/crates/ide/src/diagnostics/mutable_variable.rs index 42a698eaa4..6878c90d57 100644 --- a/crates/ide/src/diagnostics/mutable_variable.rs +++ b/crates/ide/src/diagnostics/mutable_variable.rs @@ -27,12 +27,8 @@ // 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; @@ -60,21 +56,7 @@ fn mutable_variable_bug( sema: &Semantic, file_id: FileId, ) -> Option<()> { - 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 - }); - }); + let bound_vars_by_function = sema.bound_vars_by_function(file_id); sema.def_map(file_id) .get_function_clauses() .for_each(|(_, def)| { @@ -129,7 +111,7 @@ test() -> One = 1, Result = One = Zero, -%% ^^^^^^^^^^^^^^^^^^^ error: Possible mutable variable bug +%% ^^^^^^^^^^^^^^^^^^^ error: W0005: Possible mutable variable bug Result. "#, @@ -137,7 +119,7 @@ test() -> } #[test] - fn mutable_variable_mutliple_clauses() { + fn mutable_variable_multiple_clauses() { check_diagnostics( r#" //- /src/test.erl @@ -155,8 +137,8 @@ push_eligible(ProductPlatform, _Pu) -> false; push_eligible(_ProductPlatform, Pu) -> AppVersion = ABUserInfo = Pu, -%% ^^^^^^^^^^ 💡 warning: match is redundant -%% ^^^^^^^^^^ 💡 warning: match is redundant +%% ^^^^^^^^^^ 💡 warning: W0007: match is redundant +%% ^^^^^^^^^^ 💡 warning: W0007: match is redundant false. "#, diff --git a/crates/ide/src/diagnostics/no_catch.rs b/crates/ide/src/diagnostics/no_catch.rs index eeffcc002e..a804f248bd 100644 --- a/crates/ide/src/diagnostics/no_catch.rs +++ b/crates/ide/src/diagnostics/no_catch.rs @@ -8,7 +8,8 @@ * above-listed licenses. */ -use elp_ide_db::DiagnosticCode; +// Diagnostic: no-catch +use elp_ide_db::elp_base_db::FileId; use elp_syntax::AstNode; use hir::AnyExpr; use hir::AnyExprId; @@ -20,28 +21,48 @@ use hir::Strategy; use hir::fold::MacroStrategy; use hir::fold::ParenStrategy; -use super::DiagnosticConditions; -use super::DiagnosticDescriptor; -use crate::diagnostics::Diagnostic; -use crate::diagnostics::Severity; +use crate::diagnostics::DiagnosticCode; +use crate::diagnostics::GenericLinter; +use crate::diagnostics::GenericLinterMatchContext; +use crate::diagnostics::Linter; -const DIAGNOSTIC_CODE: DiagnosticCode = DiagnosticCode::NoCatch; -const DIAGNOSTIC_MESSAGE: &str = "Avoid `catch`."; -const DIAGNOSTIC_SEVERITY: Severity = Severity::Warning; +pub(crate) struct NoCatchLinter; -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)); - }, -}; +impl Linter for NoCatchLinter { + fn id(&self) -> DiagnosticCode { + DiagnosticCode::NoCatch + } -fn check_function(diagnostics: &mut Vec, sema: &Semantic, def: &FunctionDef) { + 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, +) { let def_fb = def.in_function_body(sema, def); def_fb.fold_function( Strategy { @@ -52,15 +73,19 @@ fn check_function(diagnostics: &mut Vec, sema: &Semantic, def: &Func &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(diagnostic) = make_diagnostic(sema, &map, ctx.item_id) { - diagnostics.push(diagnostic); + if let Some(match_context) = make_match_context(sema, &map, ctx.item_id) { + matches.push(match_context); } }; }, ) } -fn make_diagnostic(sema: &Semantic, map: &BodySourceMap, item_id: AnyExprId) -> Option { +fn make_match_context( + sema: &Semantic, + map: &BodySourceMap, + item_id: AnyExprId, +) -> Option> { match item_id { AnyExprId::Expr(expr_id) => { let ast_ptr = map.expr(expr_id)?; @@ -68,9 +93,7 @@ fn make_diagnostic(sema: &Semantic, map: &BodySourceMap, item_id: AnyExprId) -> elp_syntax::ast::Expr::CatchExpr(catch_expr) => { let catch_keyword = catch_expr.syntax().first_token()?; let range = catch_keyword.text_range(); - let diagnostic = Diagnostic::new(DIAGNOSTIC_CODE, DIAGNOSTIC_MESSAGE, range) - .with_severity(DIAGNOSTIC_SEVERITY); - Some(diagnostic) + Some(GenericLinterMatchContext { range, context: () }) } _ => None, } @@ -93,7 +116,7 @@ mod tests { catcher(X,Y) -> case catch X/Y of - %% ^^^^^ warning: 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 ec67123aa9..9a671e6c65 100644 --- a/crates/ide/src/diagnostics/no_dialyzer_attribute.rs +++ b/crates/ide/src/diagnostics/no_dialyzer_attribute.rs @@ -8,50 +8,55 @@ * above-listed licenses. */ -use elp_ide_db::DiagnosticCode; +// Diagnostic: no-dialyzer-attribute use elp_ide_db::elp_base_db::FileId; use hir::Semantic; use hir::known; -use crate::diagnostics::Diagnostic; -use crate::diagnostics::DiagnosticConditions; -use crate::diagnostics::DiagnosticDescriptor; -use crate::diagnostics::Severity; +use crate::diagnostics::DiagnosticCode; +use crate::diagnostics::GenericLinter; +use crate::diagnostics::GenericLinterMatchContext; +use crate::diagnostics::Linter; -const DIAGNOSTIC_CODE: DiagnosticCode = DiagnosticCode::NoDialyzerAttribute; -const DIAGNOSTIC_MESSAGE: &str = "Avoid -dialyzer attribute."; -const DIAGNOSTIC_SEVERITY: Severity = Severity::Warning; +pub(crate) struct NoDialyzerAttributeLinter; -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); - }, -}; +impl Linter for NoDialyzerAttributeLinter { + fn id(&self) -> DiagnosticCode { + DiagnosticCode::NoDialyzerAttribute + } -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); - } - }); + fn description(&self) -> &'static str { + "Avoid using the -dialyzer attribute." + } + + fn should_process_test_files(&self) -> bool { + false + } } -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) +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) + } } +pub static LINTER: NoDialyzerAttributeLinter = NoDialyzerAttributeLinter; + #[cfg(test)] mod tests { @@ -63,7 +68,7 @@ mod tests { r#" -module(main). -dialyzer({nowarn_function, foo/0}). - %% ^^^^^^^^^ warning: Avoid -dialyzer attribute. + %% ^^^^^^^^^ 💡 warning: W0048: Avoid using the -dialyzer attribute. "#, ) } diff --git a/crates/ide/src/diagnostics/no_error_logger.rs b/crates/ide/src/diagnostics/no_error_logger.rs index b48ccf115c..46f3d15e3e 100644 --- a/crates/ide/src/diagnostics/no_error_logger.rs +++ b/crates/ide/src/diagnostics/no_error_logger.rs @@ -8,6 +8,9 @@ * 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; @@ -23,9 +26,12 @@ impl Linter for NoErrorLoggerLinter { fn description(&self) -> &'static str { "The `error_logger` module is deprecated." } - fn severity(&self) -> Severity { + fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { Severity::Error } + fn should_process_test_files(&self) -> bool { + false + } } impl FunctionCallLinter for NoErrorLoggerLinter { @@ -50,7 +56,7 @@ mod tests { //- /src/main.erl -module(main). foo() -> error_logger:error_msg("ops"). - %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 error: The `error_logger` module is deprecated. + %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 error: W0053: The `error_logger` module is deprecated. //- /src/error_logger.erl -module(error_logger). -export([error_msg/1]). @@ -67,7 +73,7 @@ mod tests { -module(main). -import(error_logger, [error_msg/1]). foo() -> error_msg("ops"). - %% ^^^^^^^^^^^^^^^^ 💡 error: The `error_logger` module is deprecated. + %% ^^^^^^^^^^^^^^^^ 💡 error: W0053: The `error_logger` module is deprecated. //- /src/error_logger.erl -module(error_logger). -export([error_msg/1]). diff --git a/crates/ide/src/diagnostics/no_garbage_collect.rs b/crates/ide/src/diagnostics/no_garbage_collect.rs index e24ef7c9a9..4fcfa57257 100644 --- a/crates/ide/src/diagnostics/no_garbage_collect.rs +++ b/crates/ide/src/diagnostics/no_garbage_collect.rs @@ -50,10 +50,10 @@ mod tests { //- /src/main.erl -module(main). -export([error/0]). - + error() -> erlang:garbage_collect(). - %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Avoid forcing garbage collection. + %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 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]). @@ -69,10 +69,10 @@ mod tests { //- /src/main.erl -module(main). -export([error/0]). - + error() -> garbage_collect(). - %% ^^^^^^^^^^^^^^^ 💡 warning: Avoid forcing garbage collection. + %% ^^^^^^^^^^^^^^^ 💡 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]). diff --git a/crates/ide/src/diagnostics/no_nowarn_suppressions.rs b/crates/ide/src/diagnostics/no_nowarn_suppressions.rs index f0484f0256..a0b36f87b8 100644 --- a/crates/ide/src/diagnostics/no_nowarn_suppressions.rs +++ b/crates/ide/src/diagnostics/no_nowarn_suppressions.rs @@ -16,62 +16,63 @@ use hir::Semantic; use lazy_static::lazy_static; use regex::Regex; -use crate::diagnostics::Diagnostic; use crate::diagnostics::DiagnosticCode; -use crate::diagnostics::DiagnosticConditions; -use crate::diagnostics::DiagnosticDescriptor; -use crate::diagnostics::Severity; +use crate::diagnostics::GenericLinter; +use crate::diagnostics::GenericLinterMatchContext; +use crate::diagnostics::Linter; -const DIAGNOSTIC_CODE: DiagnosticCode = DiagnosticCode::NoNoWarnSuppressions; -const DIAGNOSTIC_MESSAGE: &str = "Do not suppress compiler warnings at module level."; -const DIAGNOSTIC_SEVERITY: Severity = Severity::Warning; +pub(crate) struct NoNoWarnSuppressionsLinter; -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(); +impl Linter for NoNoWarnSuppressionsLinter { + fn id(&self) -> DiagnosticCode { + DiagnosticCode::NoNoWarnSuppressions } - 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); - } - }, - _ => {} + 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: () }); + } + }, + _ => {} + } } } } } + Some(res) } } +pub static LINTER: NoNoWarnSuppressionsLinter = NoNoWarnSuppressionsLinter; + #[cfg(test)] mod tests { use crate::tests; @@ -82,7 +83,7 @@ mod tests { r#" -module(main). -compile(nowarn_export_all). - %% ^^^^^^^^^^^^^^^^^ 💡 warning: Do not suppress compiler warnings at module level. + %% ^^^^^^^^^^^^^^^^^ 💡 warning: W0054: Do not suppress compiler warnings at module level. "#, ) } @@ -93,7 +94,7 @@ mod tests { r#" -module(main). -compile({nowarn_unused_function, {unused_function, 1}}). - %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Do not suppress compiler warnings at module level. + %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0054: Do not suppress compiler warnings at module level. "#, ) } @@ -105,9 +106,9 @@ mod tests { -module(main). -compile([ nowarn_export_all, - %% ^^^^^^^^^^^^^^^^^ 💡 warning: Do not suppress compiler warnings at module level. + %% ^^^^^^^^^^^^^^^^^ 💡 warning: W0054: Do not suppress compiler warnings at module level. {nowarn_unused_function, {unused_function, 1}} - %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Do not suppress compiler warnings at module level. + %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0054: Do not suppress compiler warnings at module level. ]). "#, ) diff --git a/crates/ide/src/diagnostics/no_size.rs b/crates/ide/src/diagnostics/no_size.rs index d298b49cfa..87df996048 100644 --- a/crates/ide/src/diagnostics/no_size.rs +++ b/crates/ide/src/diagnostics/no_size.rs @@ -53,10 +53,10 @@ mod tests { //- /src/main.erl -module(main). foo() -> erlang:size({}). - %% ^^^^^^^^^^^ 💡 warning: Avoid using the `size/1` BIF. - + %% ^^^^^^^^^^^ 💡 warning: W0050: Avoid using the `size/1` BIF. + bar() -> size(<<>>). - %% ^^^^ 💡 warning: Avoid using the `size/1` BIF. + %% ^^^^ 💡 warning: W0050: Avoid using the `size/1` BIF. //- /opt/lib/stdlib-3.17/src/erlang.erl otp_app:/opt/lib/stdlib-3.17 -module(erlang). -export([size/1]). @@ -72,7 +72,7 @@ mod tests { //- /src/main.erl -module(main). foo() -> er~lang:size({}). - + bar() -> size(<<>>). //- /opt/lib/stdlib-3.17/src/erlang.erl otp_app:/opt/lib/stdlib-3.17 -module(erlang). diff --git a/crates/ide/src/diagnostics/nonstandard_integer_formatting.rs b/crates/ide/src/diagnostics/nonstandard_integer_formatting.rs index cb353cc63a..63b0a450cb 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; @@ -285,7 +285,7 @@ mod tests { -module(integer_literal_format). fn() -> {val, 10000}. - %% ^^^^^ 💡 information: Non-standard integer formatting. + %% ^^^^^ 💡 information: W0043: Non-standard integer formatting. "#, ) } @@ -315,7 +315,7 @@ mod tests { -module(integer_literal_format). fn() -> {val, 16#4865316F774F6C64}. - %% ^^^^^^^^^^^^^^^^^^^ 💡 information: Non-standard integer formatting. + %% ^^^^^^^^^^^^^^^^^^^ 💡 information: W0043: Non-standard integer formatting. "#, ) } @@ -345,7 +345,7 @@ mod tests { -module(integer_literal_format). fn() -> {val, 2#1011011110010001}. - %% ^^^^^^^^^^^^^^^^^^ 💡 information: Non-standard integer formatting. + %% ^^^^^^^^^^^^^^^^^^ 💡 information: W0043: Non-standard integer formatting. "#, ) } @@ -375,7 +375,7 @@ mod tests { -module(integer_literal_format). fn() -> {val, -10000}. - %% ^^^^^ 💡 information: Non-standard integer formatting. + %% ^^^^^ 💡 information: W0043: Non-standard integer formatting. "#, ) } @@ -435,7 +435,7 @@ mod tests { -module(integer_literal_format). fn() -> {val, -16#4865316F774F6C64}. - %% ^^^^^^^^^^^^^^^^^^^ 💡 information: Non-standard integer formatting. + %% ^^^^^^^^^^^^^^^^^^^ 💡 information: W0043: Non-standard integer formatting. "#, ) } @@ -465,7 +465,7 @@ mod tests { -module(integer_literal_format). fn() -> {val, -2#1011011110010001}. - %% ^^^^^^^^^^^^^^^^^^ 💡 information: Non-standard integer formatting. + %% ^^^^^^^^^^^^^^^^^^ 💡 information: W0043: Non-standard integer formatting. "#, ) } @@ -512,7 +512,7 @@ mod tests { -module(integer_literal_format). fn() -> {val, 16#4865316F7_74F6_C64}. - %% ^^^^^^^^^^^^^^^^^^^^^ 💡 information: Non-standard integer formatting. + %% ^^^^^^^^^^^^^^^^^^^^^ 💡 information: W0043: Non-standard integer formatting. "#, ) } @@ -542,7 +542,7 @@ mod tests { -module(integer_literal_format). fn() -> {val, 2#1011011_110010001}. - %% ^^^^^^^^^^^^^^^^^^^ 💡 information: Non-standard integer formatting. + %% ^^^^^^^^^^^^^^^^^^^ 💡 information: W0043: Non-standard integer formatting. "#, ) } @@ -572,7 +572,7 @@ mod tests { -module(integer_literal_format). fn() -> {val, -1000_0}. - %% ^^^^^^ 💡 information: Non-standard integer formatting. + %% ^^^^^^ 💡 information: W0043: Non-standard integer formatting. "#, ) } @@ -602,7 +602,7 @@ mod tests { -module(integer_literal_format). fn() -> {val, -16#4865316F7_74F6C64}. - %% ^^^^^^^^^^^^^^^^^^^^ 💡 information: Non-standard integer formatting. + %% ^^^^^^^^^^^^^^^^^^^^ 💡 information: W0043: Non-standard integer formatting. "#, ) } @@ -632,7 +632,7 @@ mod tests { -module(integer_literal_format). fn() -> {val, -2#101_1011110010001}. - %% ^^^^^^^^^^^^^^^^^^^ 💡 information: Non-standard integer formatting. + %% ^^^^^^^^^^^^^^^^^^^ 💡 information: W0043: Non-standard integer formatting. "#, ) } @@ -662,7 +662,7 @@ mod tests { -module(integer_literal_format). fn() -> {val, +10000}. - %% ^^^^^ 💡 information: Non-standard integer formatting. + %% ^^^^^ 💡 information: W0043: Non-standard integer formatting. "#, ) } @@ -692,7 +692,7 @@ mod tests { -module(integer_literal_format). fn() -> {val, - 10000}. - %% ^^^^^ 💡 information: Non-standard integer formatting. + %% ^^^^^ 💡 information: W0043: Non-standard integer formatting. "#, ) } diff --git a/crates/ide/src/diagnostics/edoc.rs b/crates/ide/src/diagnostics/old_edoc_syntax.rs similarity index 90% rename from crates/ide/src/diagnostics/edoc.rs rename to crates/ide/src/diagnostics/old_edoc_syntax.rs index 1f708b51ea..da4c3f2430 100644 --- a/crates/ide/src/diagnostics/edoc.rs +++ b/crates/ide/src/diagnostics/old_edoc_syntax.rs @@ -8,96 +8,138 @@ * above-listed licenses. */ -// Diagnostic: edoc +// Diagnostic: old_edoc_syntax +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_text_edit::TextRange; -use elp_text_edit::TextSize; +use elp_syntax::ast; 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::DiagnosticConditions; -use super::DiagnosticDescriptor; -use super::Severity; +use super::GenericLinter; +use super::GenericLinterMatchContext; +use super::Linter; -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"; +pub(crate) struct OldEdocSyntaxLinter; -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); - }, -}; +impl Linter for OldEdocSyntaxLinter { + fn id(&self) -> DiagnosticCode { + DiagnosticCode::OldEdocSyntax + } -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, - )); - } - } + fn description(&self) -> &'static str { + "EDoc style comments are deprecated. Please use Markdown instead." + } + + fn should_process_test_files(&self) -> bool { + false } } -fn old_edoc_syntax_diagnostic( +#[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, + }, + }); + } + } + } + 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( sema: &Semantic, file_id: FileId, - show_range: TextRange, header: &EdocHeader, start_offset: TextSize, -) -> Diagnostic { + range: TextRange, +) -> Assist { let eep59_insert_offset = match header.kind { EdocHeaderKind::Module => { helpers::moduledoc_insert_offset(sema, file_id).unwrap_or(start_offset) @@ -135,17 +177,12 @@ fn old_edoc_syntax_diagnostic( } builder.insert(eep59_insert_offset, header.to_eep59()); let source_change = builder.finish(); - 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, - } + crate::fix( + "convert_to_markdown", + "Convert to Markdown", + source_change, + range, + ) } fn author_exists(author: &str, authors: &FxHashSet) -> bool { @@ -226,7 +263,7 @@ mod tests { %% This is some license text. %%%------------------------------------------------------------------- %% @doc This is the module documentation. - %% ^^^^ 💡 warning: EDoc style comments are deprecated. Please use Markdown instead. + %% ^^^^ 💡 warning: W0038: EDoc style comments are deprecated. Please use Markdown instead. %% With some more text. %% And some more lines. %% @end @@ -248,23 +285,7 @@ mod tests { r#" -module(main). %% @doc This is the main function documentation. - %% ^^^^ 💡 warning: EDoc style comments are deprecated. Please use Markdown instead. - main() -> - dep(). - - dep() -> ok. - "#, - ) - } - - #[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: EDoc style comments are deprecated. Please use Markdown instead. + %% ^^^^ 💡 warning: W0038: EDoc style comments are deprecated. Please use Markdown instead. main() -> dep(). @@ -281,14 +302,14 @@ mod tests { -export([main/0, main/2]). %% @doc This is the main function documentation. - %% ^^^^ 💡 warning: EDoc style comments are deprecated. Please use Markdown instead. + %% ^^^^ 💡 warning: W0038: EDoc style comments are deprecated. Please use Markdown instead. %% @see main/2 for more information. -spec main() -> tuple(). main() -> main([], []). %% @doc This is the main function with two arguments documentation. - %% ^^^^ 💡 warning: EDoc style comments are deprecated. Please use Markdown instead. + %% ^^^^ 💡 warning: W0038: EDoc style comments are deprecated. Please use Markdown instead. -spec main(any(), any()) -> tuple(). main(A, B) -> {A, B}. @@ -305,7 +326,7 @@ mod tests { -export_type([my_integer/0]). %% @doc This is an incorrect type doc - %% ^^^^ 💡 warning: EDoc style comments are deprecated. Please use Markdown instead. + %% ^^^^ 💡 warning: W0038: EDoc style comments are deprecated. Please use Markdown instead. -type my_integer() :: integer(). -type my_integer2() :: integer(). @@ -333,7 +354,7 @@ mod tests { -type my_integer2() :: integer(). %% @doc These are docs for the main function - %% ^^^^ 💡 warning: EDoc style comments are deprecated. Please use Markdown instead. + %% ^^^^ 💡 warning: W0038: EDoc style comments are deprecated. Please use Markdown instead. -spec main(any(), any()) -> ok. main(A, B) -> dep(). @@ -351,7 +372,7 @@ mod tests { -export([main/0, main/2]). %% @doc This is the main function documentation. - %% ^^^^ 💡 warning: EDoc style comments are deprecated. Please use Markdown instead. + %% ^^^^ 💡 warning: W0038: EDoc style comments are deprecated. Please use Markdown instead. %% @see main/2 which is a great function to look at %% with a very long description that goes on and on -spec main() -> tuple(). @@ -359,7 +380,7 @@ mod tests { main([], []). %% @doc This is the main function with two arguments documentation. - %% ^^^^ 💡 warning: EDoc style comments are deprecated. Please use Markdown instead. + %% ^^^^ 💡 warning: W0038: EDoc style comments are deprecated. Please use Markdown instead. -spec main(any(), any()) -> tuple(). main(A, B) -> {A, B}. @@ -604,7 +625,7 @@ dep() -> ok. check_fix( r#" -module(main). -%% @d~oc +%% @d~oc %% This is some doc %% @end main() -> diff --git a/crates/ide/src/diagnostics/record_tuple_match.rs b/crates/ide/src/diagnostics/record_tuple_match.rs index 019d6a57f5..9756bfeb73 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_text_edit::TextRange; +use elp_ide_db::text_edit::TextRange; use hir::AnyExpr; use hir::FunctionDef; use hir::Literal; @@ -108,7 +108,7 @@ mod tests { tt(X) -> A = #my_rec{field1 = 4, field2 = 2}, {my_rec, Field1, _} = X, - %% ^^^^^^ warning: matching record 'my_rec' as a tuple. + %% ^^^^^^ warning: W0027: matching record 'my_rec' as a tuple. {A, Field1}. "#, ); @@ -137,7 +137,7 @@ mod tests { -record(my_rec, {field1, field2}). tt({my_rec, Field1, _}) -> - %% ^^^^^^ warning: matching record 'my_rec' as a tuple. + %% ^^^^^^ warning: W0027: matching record 'my_rec' as a tuple. A = #my_rec{field1 = 4, field2 = 2}, {A, Field1}. "#, diff --git a/crates/ide/src/diagnostics/redundant_assignment.rs b/crates/ide/src/diagnostics/redundant_assignment.rs index 1521d4117c..6351335533 100644 --- a/crates/ide/src/diagnostics/redundant_assignment.rs +++ b/crates/ide/src/diagnostics/redundant_assignment.rs @@ -200,10 +200,10 @@ mod tests { do_foo() -> X = 42, Y = X, - %% ^^^^^ 💡 weak: assignment is redundant + %% ^^^^^ 💡 weak: W0009: assignment is redundant bar(Y), Z = Y, - %% ^^^^^ 💡 weak: assignment is redundant + %% ^^^^^ 💡 weak: W0009: assignment is redundant g(Z), case Y of [A] -> C = A; diff --git a/crates/ide/src/diagnostics/replace_call.rs b/crates/ide/src/diagnostics/replace_call.rs index e27592dd3a..fa16acf356 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; @@ -109,7 +109,7 @@ pub fn replace_call_site_if_args_match( sema, def_fb, file_id, - &args.as_vec(), + args.as_slice(), target, &range, ) { @@ -536,7 +536,7 @@ mod tests { foo:fire_bombs(Config, 44), foo:fire_bombs(Config, 43), foo:fire_bombs(Config, 42), - %%% ^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: 'foo:fire_bombs/2' called with 42 + %%% ^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: ad-hoc: foo:fire_bombs/2: 'foo:fire_bombs/2' called with 42 foo:fire_bombs(Config, 41), foo:fire_bombs(Config, 40). //- /src/foo.erl diff --git a/crates/ide/src/diagnostics/replace_in_spec.rs b/crates/ide/src/diagnostics/replace_in_spec.rs index 0c43154064..a5df5217e2 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; @@ -185,7 +185,7 @@ mod tests { -type one() :: one. -spec fn(integer()) -> modu:one(). - %% ^^^^^^^^^^ 💡 weak: Replace 'modu:one/0' with 'modu:other()' + %% ^^^^^^^^^^ 💡 weak: ad-hoc: modu:one/0: Replace 'modu:one/0' with 'modu:other()' fn(0) -> one. "#, diff --git a/crates/ide/src/diagnostics/sets_version_2.rs b/crates/ide/src/diagnostics/sets_version_2.rs index dcd4c41a9f..4535d6839a 100644 --- a/crates/ide/src/diagnostics/sets_version_2.rs +++ b/crates/ide/src/diagnostics/sets_version_2.rs @@ -53,11 +53,11 @@ mod tests { //- /src/main.erl -module(main). foo() -> sets:new(). - %% ^^^^^^^^ 💡 warning: Prefer `[{version, 2}]` when constructing a set. - + %% ^^^^^^^^ 💡 warning: W0049: Prefer `[{version, 2}]` when constructing a set. + bar() -> sets:from_list([]). - %% ^^^^^^^^^^^^^^ 💡 warning: Prefer `[{version, 2}]` when constructing a set. - + %% ^^^^^^^^^^^^^^ 💡 warning: W0049: Prefer `[{version, 2}]` when constructing a set. + //- /src/sets.erl -module(sets). -export([new/0, from_list/1]). diff --git a/crates/ide/src/diagnostics/simplify_negation.rs b/crates/ide/src/diagnostics/simplify_negation.rs index 7f381adc4d..bb45c582c9 100644 --- a/crates/ide/src/diagnostics/simplify_negation.rs +++ b/crates/ide/src/diagnostics/simplify_negation.rs @@ -246,7 +246,7 @@ mod tests { fn(A, TrueBranch, FalseBranch) -> case not A of true -> FalseBranch; false -> TrueBranch end. - %% ^ 💡 information: Consider rewriting to match directly on the negated expression. + %% ^ 💡 information: W0044: Consider rewriting to match directly on the negated expression. "#, ) } @@ -260,7 +260,7 @@ mod tests { fn(A, TrueBranch, FalseBranch) -> case not A of false -> TrueBranch; true -> FalseBranch end. - %% ^ 💡 information: Consider rewriting to match directly on the negated expression. + %% ^ 💡 information: W0044: Consider rewriting to match directly on the negated expression. "#, ) } @@ -274,7 +274,7 @@ mod tests { fn(A, TrueBranch, FalseBranch) -> if not A -> FalseBranch; true -> TrueBranch end. - %% ^ 💡 information: Consider rewriting to match directly on the negated expression. + %% ^ 💡 information: W0044: Consider rewriting to match directly on the negated expression. "#, ) } diff --git a/crates/ide/src/diagnostics/trivial_match.rs b/crates/ide/src/diagnostics/trivial_match.rs index ab94c0c9ad..705cc22d7e 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; @@ -348,16 +348,16 @@ mod tests { do_foo() -> 42 = 42, - %% ^^ 💡 warning: match is redundant + %% ^^ 💡 warning: W0007: match is redundant 42 = 43, "blah" = "blah", - %% ^^^^^^ 💡 warning: match is redundant + %% ^^^^^^ 💡 warning: W0007: match is redundant "blah" = "bleh", 'x' = 'x', - %% ^^^ 💡 warning: match is redundant + %% ^^^ 💡 warning: W0007: match is redundant 'x' = 'X', true = true, - %% ^^^^ 💡 warning: match is redundant + %% ^^^^ 💡 warning: W0007: match is redundant true = false, ok. "#, @@ -374,12 +374,12 @@ mod tests { X = 42, Y = 42, X = X, - %% ^ 💡 warning: match is redundant + %% ^ 💡 warning: W0007: match is redundant X = Y, {Z} = {Y}, - %% ^^^ 💡 warning: match is redundant + %% ^^^ 💡 warning: W0007: match is redundant [W, ok] = [ok, ok], - %% ^^^^^^^ 💡 warning: match is redundant + %% ^^^^^^^ 💡 warning: W0007: match is redundant [_W, ok] = [ok, ok], ok. "#, @@ -395,9 +395,9 @@ mod tests { do_foo() -> X = 42, <<"foo", 42>> = <<"foo", 42>>, - %% ^^^^^^^^^^^^^ 💡 warning: match is redundant + %% ^^^^^^^^^^^^^ 💡 warning: W0007: match is redundant <<"foo", X>> = <<"foo", X>>, - %% ^^^^^^^^^^^^ 💡 warning: match is redundant + %% ^^^^^^^^^^^^ 💡 warning: W0007: match is redundant <<"foo", Y>> = <<"foo", 42>>, Y. "#, @@ -412,12 +412,12 @@ mod tests { do_foo() -> X = 42, {X, "foo", {foo, bar}} = {X, "foo", {foo, bar}}, - %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: match is redundant + %% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0007: match is redundant {X, foo} = {X, bar}, {X, "foo", {foo, bar}} = {X, "foo", {foo, pub}}, {X, "foo", {foo, bar}} = {X, "foo", {foo, bar, hey}}, {} = {}, - %% ^^ 💡 warning: match is redundant + %% ^^ 💡 warning: W0007: match is redundant ok. "#, ) @@ -432,12 +432,12 @@ mod tests { do_foo() -> X = 42, [X, ["foo"], [foo, bar]] = [X, ["foo"], [foo, bar]], - %% ^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: match is redundant + %% ^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0007: match is redundant [X, foo] = [X, bar], [X, "foo", [foo, bar]] = [X, "foo", [foo, pub]], [X, "foo", [foo, bar]] = [X, "foo", [foo, bar, hey]], [] = [], - %% ^^ 💡 warning: match is redundant + %% ^^ 💡 warning: W0007: match is redundant ok. "#, ) @@ -453,12 +453,12 @@ mod tests { do_foo() -> #person{name = "Joe", age = 42} = #person{age = 42, name = "Joe"}, - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: match is redundant + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0007: match is redundant #person{name = "Joe", age = 43} = #person{age = 42, name = "Joe"}, #person{name = "Joe"} = #person{age = 42, name = "Joe"}, - %% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: match is redundant + %% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0007: match is redundant #person{age = 42} = #person{age = 42, name = "Joe"}, - %% ^^^^^^^^^^^^^^^^^ 💡 warning: match is redundant + %% ^^^^^^^^^^^^^^^^^ 💡 warning: W0007: match is redundant ok. "#, ) @@ -472,12 +472,12 @@ mod tests { do_foo() -> #{name := "Joe", age := 42} = #{age => 42, name => "Joe"}, - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: match is redundant + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0007: match is redundant #{name := "Joe", age := 43} = #{age => 42, name => "Joe"}, #{name := "Joe"} = #{age => 42, name => "Joe"}, - %% ^^^^^^^^^^^^^^^^ 💡 warning: match is redundant + %% ^^^^^^^^^^^^^^^^ 💡 warning: W0007: match is redundant #{age := 42} = #{age => 42, name => "Joe"}, - %% ^^^^^^^^^^^^ 💡 warning: match is redundant + %% ^^^^^^^^^^^^ 💡 warning: W0007: match is redundant ok. "#, ) diff --git a/crates/ide/src/diagnostics/unavailable_type.rs b/crates/ide/src/diagnostics/unavailable_type.rs new file mode 100644 index 0000000000..6f2f52c122 --- /dev/null +++ b/crates/ide/src/diagnostics/unavailable_type.rs @@ -0,0 +1,340 @@ +/* + * 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 2584e95896..52fa2cfa3c 100644 --- a/crates/ide/src/diagnostics/undefined_function.rs +++ b/crates/ide/src/diagnostics/undefined_function.rs @@ -43,6 +43,13 @@ 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 { @@ -73,19 +80,52 @@ impl FunctionCallLinter for UndefinedFunctionLinter { let arity = context.args.arity(); let module = &def_fb[*module]; let name = &def_fb[*name]; - 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)) - { + + // If the module is a variable, we can't determine at compile time + // whether the function is defined or not, so don't report it + if module.as_var().is_some() || name.as_var().is_some() { return 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())), + + if sema.is_atom_named(name, &known::module_info) && (arity == 0 || arity == 1) { + 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 + } + } } } // Diagnostic L1227 already covers the case for local calls, so avoid double-reporting @@ -167,7 +207,7 @@ mod tests { main() -> _T0 = erlang:monotonic_time(milliseconds), _T2 = erlang:monitonic_time(milliseconds), -%% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Function 'erlang:monitonic_time/1' is undefined. +%% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0017: Function 'erlang:monitonic_time/1' is undefined. exists(). exists() -> ok. @@ -188,7 +228,7 @@ mod tests { main() -> dependency:exists(), dependency:not_exists(). -%% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Function 'dependency:not_exists/0' is undefined. +%% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0017: Function 'dependency:not_exists/0' is undefined. exists() -> ok. //- /src/dependency.erl -module(dependency). @@ -211,9 +251,9 @@ mod tests { main:behaviour_info(callbacks), hascallback:behaviour_info(callbacks), nocallback:behaviour_info(callbacks), -%% ^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Function 'nocallback:behaviour_info/1' is undefined. +%% ^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0017: Function 'nocallback:behaviour_info/1' is undefined. nonexisting:behaviour_info(callbacks), -%% ^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Function 'nonexisting:behaviour_info/1' is undefined. +%% ^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0017: Function 'nonexisting:behaviour_info/1' is undefined. behaviour_info(callbacks). //- /src/hascallback.erl @@ -254,7 +294,7 @@ mod tests { main() -> dependency:exists(), dependency:module_info(a, b). -%% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Function 'dependency:module_info/2' is undefined. +%% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0017: Function 'dependency:module_info/2' is undefined. exists() -> ok. //- /src/dependency.erl -module(dependency). @@ -273,9 +313,9 @@ mod tests { -module(main). main() -> erlang:get_stacktrace(), -%% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Function 'erlang:get_stacktrace/0' is undefined. +%% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0017: Function 'erlang:get_stacktrace/0' is undefined. dependency:get_stacktrace(). -%% ^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Function 'dependency:get_stacktrace/0' is undefined. +%% ^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0017: Function 'dependency:get_stacktrace/0' is undefined. "#, ) } @@ -289,7 +329,7 @@ mod tests { -define(MY_MACRO, fun() -> dep:exists(), dep:not_exists() end). main() -> ?MY_MACRO(). -%% ^^^^^^^^^^^ 💡 warning: Function 'dep:not_exists/0' is undefined. +%% ^^^^^^^^^^^ 💡 warning: W0017: Function 'dep:not_exists/0' is undefined. exists() -> ok. //- /src/dep.erl -module(dep). @@ -359,9 +399,9 @@ exists() -> ok. main() -> {fun dependency:exists/0, fun dependency:not_exists/1, -%% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Function 'dependency:not_exists/1' is undefined. +%% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0017: Function 'dependency:not_exists/1' is undefined. fun dependency:module_info/2}. -%% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Function 'dependency:module_info/2' is undefined. +%% ^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0017: Function 'dependency:module_info/2' is undefined. exists() -> ok. //- /src/dependency.erl -module(dependency). @@ -382,4 +422,53 @@ exists() -> ok. "#, ) } + + #[test] + fn test_module_name_variable() { + check_diagnostics( + r#" + //- /src/main.erl + -module(main). + main(Callback) -> + Callback:main(). + "#, + ) + } + + #[test] + fn test_function_name_variable() { + check_diagnostics( + r#" + //- /src/main.erl + -module(main). + main(Callback) -> + main:Callback(). + "#, + ) + } + + #[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 b4be2ac306..51ee0ceaff 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_text_edit::TextEdit; +use elp_ide_db::text_edit::TextEdit; use fxhash::FxHashSet; use hir::Semantic; use lazy_static::lazy_static; @@ -121,7 +121,7 @@ mod tests { -module(main). foo(X) -> ?assertEqual(X,2). - %% ^^^^^^^^^^^^ 💡 error: undefined macro 'assertEqual/2' + %% ^^^^^^^^^^^^ 💡 error: E1508: undefined macro 'assertEqual/2' //- /another-app/include/inc.hrl app:another include_path:/another-app/include -define(assertEqual(A,B), A =:= B). "#, @@ -159,7 +159,7 @@ mod tests { -module(main). foo(X) -> ?LIFE. - %% ^^^^^ 💡 error: undefined macro 'LIFE' + %% ^^^^^ 💡 error: E1507: undefined macro 'LIFE' //- /another-app/include/inc.hrl app:another include_path:/another-app/include -define(LIFE, 42). "#, @@ -175,7 +175,7 @@ mod tests { -module(main). foo(X) -> ?'LIFE/42'. - %% ^^^^^^^^^^ 💡 error: undefined macro 'LIFE/42' + %% ^^^^^^^^^^ 💡 error: E1507: undefined macro 'LIFE/42' //- /another-app/include/inc.hrl app:another include_path:/another-app/include -define('LIFE/42', 42). "#, @@ -191,7 +191,7 @@ mod tests { -module(main). foo(X) -> ?'LIFE/42'(42). - %% ^^^^^^^^^^ 💡 error: undefined macro 'LIFE/42/1' + %% ^^^^^^^^^^ 💡 error: E1508: undefined macro 'LIFE/42/1' //- /another-app/include/inc.hrl app:another include_path:/another-app/include -define('LIFE/42(X)', X). "#, @@ -208,7 +208,7 @@ mod tests { -module(main). foo(X) -> ?assert~Equal(X,2). - %% ^^^^^^^^^^^^ 💡 error: undefined macro 'assertEqual/2' + %% ^^^^^^^^^^^^ 💡 error: E1508: undefined macro 'assertEqual/2' //- /app_a/include/inc.hrl app:app_a include_path:/app_a/include -define(assertEqual(A,B), A =:= B). @@ -236,7 +236,7 @@ mod tests { -module(main). foo(X) -> ?assert~Equal(X,2). - %% ^^^^^^^^^^^^ 💡 error: undefined macro 'assertEqual/2' + %% ^^^^^^^^^^^^ 💡 error: E1508: undefined macro 'assertEqual/2' //- /app_a/include/inc.hrl app:app_a include_path:/app_a/include -define(assertEqual(A,B), A =:= B). @@ -264,7 +264,7 @@ mod tests { -module(main). foo(X) -> ?assert~Equal(X,2). - %% ^^^^^^^^^^^^ 💡 error: undefined macro 'assertEqual/2' + %% ^^^^^^^^^^^^ 💡 error: E1508: undefined macro 'assertEqual/2' //- /app_a/include/inc.hrl app:app_a include_path:/app_a/include diff --git a/crates/ide/src/diagnostics/undocumented_function.rs b/crates/ide/src/diagnostics/undocumented_function.rs index 353e79fee3..f1d0aa06b5 100644 --- a/crates/ide/src/diagnostics/undocumented_function.rs +++ b/crates/ide/src/diagnostics/undocumented_function.rs @@ -8,9 +8,10 @@ * above-listed licenses. */ -use elp_ide_assists::helpers::unwrap_parens; // Diagnostic: undocumented-function +use elp_ide_assists::helpers::unwrap_parens; 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; @@ -21,37 +22,66 @@ use hir::Semantic; use hir::form_list::ModuleDocAttribute; use hir::known; -use super::Diagnostic; -use super::DiagnosticCode; -use super::DiagnosticConditions; -use super::DiagnosticDescriptor; -use super::Severity; +use crate::diagnostics::DiagnosticCode; +use crate::diagnostics::GenericLinter; +use crate::diagnostics::GenericLinterMatchContext; +use crate::diagnostics::Linter; +use crate::diagnostics::Severity; -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; +pub(crate) struct UndocumentedFunctionLinter; -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); - }, -}; +impl Linter for UndocumentedFunctionLinter { + fn id(&self) -> DiagnosticCode { + DiagnosticCode::UndocumentedFunction + } -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)); + 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 } } +#[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() @@ -87,20 +117,22 @@ 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) { - let diagnostic = Diagnostic::new(DIAGNOSTIC_CODE, DIAGNOSTIC_MESSAGE, name_range) - .with_severity(DIAGNOSTIC_SEVERITY); - diagnostics.push(diagnostic); + Some(GenericLinterMatchContext { + range: name_range, + context: Context { range: name_range }, + }) + } else { + None } } @@ -118,6 +150,7 @@ mod tests { .disable(DiagnosticCode::OldEdocSyntax) } + #[track_caller] fn check_diagnostics(fixture: &str) { tests::check_diagnostics_with_config(config(), fixture); } @@ -129,7 +162,7 @@ mod tests { -module(main). -export([main/0]). main() -> - %% ^^^^ weak: The function is non-trivial, exported, but not documented. + %% ^^^^ 💡 weak: W0040: The function is non-trivial, exported, but not documented. [ok, ok, ok, @@ -146,7 +179,7 @@ mod tests { -module(main). -export([main/0]). main() -> - %% ^^^^ weak: The function is non-trivial, exported, but not documented. + %% ^^^^ 💡 weak: W0040: The function is non-trivial, exported, but not documented. [ok, ok, ok, @@ -240,7 +273,7 @@ mod tests { -module(main). -moduledoc false. -export([main/0]). - + main() -> [ok, ok, @@ -258,7 +291,7 @@ mod tests { -module(main). -moduledoc(false). -export([main/0]). - + main() -> [ok, ok, @@ -276,7 +309,7 @@ mod tests { -module(main). -moduledoc hidden. -export([main/0]). - + main() -> [ok, ok, @@ -294,7 +327,7 @@ mod tests { -module(main). -moduledoc(hidden). -export([main/0]). - + main() -> [ok, ok, @@ -314,9 +347,9 @@ mod tests { -behaviour(gen_server). -export([main/0]). -export([handle_call/1]). - + main() -> - %%<^ weak: The function is non-trivial, exported, but not documented. + %%<^ 💡 weak: W0040: The function is non-trivial, exported, but not documented. [ok, ok, ok, @@ -343,12 +376,12 @@ mod tests { r#" -module(main). -export([simple/0, complex/0]). - + simple() -> ok. complex() -> - %%<^^^^ weak: The function is non-trivial, exported, but not documented. + %%<^^^^ 💡 weak: W0040: The function is non-trivial, exported, but not documented. [ok, ok, ok, @@ -364,12 +397,12 @@ mod tests { r#" -module(main). -export([simple/0, complex/1]). - + simple() -> ok. complex(a) -> - %%<^^^^ weak: 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 1e4659c1f8..1b2c80cfc9 100644 --- a/crates/ide/src/diagnostics/undocumented_module.rs +++ b/crates/ide/src/diagnostics/undocumented_module.rs @@ -1,74 +1,105 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * - * 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 + * 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. + * of this source tree. You may select, at your option, one of the + * above-listed licenses. */ 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 super::Diagnostic; -use super::DiagnosticCode; -use super::DiagnosticConditions; -use super::DiagnosticDescriptor; -use super::Severity; +use crate::diagnostics::DiagnosticCode; +use crate::diagnostics::GenericLinter; +use crate::diagnostics::GenericLinterMatchContext; +use crate::diagnostics::Linter; +use crate::diagnostics::Severity; +use crate::fix; -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"; +pub(crate) struct UndocumentedModuleLinter; -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); +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 } - Some(()) } -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] +#[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]) + } } +pub static LINTER: UndocumentedModuleLinter = UndocumentedModuleLinter; + #[cfg(test)] mod tests { @@ -83,6 +114,7 @@ mod tests { DiagnosticsConfig::default().enable(DiagnosticCode::UndocumentedModule) } + #[track_caller] fn check_diagnostics(fixture: &str) { tests::check_diagnostics_with_config(config(), fixture); } @@ -96,7 +128,7 @@ mod tests { check_diagnostics( r#" -module(main). - %% ^^^^ 💡 weak: The module is not documented. + %% ^^^^ 💡 weak: W0046: The module is not documented. "#, ) } @@ -141,7 +173,7 @@ mod tests { check_diagnostics( r#" % @doc - %% ^^^^ 💡 warning: EDoc style comments are deprecated. Please use Markdown instead. + %% ^^^^ 💡 warning: W0038: EDoc style comments are deprecated. Please use Markdown instead. % This is a module -module(main). "#, diff --git a/crates/ide/src/diagnostics/unexported_function.rs b/crates/ide/src/diagnostics/unexported_function.rs index 4985b3c4e3..2e1ebf7f54 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 +// @fb-only: use crate::diagnostics::meta_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 + // @fb-only: fn should_process_file_id(&self, sema: &Semantic, file_id: FileId) -> bool { true // @oss-only - // @fb-only + // @fb-only: meta_only::should_check_for_unexported(sema, file_id) } } @@ -127,6 +127,7 @@ mod tests { use crate::tests::check_diagnostics_with_config; use crate::tests::check_nth_fix; + #[track_caller] pub(crate) fn check_diagnostics(fixture: &str) { let config = DiagnosticsConfig::default().disable(elp_ide_db::DiagnosticCode::NoSize); check_diagnostics_with_config(config, fixture) @@ -141,7 +142,7 @@ mod tests { main() -> dependency:exists(), dependency:private(). -%% ^^^^^^^^^^^^^^^^^^ 💡 warning: Function 'dependency:private/0' is not exported. +%% ^^^^^^^^^^^^^^^^^^ 💡 warning: W0026: Function 'dependency:private/0' is not exported. exists() -> ok. //- /src/dependency.erl -module(dependency). @@ -160,9 +161,9 @@ mod tests { -module(main). main() -> ?MODULE:private(), -%% ^^^^^^^^^^^^^^^ 💡 warning: Function 'main:private/0' is not exported. +%% ^^^^^^^^^^^^^^^ 💡 warning: W0026: Function 'main:private/0' is not exported. main:private(). -%% ^^^^^^^^^^^^ 💡 warning: Function 'main:private/0' is not exported. +%% ^^^^^^^^^^^^ 💡 warning: W0026: Function 'main:private/0' is not exported. private() -> ok. "#, @@ -178,7 +179,7 @@ mod tests { -include("header.hrl"). foo() -> main:bar(). -%% ^^^^^^^^ 💡 warning: Function 'main:bar/0' is not exported. +%% ^^^^^^^^ 💡 warning: W0026: Function 'main:bar/0' is not exported. //- /src/header.hrl bar() -> ok. 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 9fabb2f21d..40f16da4d8 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) -> Severity { + fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { Severity::WeakWarning } } @@ -260,7 +260,7 @@ mod tests { % elp:ignore W0017 (undefined_function) fn(List) -> lists:foldl(fun(K, Acc) -> Acc#{K => []} end, #{}, List). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: Unnecessary explicit fold to construct map from keys. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: W0035: Unnecessary explicit fold to construct map from keys. "#, ) } @@ -274,7 +274,7 @@ mod tests { % elp:ignore W0017 (undefined_function) fn(List) -> lists:foldl(fun({K,V}, Acc) -> Acc#{K => V} end, #{}, List). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: Unnecessary explicit fold to construct map from list. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: W0035: Unnecessary explicit fold to construct map from list. "#, ) } diff --git a/crates/ide/src/diagnostics/unnecessary_map_from_list_around_comprehension.rs b/crates/ide/src/diagnostics/unnecessary_map_from_list_around_comprehension.rs index 9d337dda7d..d2378528ce 100644 --- a/crates/ide/src/diagnostics/unnecessary_map_from_list_around_comprehension.rs +++ b/crates/ide/src/diagnostics/unnecessary_map_from_list_around_comprehension.rs @@ -160,7 +160,7 @@ mod tests { % elp:ignore W0017 (undefined_function) fn(List) -> maps:from_list([{K + 1, V + 2} || {K,V} <- List]). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: Unnecessary intermediate list allocated. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: W0036: Unnecessary intermediate list allocated. "#, ) } @@ -174,7 +174,7 @@ mod tests { % elp:ignore W0017 (undefined_function) fn(List) -> maps:from_list([{element(1, Pair) + 1, element(2, Pair) + 2} || Pair <- List]). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: Unnecessary intermediate list allocated. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: W0036: Unnecessary intermediate list allocated. "#, ) } 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 99859c225d..0c2ed5e140 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) -> Severity { + fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { Severity::WeakWarning } } @@ -137,7 +137,7 @@ mod tests { % elp:ignore W0017 (undefined_function) fn(Map) -> [K + V + 1 || {K,V} <- maps:to_list(Map)]. - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: Unnecessary intermediate list allocated. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: W0034: Unnecessary intermediate list allocated. "#, ) } diff --git a/crates/ide/src/diagnostics/unspecific_include.rs b/crates/ide/src/diagnostics/unspecific_include.rs index b6306c399f..431740c085 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,10 +152,12 @@ 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 { @@ -167,9 +169,13 @@ mod tests { tests::check_filtered_diagnostics(fixture, &filter) } + #[rustfmt::skip] #[track_caller] fn check_fix(fixture_before: &str, fixture_after: Expect) { - tests::check_fix(fixture_before, fixture_after) + let config = DiagnosticsConfig::default() + // @fb-only: .disable(DiagnosticCode::MetaOnly(MetaOnlyDiagnosticCode::MalformedInclude)) + .disable(DiagnosticCode::UnusedInclude); + tests::check_fix_with_config(config, fixture_before, fixture_after) } #[test] @@ -179,7 +185,7 @@ mod tests { //- /app_a/src/unspecific_include.erl -module(unspecific_include). -include("some_header_from_app_a.hrl"). - %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: Unspecific include. + %% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: W0037: Unspecific include. //- /app_a/include/some_header_from_app_a.hrl include_path:/app_a/include -define(A,3). diff --git a/crates/ide/src/diagnostics/unused_function_args.rs b/crates/ide/src/diagnostics/unused_function_args.rs index dbe7cd6152..ec4825e522 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; @@ -210,8 +210,8 @@ mod tests { r#" -module(main). do_something(Unused, Used, _AlsoUsed, AlsoUnused, _UnusedButOk) -> - %%% ^^^^^^ 💡 warning: this variable is unused - %%% ^^^^^^^^^^ 💡 warning: this variable is unused + %%% ^^^^^^ 💡 warning: W0010: this variable is unused + %%% ^^^^^^^^^^ 💡 warning: W0010: this variable is unused case Used of undefined -> ok; @@ -227,8 +227,8 @@ mod tests { r#" -module(main). do_something([Unused | Used], #{foo := {_AlsoUsed, AlsoUnused, _UnusedButOk}}) -> - %%% ^^^^^^ 💡 warning: this variable is unused - %%% ^^^^^^^^^^ 💡 warning: this variable is unused + %%% ^^^^^^ 💡 warning: W0010: this variable is unused + %%% ^^^^^^^^^^ 💡 warning: W0010: this variable is unused case Used of undefined -> ok; @@ -302,7 +302,7 @@ mod tests { -module(main). foo(Args) -> {foo, Args}; foo(Args2) -> ok. - %% ^^^^^ 💡 warning: this variable is unused + %% ^^^^^ 💡 warning: W0010: this variable is unused "#, ); } @@ -314,7 +314,7 @@ mod tests { -module(main). foo(X, _Y = [_Z = {X, _, _} | _]) -> bar; foo(X, _Y) -> pub. - %% ^ 💡 warning: this variable is unused + %% ^ 💡 warning: W0010: this variable is unused "#, ); } diff --git a/crates/ide/src/diagnostics/unused_include.rs b/crates/ide/src/diagnostics/unused_include.rs index 08f23af1d5..eb26bcd923 100644 --- a/crates/ide/src/diagnostics/unused_include.rs +++ b/crates/ide/src/diagnostics/unused_include.rs @@ -12,14 +12,17 @@ // // 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; @@ -31,9 +34,11 @@ use hir::db::DefDatabase; use hir::known; use lazy_static::lazy_static; -use super::Diagnostic; +use crate::Assist; use crate::diagnostics::DiagnosticCode; -use crate::diagnostics::Severity; +use crate::diagnostics::GenericLinter; +use crate::diagnostics::GenericLinterMatchContext; +use crate::diagnostics::Linter; use crate::fix; lazy_static! { @@ -43,56 +48,114 @@ lazy_static! { .collect(); } -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; - } +pub(crate) struct UnusedIncludeLinter; - 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(); +impl Linter for UnusedIncludeLinter { + fn id(&self) -> DiagnosticCode { + DiagnosticCode::UnusedInclude + } - 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, - )])); + fn description(&self) -> &'static str { + "Unused include file" + } - log::debug!("Found unused include {path:?}"); + 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() + } - diagnostics.push(diagnostic); - } + 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, + }, + }); + } + } + } + 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, @@ -265,7 +328,7 @@ mod tests { //- /src/foo.erl -module(foo). -include("foo.hrl"). -%%^^^^^^^^^^^^^^^^^^^^ 💡 warning: Unused file: foo.hrl +%%^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0020: Unused file: foo.hrl "#, ); } @@ -293,7 +356,7 @@ mod tests { //- /src/foo.erl -module(foo). -include("foo.hrl"). -%%^^^^^^^^^^^^^^^^^^^^ 💡 warning: Unused file: foo.hrl +%%^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0020: Unused file: foo.hrl "#, ); } @@ -321,7 +384,7 @@ mod tests { //- /src/foo.erl -module(foo). -include("foo.hrl"). -%%^^^^^^^^^^^^^^^^^^^^ 💡 warning: Unused file: foo.hrl +%%^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0020: Unused file: foo.hrl "#, ); } @@ -350,7 +413,7 @@ mod tests { //- /src/foo.erl -module(foo). -include("foo.hrl"). -%%^^^^^^^^^^^^^^^^^^^^ 💡 warning: Unused file: foo.hrl +%%^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0020: Unused file: foo.hrl "#, ); } @@ -580,7 +643,7 @@ foo() -> ok. //- /src/header.hrl %% The following shows up as a wild attribute, which we regard as being used. -defin e(X, 1). -%% ^^^^^ 💡 error: misspelled attribute, saw 'defin' but expected 'define' +%% ^^^^^ 💡 error: W0013: misspelled attribute, saw 'defin' but expected 'define' -def ine(Y, 2). "#, @@ -594,7 +657,7 @@ foo() -> ok. //- /src/main.erl -module(main). -include("header.hrl"). -%%^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Unused file: header.hrl +%%^^^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0020: Unused file: header.hrl foo() -> ok. diff --git a/crates/ide/src/diagnostics/unused_macro.rs b/crates/ide/src/diagnostics/unused_macro.rs index 99af05370d..6ea8756b91 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,7 +88,13 @@ impl GenericLinter for UnusedMacroLinter { Some(DiagnosticTag::Unused) } - fn fixes(&self, context: &Context, _sema: &Semantic, file_id: FileId) -> Option> { + fn fixes( + &self, + context: &Context, + _range: TextRange, + _sema: &Semantic, + file_id: FileId, + ) -> Option> { Some(vec![delete_unused_macro( file_id, context.delete_range, @@ -123,7 +129,9 @@ mod tests { #[track_caller] pub(crate) fn check_diagnostics(fixture: &str) { - let config = DiagnosticsConfig::default().disable(DiagnosticCode::UndefinedFunction); + let config = DiagnosticsConfig::default() + .disable(DiagnosticCode::UndefinedFunction) + .disable(DiagnosticCode::HirUnresolvedMacro); check_diagnostics_with_config(config, fixture) } @@ -133,7 +141,7 @@ mod tests { r#" -module(main). -define(MEANING_OF_LIFE, 42). - %% ^^^^^^^^^^^^^^^ 💡 warning: Unused macro (MEANING_OF_LIFE) + %% ^^^^^^^^^^^^^^^ 💡 warning: W0002: Unused macro (MEANING_OF_LIFE) "#, ); check_fix( @@ -176,9 +184,9 @@ main() -> -module(main). -define(USED_MACRO, used_macro). -define(UNUSED_MACRO, unused_macro). - %% ^^^^^^^^^^^^ 💡 warning: Unused macro (UNUSED_MACRO) + %% ^^^^^^^^^^^^ 💡 warning: W0002: Unused macro (UNUSED_MACRO) -define(UNUSED_MACRO_WITH_ARG(C), C). - %% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: Unused macro (UNUSED_MACRO_WITH_ARG/1) + %% ^^^^^^^^^^^^^^^^^^^^^ 💡 warning: W0002: Unused macro (UNUSED_MACRO_WITH_ARG/1) main() -> ?MOD:foo(), @@ -211,7 +219,7 @@ main() -> -module(foo). -include("foo.hrl"). -define(BAR, 42). - %% ^^^ 💡 warning: Unused macro (BAR) + %% ^^^ 💡 warning: W0002: Unused macro (BAR) main() -> ?A. "#, diff --git a/crates/ide/src/diagnostics/unused_record_field.rs b/crates/ide/src/diagnostics/unused_record_field.rs index 33f5bbaac3..cbce6009bf 100644 --- a/crates/ide/src/diagnostics/unused_record_field.rs +++ b/crates/ide/src/diagnostics/unused_record_field.rs @@ -100,7 +100,7 @@ mod tests { -record(used_field, {field_a, field_b = 42}). -record(unused_field, {field_c, field_d}). - %% ^^^^^^^ warning: Unused record field (unused_field.field_d) + %% ^^^^^^^ warning: W0003: Unused record field (unused_field.field_d) main(#used_field{field_a = A, field_b = B}) -> {A, B}; @@ -120,7 +120,7 @@ main(R) -> -record(used_field, {field_a, field_b = 42}). -record(unused_field, {field_c :: atom(), field_d :: number()}). - %% ^^^^^^^ warning: Unused record field (unused_field.field_d) + %% ^^^^^^^ warning: W0003: Unused record field (unused_field.field_d) main(#used_field{field_a = A, field_b = B}) -> {A, B}; @@ -189,9 +189,9 @@ main(#used_field{field_a = A}) -> r#" -module(main). -record(a, {a1, a2}). - %% ^^ warning: Unused record field (a.a2) + %% ^^ warning: W0003: Unused record field (a.a2) -record(b, {b1, b2}). - %% ^^ warning: Unused record field (b.b1) + %% ^^ warning: W0003: Unused record field (b.b1) main(#a{a1 = #b{b2 = B2}} = A) -> {A, B2}. "#, diff --git a/crates/ide/src/diagnostics_collection.rs b/crates/ide/src/diagnostics_collection.rs index d944e223da..fe1fc759aa 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(native.clone(), erlang_service.clone()); + attach_related_diagnostics(file_id, 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(diagnostics, extra_diags.clone()); + let combined = attach_related_diagnostics(file_id, diagnostics, extra_diags.clone()); let expected = fixture.annotations_by_file_id(&file_id); let mut actual = combined .into_iter() @@ -415,6 +415,7 @@ 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 d13befe8bb..6a85ab3dc3 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 +// @fb-only: use crate::meta_only::exdoc_links; -// @fb-only +// @fb-only: mod meta_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 + // @fb-only: exdoc_links::links(&mut doc_links, &sema, &def); }); } - // @fb-only + // @fb-only: meta_only::links(&mut doc_links, node, position); Some(doc_links) } diff --git a/crates/ide/src/document_symbols.rs b/crates/ide/src/document_symbols.rs index 390a975132..daed2c6368 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 95735a904d..a5a6f759fc 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 @@ mod tests { 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/handlers/get_docs.rs b/crates/ide/src/handlers/get_docs.rs index 7fdd979e92..f4476bd12c 100644 --- a/crates/ide/src/handlers/get_docs.rs +++ b/crates/ide/src/handlers/get_docs.rs @@ -22,3 +22,108 @@ pub(crate) fn get_doc_for_token( let docs = elp_ide_db::docs::Documentation::new(db, sema); Doc::from_reference(&docs, token) } + +#[cfg(test)] +mod tests { + use elp_project_model::otp::supports_eep59_doc_attributes; + + use crate::fixture; + + #[track_caller] + fn check(fixture: &str, expected: &str) { + let (analysis, fixture) = fixture::with_fixture(fixture); + let docs = analysis + .get_docs_at_position(fixture.position()) + .unwrap() + .unwrap(); + let doc = docs.doc.unwrap(); + assert_eq!(doc.markdown_text(), expected); + } + + #[test] + fn local_type() { + if supports_eep59_doc_attributes() { + check( + r#" +-module(main). +-export([main/0]). +-doc """ +My integer +""". +-type my_integer() :: integer(). + +-spec main() -> my_in~teger(). +main() -> 42. +"#, + "\ +```erlang +-type my_integer() :: integer(). +``` + +----- + +My integer", + ); + } + } + + #[test] + fn remote_type() { + if supports_eep59_doc_attributes() { + check( + r#" +//- /src/main.erl +-module(main). +-export([main/0]). +-spec main() -> other:my_in~teger(). +main() -> 42. + +//- /src/other.erl +-module(other). +-doc """ +My integer +""". +-export_type([my_integer/0]). +-type my_integer() :: integer(). +"#, + "\ +```erlang +-type my_integer() :: integer(). +``` + +----- + +My integer", + ); + } + } + + #[test] + fn local_function() { + if supports_eep59_doc_attributes() { + check( + r#" +-module(main). +-export([main/0]). + +-doc """ +My function +""". +-spec main() -> ok. +main() -> ok. + +-spec caller() -> ok. +caller() -> ma~in(). +"#, + "\ +```erlang +-spec main() -> ok. +``` + +----- + +My function", + ); + } + } +} diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs index cf16198dfe..88a95e86d7 100644 --- a/crates/ide/src/inlay_hints/param_name.rs +++ b/crates/ide/src/inlay_hints/param_name.rs @@ -259,6 +259,7 @@ 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 449a99de4a..ad5c1bb680 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 +// @fb-only: pub mod meta_only; pub use annotations::Annotation; pub use annotations::AnnotationKind; @@ -170,6 +170,7 @@ pub struct AnalysisHost { db: RootDatabase, } +#[derive(Debug)] pub struct DocResult { pub doc: Option, pub token_kind: SyntaxKind, @@ -250,9 +251,9 @@ impl Analysis { }) } - pub fn should_eqwalize(&self, file_id: FileId, include_tests: bool) -> Cancellable { + pub fn should_eqwalize(&self, file_id: FileId) -> 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, include_tests)?) + Ok(is_in_app && self.is_eqwalizer_enabled(file_id)?) } /// Computes the set of eqwalizer diagnostics for the given files, @@ -382,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, include_tests: bool) -> Cancellable { - self.with_db(|db| db.is_eqwalizer_enabled(file_id, include_tests)) + pub fn is_eqwalizer_enabled(&self, file_id: FileId) -> Cancellable { + self.with_db(|db| db.is_eqwalizer_enabled(file_id)) } /// ETF for the module's abstract forms @@ -565,6 +566,16 @@ impl Analysis { self.with_db(|db| db.is_otp(file_id)) } + /// Validates an SSR pattern string by attempting to parse it. + /// Returns `Ok(())` if the pattern is valid, or an error message if parsing fails. + pub fn validate_ssr_pattern(&self, pattern: &str) -> Cancellable> { + self.with_db(|db| { + elp_ide_ssr::SsrRule::parse_str(db, pattern) + .map(|_| ()) + .map_err(|e| e.to_string()) + }) + } + /// Search symbols. Only module names are currently supported. pub fn symbol_search( &self, diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index 23e9ceca89..ee5bfb7219 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -77,6 +77,28 @@ 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 { @@ -171,36 +193,54 @@ pub fn rename_var( } #[cfg(test)] -mod tests { +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 elp_text_edit::TextEdit; + use fxhash::FxHashSet; use hir::AnyExprId; use hir::InFile; use hir::Semantic; use super::rename_var; + use crate::AnalysisHost; use crate::fixture; #[track_caller] - fn check(new_name: &str, fixture_before: &str, fixture_after_str: &str) { + 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 (analysis, position, _) = fixture::position(fixture_before); + 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 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); } @@ -210,6 +250,82 @@ 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:") { @@ -225,14 +341,24 @@ 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("Y", r#"main() -> I~ = 1."#, r#"main() -> Y = 1."#); + check_rename("Y", r#"main() -> I~ = 1."#, r#"main() -> Y = 1."#); } #[test] fn test_rename_var_2() { - check( + check_rename( "Y", r#"main() -> I~ = 1, @@ -245,7 +371,7 @@ mod tests { #[test] fn test_rename_var_3() { - check( + check_rename( "Y", r#"main(X) -> case X of @@ -264,7 +390,7 @@ mod tests { #[test] fn test_rename_var_4() { - check( + check_rename( "Y", r#"testz() -> case rand:uniform(2) of @@ -291,7 +417,7 @@ mod tests { #[test] fn test_rename_var_5() { - check( + check_rename( "YY", r#"main(_) -> Y = 5, @@ -316,7 +442,7 @@ mod tests { #[test] fn test_rename_var_6() { - check( + check_rename( "ZZ", r#"main(_) -> Z = 2, @@ -333,7 +459,7 @@ mod tests { #[test] fn test_rename_var_7() { - check( + check_rename( "Y", r#"main() -> I = 1, @@ -346,7 +472,7 @@ mod tests { #[test] fn test_rename_var_name_clash_1() { - check( + check_rename( "Y", r#"main(Y) -> I~ = 1, @@ -357,7 +483,7 @@ mod tests { #[test] fn test_rename_var_but_not_shadowed() { - check( + check_rename( "Z", r#"triples( Self, X, Y, none )-> [ Result || Result = { X~, Y, _} <- Self ]."#, @@ -370,7 +496,7 @@ mod tests { #[test] fn test_rename_local_function_no_calls() { - check( + check_rename( "new_fun", r#"trip~les( Self, X, Y, none )-> [ Result || Result = { X, Y, _} <- Self ]."#, @@ -381,7 +507,7 @@ mod tests { #[test] fn test_rename_local_function_with_calls_1() { - check( + check_rename( "new_fun", r#"fo~o() -> ok. bar() -> foo()."#, @@ -392,7 +518,7 @@ mod tests { #[test] fn test_rename_local_function_with_calls_2() { - check( + check_rename( "new_fun", r#"fo~o() -> ok. bar() -> baz(),foo()."#, @@ -403,7 +529,7 @@ mod tests { #[test] fn test_rename_local_function_with_calls_3() { - check( + check_rename( "new_fun", r#"fo~o(0) -> 0; foo(X) -> foo(X - 1). @@ -416,7 +542,7 @@ mod tests { #[test] fn test_rename_local_function_with_calls_4() { - check( + check_rename( "new_fun", r#"test1() -> ok. @@ -429,7 +555,7 @@ mod tests { #[test] fn test_rename_local_function_fails_name_clash_1() { - check( + check_rename( "new_fun", r#"fo~o() -> ok. new_fun() -> ok."#, @@ -439,7 +565,7 @@ mod tests { #[test] fn test_rename_local_function_fails_name_clash_2() { - check( + check_rename( "foo", r#"foo() -> ok. b~ar() -> ok."#, @@ -449,7 +575,7 @@ mod tests { #[test] fn test_rename_local_function_fails_name_clash_checks_arity() { - check( + check_rename( "new_fun", r#"fo~o() -> ok. new_fun(X) -> ok."#, @@ -460,7 +586,7 @@ mod tests { #[test] fn test_rename_local_function_fails_name_clash_imported_function() { - check( + check_rename( "new_fun", r#"-import(bar, [new_fun/0]). fo~o() -> ok."#, @@ -470,7 +596,7 @@ mod tests { #[test] fn test_rename_local_function_fails_name_clash_erlang_function() { - check( + check_rename( "alias", r#"fo~o() -> ok."#, r#"error: Function 'alias/0' already in scope"#, @@ -479,7 +605,7 @@ mod tests { #[test] fn test_rename_local_function_also_name_in_macro() { - check( + check_rename( "new", r#"-define(FOO, foo). fo~o() -> ok. @@ -492,17 +618,17 @@ mod tests { #[test] fn test_rename_local_var_trims_surrounding_spaces() { - check(" Aaa ", r#"foo() -> V~ar = 3."#, r#"foo() -> Aaa = 3."#); + check_rename(" Aaa ", r#"foo() -> V~ar = 3."#, r#"foo() -> Aaa = 3."#); } #[test] fn test_rename_local_function_trims_surrounding_spaces() { - check(" aaa ", r#"fo~o() -> Var = 3."#, r#"aaa() -> Var = 3."#); + check_rename(" aaa ", r#"fo~o() -> Var = 3."#, r#"aaa() -> Var = 3."#); } #[test] fn test_rename_local_var_fails_invalid_var_name() { - check( + check_rename( "aaa", r#"foo() -> V~ar = 3."#, r#"error: Invalid new variable name: 'aaa'"#, @@ -511,7 +637,7 @@ mod tests { #[test] fn test_rename_local_function_fails_invalid_function_name_1() { - check( + check_rename( "Foo", r#"fo~o() -> ok."#, r#"error: Invalid new function name: 'Foo'"#, @@ -520,7 +646,7 @@ mod tests { #[test] fn test_rename_local_function_fails_invalid_function_name_2() { - check( + check_rename( "TT TTT", r#"fo~o() -> ok."#, r#"error: Invalid new function name: 'TT TTT'"#, @@ -529,7 +655,7 @@ mod tests { #[test] fn test_rename_local_function_fails_invalid_function_name_3() { - check( + check_rename( "TTT", r#"fo~o() -> ok."#, r#"error: Invalid new function name: 'TTT'"#, @@ -538,7 +664,7 @@ mod tests { #[test] fn test_rename_var_d39578003_case_5() { - check( + check_rename( "_G", r#"main(_) -> fun F() -> @@ -561,7 +687,7 @@ mod tests { #[test] fn test_rename_in_spawn_1() { - check( + check_rename( "new_name", r#"foo() -> Pid = erlang:spawn(fun noop_~group_leader/0), @@ -578,7 +704,7 @@ mod tests { #[test] fn test_rename_in_spawn_2() { - check( + check_rename( "new_name", r#"foo() -> Pid = erlang:spawn(fun noop_group_leader/0), @@ -595,7 +721,7 @@ mod tests { #[test] fn test_rename_in_apply_1() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -617,7 +743,7 @@ mod tests { #[test] fn test_rename_in_apply_2() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -637,7 +763,7 @@ mod tests { #[test] fn test_rename_in_apply_args_1() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -661,7 +787,7 @@ mod tests { #[test] fn test_rename_in_apply_args_2() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -678,7 +804,7 @@ mod tests { #[test] fn test_rename_in_apply_3() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -700,7 +826,7 @@ mod tests { #[test] fn test_rename_in_apply_4() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -722,7 +848,7 @@ mod tests { #[test] fn test_rename_in_apply_5() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -737,7 +863,7 @@ mod tests { #[test] fn test_rename_function_with_spec_1() { - check( + check_rename( "new_name", r#" -spec foo() -> ok. @@ -752,7 +878,7 @@ mod tests { #[test] fn test_rename_function_with_spec_2() { - check( + check_rename( "new_name", r#" -spec f~oo() -> ok. @@ -767,7 +893,7 @@ mod tests { #[test] fn test_rename_function_with_spec_3() { - check( + check_rename( "new_name", r#" -spec f~oo(any()) -> ok. @@ -782,7 +908,7 @@ mod tests { #[test] fn test_rename_underscore_1() { - check( + check_rename( "NewName", r#" foo() -> @@ -794,7 +920,7 @@ mod tests { #[test] fn test_rename_underscore_2() { - check( + check_rename( "NewName", r#" foo(X) -> @@ -807,7 +933,7 @@ mod tests { #[test] fn test_rename_case_1() { - check( + check_rename( "XX", r#" foo(X) -> @@ -828,7 +954,7 @@ mod tests { #[test] fn test_rename_case_2() { - check( + check_rename( "XX", r#" foo() -> @@ -845,7 +971,7 @@ mod tests { #[test] fn test_rename_case_3() { - check( + check_rename( "XX", r#" foo() -> @@ -860,7 +986,7 @@ mod tests { #[test] fn rename_export_function() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -893,7 +1019,7 @@ mod tests { #[test] fn rename_export_function_2() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -928,7 +1054,7 @@ mod tests { #[test] fn rename_export_function_fails() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -951,7 +1077,7 @@ mod tests { #[test] fn rename_export_function_ok_no_local_import() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -988,7 +1114,7 @@ mod tests { fn rename_function_in_include() { // We do not have functions defined in our header files, but // confirm it does the right thing anyway - check( + check_rename( "new_name", r#" //- /src/main.hrl @@ -1041,7 +1167,7 @@ mod tests { #[test] fn test_rename_in_macro_rhs_1() { - check( + check_rename( "new_name", r#" -define(BAR(X), foo(X)). @@ -1058,7 +1184,7 @@ mod tests { #[test] fn rename_with_macro() { - check( + check_rename( "NewName", r#" //- /src/main.hrl @@ -1094,7 +1220,7 @@ mod tests { // See T157498333 #[test] fn rename_function_with_macro_type() { - check( + check_rename( "newFoo", r#" -module(main). @@ -1113,6 +1239,326 @@ 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] @@ -1183,9 +1629,261 @@ 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( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1207,7 +1905,7 @@ mod tests { #[test] fn test_rename_in_rpc_call_5() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1229,7 +1927,7 @@ mod tests { #[test] fn test_rename_in_rpc_async_call() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1251,7 +1949,7 @@ mod tests { #[test] fn test_rename_in_rpc_cast() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1273,7 +1971,7 @@ mod tests { #[test] fn test_rename_in_rpc_multicall_3() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1295,7 +1993,7 @@ mod tests { #[test] fn test_rename_in_rpc_multicall_4() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1317,7 +2015,7 @@ mod tests { #[test] fn test_rename_in_rpc_multicall_5() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1339,7 +2037,7 @@ mod tests { #[test] fn test_rename_in_function_exported() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1361,7 +2059,7 @@ mod tests { #[test] fn test_rename_in_erlang_function_exported() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1383,7 +2081,7 @@ mod tests { #[test] fn test_rename_in_is_builtin() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1405,7 +2103,7 @@ mod tests { #[test] fn test_rename_in_erlang_is_builtin() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1427,7 +2125,7 @@ mod tests { #[test] fn test_rename_in_hibernate() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1449,7 +2147,7 @@ mod tests { #[test] fn test_rename_in_erlang_hibernate() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1471,7 +2169,7 @@ mod tests { #[test] fn test_rename_in_spawn() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1493,7 +2191,7 @@ mod tests { #[test] fn test_rename_in_erlang_spawn() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1515,7 +2213,7 @@ mod tests { #[test] fn test_rename_in_spawn_4() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1537,7 +2235,7 @@ mod tests { #[test] fn test_rename_in_erlang_spawn_4() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1559,7 +2257,7 @@ mod tests { #[test] fn test_rename_in_spawn_link() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1581,7 +2279,7 @@ mod tests { #[test] fn test_rename_in_erlang_spawn_link() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1603,7 +2301,7 @@ mod tests { #[test] fn test_rename_in_spawn_link_4() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1625,7 +2323,7 @@ mod tests { #[test] fn test_rename_in_erlang_spawn_link_4() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1647,7 +2345,7 @@ mod tests { #[test] fn test_rename_in_spawn_monitor() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1669,7 +2367,7 @@ mod tests { #[test] fn test_rename_in_erlang_spawn_monitor() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1691,7 +2389,7 @@ mod tests { #[test] fn test_rename_in_spawn_monitor_4() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1713,7 +2411,7 @@ mod tests { #[test] fn test_rename_in_erlang_spawn_monitor_4() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1735,7 +2433,7 @@ mod tests { #[test] fn test_rename_in_spawn_opt() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1757,7 +2455,7 @@ mod tests { #[test] fn test_rename_in_erlang_spawn_opt() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1779,7 +2477,7 @@ mod tests { #[test] fn test_rename_in_spawn_opt_5() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1801,7 +2499,7 @@ mod tests { #[test] fn test_rename_in_erlang_spawn_opt_5() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1823,7 +2521,7 @@ mod tests { #[test] fn test_rename_in_spawn_request() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1845,7 +2543,7 @@ mod tests { #[test] fn test_rename_in_erlang_spawn_request() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1867,7 +2565,7 @@ mod tests { #[test] fn test_rename_in_erpc_call_4() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1889,7 +2587,7 @@ mod tests { #[test] fn test_rename_in_erpc_call_5() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1911,7 +2609,7 @@ mod tests { #[test] fn test_rename_in_erpc_cast() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1933,7 +2631,7 @@ mod tests { #[test] fn test_rename_in_erpc_multicall_4() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1955,7 +2653,7 @@ mod tests { #[test] fn test_rename_in_erpc_multicall_5() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1977,7 +2675,7 @@ mod tests { #[test] fn test_rename_in_erpc_multicast() { - check( + check_rename( "new_name", r#" //- /src/baz.erl @@ -1999,23 +2697,406 @@ mod tests { #[test] fn test_rename_in_erpc_send_request() { - check( + 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."#, + 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. + "#, ); } } diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 4b2348f610..0aa731c8c9 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/]). + -export([all/0]). main() -> ok. "#, diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index fba6d12d73..d09ec201f8 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -311,6 +311,7 @@ mod tests { fn test_fn_signature_local_two_args() { check( r#" +//- expect_parse_errors -module(main). -spec add(integer(), integer()) -> integer(). @@ -343,6 +344,7 @@ main() -> ); check( r#" +//- expect_parse_errors -module(main). -spec add(integer(), integer()) -> integer(). @@ -375,6 +377,7 @@ main() -> ); check( r#" +//- expect_parse_errors -module(main). -spec add(integer(), integer()) -> integer(). @@ -411,6 +414,7 @@ main() -> fn test_fn_signature_remote_two_args() { check( r#" +//- expect_parse_errors //- /one.erl -module(one). @@ -449,6 +453,7 @@ main() -> ); check( r#" +//- expect_parse_errors //- /one.erl -module(one). @@ -487,6 +492,7 @@ main() -> ); check( r#" +//- expect_parse_errors //- /one.erl -module(one). @@ -529,6 +535,7 @@ main() -> fn test_fn_signature_quoted_remote_two_args() { check( r#" +//- expect_parse_errors //- /Elixir.One.erl -module('Elixir.One'). @@ -576,6 +583,7 @@ main() -> fn test_fn_signature_unclosed_call() { check( r#" +//- expect_parse_errors -module(main). -compile(export_all). @@ -626,6 +634,7 @@ main() -> fn test_fn_signature_doc() { check( r#" +//- expect_parse_errors -module(main). -compile(export_all). @@ -685,6 +694,7 @@ main() -> if supports_eep59_doc_attributes() { check( r#" +//- expect_parse_errors -module(main). -compile(export_all). @@ -753,6 +763,7 @@ main() -> fn test_fn_signature_local_imported() { check( r#" +//- expect_parse_errors //- /one.erl -module(one). -compile(export_all). @@ -794,6 +805,7 @@ 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 418adf88da..55e9494e48 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,7 +376,10 @@ pub(crate) fn check_diagnostics(fixture: &str) { let config = DiagnosticsConfig::default() .set_experimental(true) .disable(DiagnosticCode::UnspecificInclude) - .disable(DiagnosticCode::BinaryStringToSigil); + .disable(DiagnosticCode::BinaryStringToSigil) + .disable(DiagnosticCode::HirUnresolvedMacro) + .disable(DiagnosticCode::BoundVarInLhs) + .disable(DiagnosticCode::HirUnresolvedInclude); check_diagnostics_with_config(config, fixture) } @@ -396,7 +399,26 @@ fn convert_diagnostics_to_annotations(diagnostics: Vec) -> Vec<(Text Severity::Information => "information", }); annotation.push_str(": "); + 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::>(); @@ -509,7 +531,8 @@ 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(diagnostics, extra_diags.clone()); + let diagnostics = + diagnostics::attach_related_diagnostics(file_id, diagnostics, extra_diags.clone()); let expected = fixture.annotations_by_file_id(&file_id); let actual = convert_diagnostics_to_annotations(diagnostics); @@ -522,6 +545,7 @@ 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![]); } @@ -672,11 +696,12 @@ mod test { fn filtered_diagnostics_passes_syntax_errors() { check_filtered_diagnostics( r#" - %%<^^^^^^^^^^^^ error: no module definition + //- expect_parse_errors + %%<^^^^^^^^^^^^ 💡 error: L1201: no module definition foo() -> bug bug. - %% ^^^^ error: Syntax Error - + %% ^^^^ error: P1711: Syntax Error + "#, &filter, ) diff --git a/crates/ide_assists/Cargo.toml b/crates/ide_assists/Cargo.toml index 167e1f4b11..b2277cd12d 100644 --- a/crates/ide_assists/Cargo.toml +++ b/crates/ide_assists/Cargo.toml @@ -9,7 +9,6 @@ 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 b1f51a7b90..87a511fbff 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 662e31b3e9..65ae663518 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 384ac8a65b..2821e9214e 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 69dbb1c55d..055395af52 100644 --- a/crates/ide_assists/src/handlers/inline_function.rs +++ b/crates/ide_assists/src/handlers/inline_function.rs @@ -22,6 +22,7 @@ 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; @@ -32,7 +33,6 @@ 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 bb2a38cf1b..121b1dda41 100644 --- a/crates/ide_assists/src/helpers.rs +++ b/crates/ide_assists/src/helpers.rs @@ -20,6 +20,8 @@ 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; @@ -34,8 +36,6 @@ 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_assists/src/lib.rs b/crates/ide_assists/src/lib.rs index 12f4b837b7..7f03139e6f 100644 --- a/crates/ide_assists/src/lib.rs +++ b/crates/ide_assists/src/lib.rs @@ -86,7 +86,7 @@ mod handlers { pub(crate) fn all() -> &'static [Handler] { &[ - // These are alphabetic for the foolish consistency + // These affect the order of display in the UI add_doc::add_doc, add_fixme::add_fixme, add_format::add_format, @@ -97,22 +97,15 @@ mod handlers { delete_function::delete_function, export_function::export_function, export_type::export_type, - extract_function::extract_function, + // Put extract variable before extract function, so it is + // easier to access, as it is used more frequently extract_variable::extract_variable, + extract_function::extract_function, flip_sep::flip_sep, ignore_variable::ignore_variable, implement_behaviour::implement_behaviour, inline_function::inline_function, inline_local_variable::inline_local_variable, - // These are manually sorted for better priorities. By default, - // priority is determined by the size of the target range (smaller - // target wins). If the ranges are equal, position in this list is - // used as a tie-breaker. - // add_missing_impl_members::add_missing_impl_members, - // add_missing_impl_members::add_missing_default_members, - - // Are you sure you want to add new assist here, and not to the - // sorted list above? ] } } diff --git a/crates/ide_completion/src/attributes.rs b/crates/ide_completion/src/attributes.rs index fc97832d30..f381df147d 100644 --- a/crates/ide_completion/src/attributes.rs +++ b/crates/ide_completion/src/attributes.rs @@ -166,6 +166,7 @@ mod test { fn test_error_recovery() { check( r#" + //- expect_parse_errors //- /src/sample.erl -module(sample1). % U.S. English @@ -180,6 +181,7 @@ mod test { check( r#" + //- expect_parse_errors //- /src/sample.erl -module(sample1). % U.K. English @@ -197,6 +199,7 @@ mod test { fn test_typing_attribute() { check( r#" + //- expect_parse_errors -module(sample). -typ~ "#, @@ -211,6 +214,7 @@ mod test { fn test_module_attribute() { check( r#" + //- expect_parse_errors -mod~ "#, None, @@ -224,6 +228,7 @@ mod test { fn test_module_attribute_hyphen() { check( r#" + //- expect_parse_errors //- /src/my-module.erl -mod~ "#, @@ -238,6 +243,7 @@ mod test { fn test_module_attribute_at() { check( r#" + //- expect_parse_errors //- /src/my@module.erl -mod~ "#, @@ -252,6 +258,7 @@ mod test { fn test_module_attribute_underscore() { check( r#" + //- expect_parse_errors //- /src/my_module.erl -mod~ "#, @@ -266,6 +273,7 @@ mod test { fn test_module_attribute_uppercase() { check( r#" + //- expect_parse_errors //- /src/Module.erl -mod~ "#, @@ -280,6 +288,7 @@ 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 22e385e3fa..0d9381e7ec 100644 --- a/crates/ide_completion/src/ctx.rs +++ b/crates/ide_completion/src/ctx.rs @@ -281,6 +281,7 @@ mod ctx_tests { fn expr_ctx() { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test() -> ~X. @@ -290,6 +291,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test() -> case 1 of. @@ -301,6 +303,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test() -> fun(_) -> ~X end. @@ -310,6 +313,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test() -> try 1 @@ -353,6 +357,7 @@ mod ctx_tests { fn ctx_pattern() { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test(Y, X) -> ~Y = X. @@ -362,6 +367,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test(X) -> case rand:uniform(1) of @@ -373,6 +379,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test(X) -> fun(X~) -> 1 end. @@ -382,6 +389,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test() -> receive @@ -393,6 +401,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test() -> try [1] @@ -407,6 +416,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test(X) -> if @@ -429,6 +439,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test(Y, X) -> try ok of @@ -440,6 +451,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test(Y, X) -> try ok of @@ -457,6 +469,7 @@ mod ctx_tests { fn ctx_pattern_error_recovery_wip() { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test(Y, X) -> try ok of @@ -469,6 +482,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test(Y, X) -> try ok of @@ -485,6 +499,7 @@ mod ctx_tests { fn test_type_param_ctx() { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -type ty(s~) :: ok. "#), @@ -496,6 +511,7 @@ mod ctx_tests { fn test_export_ctx() { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -export([ f~ @@ -509,6 +525,7 @@ mod ctx_tests { fn test_export_type_ctx() { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -export_type([ t~ @@ -522,6 +539,7 @@ mod ctx_tests { fn test_spec_ctx() { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -spec t~ table() -> ok. @@ -535,6 +553,7 @@ mod ctx_tests { fn test_type_ctx() { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -spec test() -> ~ test() -> ok. @@ -544,6 +563,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -spec test() -> o~k test() -> ok. @@ -553,6 +573,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -spec test(o~) -> ok. test() -> ok. @@ -562,6 +583,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -record(foo, {field1, field2 :: X~}). "#), @@ -570,6 +592,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -opaque test() :: ~. "#), @@ -578,6 +601,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -nominal test() :: ~. "#), @@ -586,6 +610,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -type test() :: m~ "#), @@ -594,6 +619,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -spec test() -> ~ok. "#), @@ -605,6 +631,7 @@ mod ctx_tests { fn test_ctx_error_recovery() { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test() -> ~ @@ -614,6 +641,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test() -> X + ~ @@ -623,6 +651,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test() -> X + ~. @@ -632,6 +661,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test() -> case rand:uniform(1) of @@ -643,6 +673,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test() -> (erlang:term_to_binary(~ @@ -653,6 +684,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). test() -> (erlang:term_to_binary(~. @@ -663,6 +695,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -type ty() :: ~ "#), @@ -671,6 +704,7 @@ mod ctx_tests { assert_eq!( ctx(r#" + //- expect_parse_errors -module(sample). -type ty() :: l~. "#), @@ -679,6 +713,7 @@ 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 f362ea830a..ef803eb9ab 100644 --- a/crates/ide_completion/src/export_functions.rs +++ b/crates/ide_completion/src/export_functions.rs @@ -83,6 +83,7 @@ mod test { check( r#" + //- expect_parse_errors -module(sample). -export([ foo~ @@ -106,6 +107,7 @@ 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 9e80828b66..c21a37339e 100644 --- a/crates/ide_completion/src/export_types.rs +++ b/crates/ide_completion/src/export_types.rs @@ -79,6 +79,7 @@ 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 4ce641d0e9..eab033765f 100644 --- a/crates/ide_completion/src/functions.rs +++ b/crates/ide_completion/src/functions.rs @@ -243,6 +243,7 @@ mod test { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -265,6 +266,7 @@ mod test { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -338,6 +340,7 @@ mod test { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -360,6 +363,7 @@ mod test { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -379,12 +383,14 @@ 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() -> @@ -413,6 +419,7 @@ mod test { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -441,6 +448,7 @@ mod test { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -466,6 +474,7 @@ mod test { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -584,6 +593,7 @@ mod test { fn test_remote_fun_exprs_with_trigger() { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). main(_) -> @@ -607,6 +617,7 @@ mod test { fn test_local_fun_exprs_with_trigger() { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). foo() -> ok. @@ -622,6 +633,7 @@ mod test { fn test_local_fun_exprs_no_trigger() { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). foo() -> ok. @@ -637,6 +649,7 @@ mod test { fn function_error_recovery() { check( r#" + //- expect_parse_errors -module(sample1). foo() -> b~ @@ -650,6 +663,7 @@ mod test { ); check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -668,6 +682,7 @@ mod test { fn test_local_and_remote() { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). samba() -> ok. @@ -688,6 +703,7 @@ mod test { fn test_remote_call_broken_case() { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). test() -> @@ -709,6 +725,7 @@ mod test { fn test_local_call_broken_case() { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). foo() -> ok. @@ -802,6 +819,7 @@ mod test { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -820,6 +838,7 @@ mod test { ); check( r#" +//- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -839,6 +858,7 @@ foo(X, Y) -> ok. ); check( r#" +//- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -902,6 +922,7 @@ 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"}). @@ -922,6 +943,7 @@ foo(X, Y) -> ok. fn test_in_dialyzer_attribute() { check( r#" + //- expect_parse_errors -module(main). -export([ foo/1, @@ -942,6 +964,7 @@ 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 734afc80a5..dc60ae8158 100644 --- a/crates/ide_completion/src/keywords.rs +++ b/crates/ide_completion/src/keywords.rs @@ -141,6 +141,7 @@ mod test { fn test_no_keywords() { check( r#" + //- expect_parse_errors -module(sample). test(X) -> a~ @@ -150,6 +151,7 @@ mod test { ); check( r#" + //- expect_parse_errors -module(sample). test(~X) -> X. @@ -160,6 +162,7 @@ mod test { check( r#" + //- expect_parse_errors -module(m~). "#, None, @@ -168,6 +171,7 @@ mod test { check( r#" + //- expect_parse_errors -module(m). -~ "#, @@ -177,6 +181,7 @@ mod test { check( r#" + //- expect_parse_errors -module(m). -type foo() :: ~. "#, @@ -191,6 +196,7 @@ mod test { fn test_keywords_error_recovery() { check( r#" + //- expect_parse_errors -module(sample). test(X) -> X ~ @@ -234,6 +240,7 @@ 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 71b4ff02c0..f41aecdd67 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 +// @fb-only: mod meta_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 + // @fb-only: || meta_only::add_completions(&mut acc, ctx) || 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 3c4b77cfad..e86cf3ba93 100644 --- a/crates/ide_completion/src/macros.rs +++ b/crates/ide_completion/src/macros.rs @@ -253,6 +253,7 @@ mod test { check( r#" + //- expect_parse_errors -module(sample1). -define(FOO, 1). -define(FOO(), 1). @@ -271,6 +272,7 @@ mod test { check( r#" + //- expect_parse_errors -module(sample1). -define(FOO, 1). -define(BAR, 1). @@ -282,6 +284,7 @@ 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 4371793356..e232a7d8bc 100644 --- a/crates/ide_completion/src/maps.rs +++ b/crates/ide_completion/src/maps.rs @@ -214,6 +214,7 @@ mod test { fn test_local_type() { check( r#" + //- expect_parse_errors -module(test_local_type). -type my_map() :: #{field1 := integer(), field2 => boolean()}. foo(X) -> #~ @@ -229,6 +230,7 @@ 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 @@ -250,6 +252,7 @@ mod test { fn test_empty_map_type() { check( r#" + //- expect_parse_errors -module(test_empty_map_type). -type my_map() :: #{}. foo(X) -> #~ @@ -265,6 +268,7 @@ 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) -> #~ @@ -280,6 +284,7 @@ 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}). @@ -297,6 +302,7 @@ 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()}}. @@ -315,11 +321,12 @@ 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()). @@ -338,11 +345,12 @@ 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()). @@ -359,6 +367,7 @@ 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 820d04cfe8..3823339f78 100644 --- a/crates/ide_completion/src/modules.rs +++ b/crates/ide_completion/src/modules.rs @@ -132,6 +132,7 @@ 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 cf8e0abc7c..d66e054423 100644 --- a/crates/ide_completion/src/records.rs +++ b/crates/ide_completion/src/records.rs @@ -320,6 +320,7 @@ mod test { fn test_record_name() { check( r#" + //- expect_parse_errors -module(sample). -record(this_record, {field1=1, field2=2}). -record(that_record, {}). @@ -334,6 +335,7 @@ mod test { check( r#" + //- expect_parse_errors -module(sample). -record(this_record, {field1=1, field2=2}). -record(that_record, {}). @@ -353,6 +355,7 @@ mod test { // Irregular names are quoted. check( r#" + //- expect_parse_errors -module(sample). -record('this.record', {field1=1, field2=2}). -record('that$record', {}). @@ -369,6 +372,7 @@ 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~. @@ -381,6 +385,7 @@ mod test { check( r#" + //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> X#rec{field1 = 1, field2~. @@ -393,6 +398,7 @@ mod test { check( r#" + //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> case ok of @@ -404,6 +410,7 @@ mod test { check( r#" + //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> case ok of @@ -417,6 +424,7 @@ mod test { check( r#" + //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> case ok of @@ -433,6 +441,7 @@ 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, {}). @@ -450,6 +459,7 @@ 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 6a0061e914..cc853af865 100644 --- a/crates/ide_completion/src/spec.rs +++ b/crates/ide_completion/src/spec.rs @@ -109,6 +109,7 @@ mod test { check( r#" + //- expect_parse_errors -module(sample). frog() -> ok. @@ -129,6 +130,7 @@ 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 3800a97b5c..e232ab2944 100644 --- a/crates/ide_completion/src/types.rs +++ b/crates/ide_completion/src/types.rs @@ -169,6 +169,7 @@ mod test { check( r#" + //- expect_parse_errors //- /src/sample.erl -module(sample). -type alias() :: ok. @@ -197,6 +198,7 @@ mod test { check( r#" + //- expect_parse_errors //- /src/sample.erl -module(sample). -type alias() :: ok. @@ -225,6 +227,7 @@ mod test { check( r#" + //- expect_parse_errors //- /src/sample.erl -module(sample). -spec foo() -> sample2:~. @@ -248,6 +251,7 @@ mod test { // something reasonable (show nothing) check( r#" + //- expect_parse_errors //- /src/sample.erl -module(sample). -spec foo() -> sample~:. @@ -263,6 +267,7 @@ 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 65740d56a4..5544475ed3 100644 --- a/crates/ide_completion/src/vars.rs +++ b/crates/ide_completion/src/vars.rs @@ -100,6 +100,7 @@ mod test { fn test_local_variables_1() { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). test(AnArg1,Blah) -> @@ -117,6 +118,7 @@ mod test { fn test_local_variables_limit_to_current_function() { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). another(AnArgNotMatched) -> @@ -142,6 +144,7 @@ mod test { fn test_local_variables_none_if_space() { check( r#" + //- expect_parse_errors //- /src/sample1.erl -module(sample1). test(AnArg1,Blah) -> @@ -157,6 +160,7 @@ 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 babeee31b9..927391ba93 100644 --- a/crates/ide_db/Cargo.toml +++ b/crates/ide_db/Cargo.toml @@ -12,15 +12,16 @@ 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 @@ -35,6 +36,7 @@ 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 d3e73636bd..ec1e1d76cf 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 +// @fb-only: use crate::meta_only::MetaOnlyDiagnosticCode; -// @fb-only +// @fb-only: pub const BASE_URL: &str = crate::meta_only::BASE_URL; pub const BASE_URL: &str = "https://whatsapp.github.io/erlang-language-platform/docs"; // @oss-only #[derive(Clone, Debug, PartialEq, Eq, Hash, EnumIter)] @@ -52,6 +52,7 @@ pub enum DiagnosticCode { DependentHeader, DeprecatedFunction, UndefinedFunction, + UnavailableType, Unexpected(String), ExpressionCanBeSimplified, CannotEvaluateCTCallbacks, @@ -89,6 +90,10 @@ pub enum DiagnosticCode { NoErrorLogger, NoNoWarnSuppressions, CouldBeAStringLiteral, + ListsReverseAppend, + HirUnresolvedMacro, + HirUnresolvedInclude, + BoundVarInLhs, // Wrapper for erlang service diagnostic codes ErlangService(String), @@ -96,7 +101,7 @@ pub enum DiagnosticCode { Eqwalizer(String), // Used for ad-hoc diagnostics via lints/codemods AdHoc(String), - // @fb-only + // @fb-only: MetaOnly(MetaOnlyDiagnosticCode), } // These namespaces map the error codes returned by the Erlang Service. @@ -112,7 +117,7 @@ pub enum Namespace { Parser, EDoc, WhatsApp, - // @fb-only + // @fb-only: MetaOnly, } impl fmt::Display for Namespace { @@ -127,7 +132,7 @@ impl fmt::Display for Namespace { Namespace::Parser => "p", Namespace::EDoc => "o", Namespace::WhatsApp => "w", - // @fb-only + // @fb-only: Namespace::MetaOnly => "meta_only", }; write!(f, "{namespace}") } @@ -160,7 +165,7 @@ impl Namespace { pub fn supports_doc_path(&self) -> bool { match self { Namespace::WhatsApp => true, - // @fb-only + // @fb-only: Namespace::MetaOnly => true, _ => false, } } @@ -248,10 +253,15 @@ 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 + // @fb-only: DiagnosticCode::MetaOnly(c) => c.as_code(), } } @@ -263,6 +273,7 @@ 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(), @@ -344,11 +355,15 @@ 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 + // @fb-only: DiagnosticCode::MetaOnly(c) => c.as_label(), } } @@ -359,7 +374,7 @@ impl DiagnosticCode { pub fn maybe_from_string(s: &str) -> Option { DIAGNOSTIC_CODE_LOOKUPS .get(s).cloned() - // @fb-only + // @fb-only: .or_else(|| MetaOnlyDiagnosticCode::from_str(s).ok().map(DiagnosticCode::MetaOnly)) .or_else( || // Look for ErlangService and AdHoc if let Some(code) = Self::is_adhoc(s) { @@ -376,7 +391,7 @@ impl DiagnosticCode { match self { DiagnosticCode::DefaultCodeForEnumIter => None, DiagnosticCode::AdHoc(_) => None, - // @fb-only + // @fb-only: DiagnosticCode::MetaOnly(_) => Some(Namespace::MetaOnly), DiagnosticCode::ErlangService(code) => Namespace::from_str(code).ok(), _ => Namespace::from_str(&self.as_code()).ok(), } @@ -385,7 +400,7 @@ impl DiagnosticCode { pub fn supports_doc_path(&self) -> bool { match self { DiagnosticCode::DefaultCodeForEnumIter => false, - // @fb-only + // @fb-only: DiagnosticCode::MetaOnly(MetaOnlyDiagnosticCode::DefaultCodeForEnumIter) => false, _ => true, } } @@ -474,6 +489,7 @@ impl DiagnosticCode { DiagnosticCode::ModuleMismatch => false, DiagnosticCode::UnusedInclude => false, DiagnosticCode::BoundVarInPattern => false, + DiagnosticCode::BoundVarInLhs => false, DiagnosticCode::UnusedMacro => false, DiagnosticCode::UnusedRecordField => false, DiagnosticCode::MutableVarBug => false, @@ -488,6 +504,7 @@ impl DiagnosticCode { DiagnosticCode::DependentHeader => false, DiagnosticCode::DeprecatedFunction => false, DiagnosticCode::UndefinedFunction => false, + DiagnosticCode::UnavailableType => false, DiagnosticCode::Unexpected(_) => false, DiagnosticCode::ExpressionCanBeSimplified => false, DiagnosticCode::UnnecessaryFlatteningToFindFlatLength => false, @@ -520,12 +537,15 @@ 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 + // @fb-only: DiagnosticCode::MetaOnly(code) => code.allows_fixme_comment(), } } diff --git a/crates/ide_db/src/docs.rs b/crates/ide_db/src/docs.rs index 655a784cab..f7a96225b0 100644 --- a/crates/ide_db/src/docs.rs +++ b/crates/ide_db/src/docs.rs @@ -137,7 +137,9 @@ impl ToDoc for InFile<&ast::Remote> { let name_arity = fun_def.name; docs.function_doc(file_id, name_arity) } - CallDef::Type(_) | CallDef::FuzzyType(_) => None, + CallDef::Type(type_def) | CallDef::FuzzyType(type_def) => { + docs.type_doc(type_def.file.file_id, type_def.name().clone()) + } } } else { None @@ -152,7 +154,9 @@ impl ToDoc for InFile<&ast::Call> { CallDef::Function(fun_def) | CallDef::FuzzyFunction(fun_def) => { docs.function_doc(fun_def.file.file_id, fun_def.name) } - CallDef::Type(_) | CallDef::FuzzyType(_) => None, + CallDef::Type(type_def) | CallDef::FuzzyType(type_def) => { + docs.type_doc(type_def.file.file_id, type_def.name().clone()) + } } } else { None diff --git a/crates/ide_db/src/eqwalizer.rs b/crates/ide_db/src/eqwalizer.rs index 4deed79778..fca577bb21 100644 --- a/crates/ide_db/src/eqwalizer.rs +++ b/crates/ide_db/src/eqwalizer.rs @@ -12,7 +12,6 @@ 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; @@ -89,7 +88,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, include_tests: bool) -> bool; + fn is_eqwalizer_enabled(&self, file_id: FileId) -> bool; } pub fn eqwalizer_diagnostics_by_project( @@ -114,7 +113,7 @@ fn type_at_position( db: &dyn EqwalizerDatabase, range: FileRange, ) -> Option> { - if !db.is_eqwalizer_enabled(range.file_id, false) { + if !db.is_eqwalizer_enabled(range.file_id) { return None; } let project_id = db.file_app_data(range.file_id)?.project_id; @@ -149,7 +148,7 @@ fn type_at_position( } fn types_for_file(db: &dyn EqwalizerDatabase, file_id: FileId) -> Option>> { - if !db.is_eqwalizer_enabled(file_id, false) { + if !db.is_eqwalizer_enabled(file_id) { return None; } let project_id = db.file_app_data(file_id)?.project_id; @@ -162,7 +161,7 @@ fn types_for_file(db: &dyn EqwalizerDatabase, file_id: FileId) -> Option bool { +fn is_eqwalizer_enabled(db: &dyn EqwalizerDatabase, file_id: FileId) -> bool { if !otp_supported_by_eqwalizer() { return false; } @@ -178,11 +177,8 @@ fn is_eqwalizer_enabled(db: &dyn EqwalizerDatabase, file_id: FileId, include_tes 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 && (is_src || is_test_opted_in)) || db.has_eqwalizer_module_marker(file_id); + let opt_in = global_opt_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 cad66d9e48..038b41f0be 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,11 +43,22 @@ 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 { - if let Some(call) = ast::Call::cast(syntax.parent()?) { - Some(call) + 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) } else { - ast::Call::cast(syntax.parent()?.parent()?) + ast::ExternalFun::cast(syntax.parent()?.parent()?) } } diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index 0240d8498d..aecfd86473 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs @@ -57,15 +57,17 @@ pub mod docs; pub mod eqwalizer; mod erl_ast; mod line_index; -// @fb-only +// @fb-only: pub mod meta_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; @@ -383,7 +385,7 @@ impl TypedSemantic for RootDatabase { let project_id = app_data.project_id; - let eqwalizer_enabled = self.is_eqwalizer_enabled(file_id, false); + let eqwalizer_enabled = self.is_eqwalizer_enabled(file_id); if !eqwalizer_enabled { return Some(vec![]); } @@ -419,8 +421,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] @@ -446,4 +448,17 @@ 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 c25ee41e2a..bd5a49f8cf 100644 --- a/crates/ide_db/src/rename.rs +++ b/crates/ide_db/src/rename.rs @@ -15,19 +15,24 @@ 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; @@ -79,6 +84,45 @@ 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, @@ -95,7 +139,10 @@ impl SymbolDefinition { ) -> RenameResult { match self.clone() { SymbolDefinition::Module(_) => { - rename_error!("Cannot rename 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) } SymbolDefinition::Function(fun) => { if safety_check == SafetyChecks::Yes && !is_valid_function_name(new_name) { @@ -117,14 +164,58 @@ impl SymbolDefinition { SymbolDefinition::RecordField(_) => { rename_error!("Cannot rename record field") } - SymbolDefinition::Type(_) => { - rename_error!("Cannot rename type") + 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::Callback(_) => { rename_error!("Cannot rename callback") } - SymbolDefinition::Define(_) => { - rename_error!("Cannot rename define") + 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::Header(_) => { rename_error!("Cannot rename header") @@ -151,6 +242,27 @@ 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, } } @@ -215,6 +327,40 @@ 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 { @@ -249,6 +395,7 @@ 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 _ => { @@ -256,6 +403,184 @@ 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( @@ -388,6 +713,32 @@ 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 20b4f050b4..1e66598359 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)] +#[derive(Debug, Clone, PartialEq, Eq)] 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 bb64431772..60b62279fe 100644 --- a/crates/ide_db/src/source_change.rs +++ b/crates/ide_db/src/source_change.rs @@ -20,19 +20,46 @@ use std::mem; use elp_base_db::AnchoredPathBuf; use elp_base_db::FileId; use elp_syntax::SyntaxNode; -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 elp_syntax::TextRange; +use elp_syntax::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, } @@ -46,6 +73,7 @@ impl SourceChange { ) -> Self { SourceChange { source_file_edits, + new_file_edits: FxHashMap::default(), file_system_edits, is_snippet: false, } @@ -74,6 +102,22 @@ 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); } @@ -85,12 +129,15 @@ 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.source_file_edits.is_empty() + && self.file_system_edits.is_empty() + && self.new_file_edits.is_empty() } pub fn text_range(&self, file_id: FileId) -> Option { @@ -116,10 +163,18 @@ 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, } @@ -171,7 +226,7 @@ impl SourceChangeBuilder { fn commit(&mut self) { if let Some(tm) = self.mutated_tree.take() { - algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit) + diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit) } let edit = mem::take(&mut self.edit).finish(); @@ -265,6 +320,7 @@ 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/text_edit/src/lib.rs b/crates/ide_db/src/text_edit.rs similarity index 99% rename from crates/text_edit/src/lib.rs rename to crates/ide_db/src/text_edit.rs index 42dac0f3ac..0410102569 100644 --- a/crates/text_edit/src/lib.rs +++ b/crates/ide_db/src/text_edit.rs @@ -15,7 +15,6 @@ //! `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/crates/ide_db/src/tree_diff.rs b/crates/ide_db/src/tree_diff.rs new file mode 100644 index 0000000000..5bca5c2ec2 --- /dev/null +++ b/crates/ide_db/src/tree_diff.rs @@ -0,0 +1,507 @@ +/* + * 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 108680853e..881a5ac123 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 8289482442..45c6b7f732 100644 --- a/crates/project_model/src/buck.rs +++ b/crates/project_model/src/buck.rs @@ -12,6 +12,7 @@ use core::str; use std::borrow::Cow; use std::convert::TryFrom; use std::fmt; +use std::path::Path; use std::path::PathBuf; use std::process; use std::process::Command; @@ -34,6 +35,7 @@ use paths::RelPathBuf; use paths::Utf8PathBuf; use regex::Regex; use serde::Deserialize; +use serde::Deserializer; use serde::Serialize; use thiserror::Error; @@ -43,6 +45,7 @@ use crate::CommandProxy; use crate::ElpConfig; use crate::ProjectAppData; use crate::ProjectModelError; +use crate::json; use crate::otp::Otp; pub type TargetFullName = String; @@ -55,6 +58,7 @@ lazy_static! { } const ERL_EXT: &str = "erl"; +const BUCK_ISOLATION_DIR: &str = "lsp"; #[derive( Debug, @@ -85,6 +89,14 @@ 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 { @@ -97,7 +109,7 @@ impl BuckConfig { cmd.env_remove("RUST_BACKTRACE") .env_remove("RUST_LIB_BACKTRACE"); cmd.arg("--isolation-dir"); - cmd.arg("lsp"); + cmd.arg(BUCK_ISOLATION_DIR); cmd.current_dir(self.buck_root()); CommandProxy::new(guard, cmd) } @@ -326,6 +338,7 @@ impl IncludeMapping { impl BuckProject { pub fn load_from_config( buck_conf: &BuckConfig, + elp_config: &ElpConfig, query_config: &BuckQueryConfig, report_progress: &impl Fn(&str), ) -> Result< @@ -349,7 +362,7 @@ impl BuckProject { }; let otp_root = Otp::find_otp()?; // TODO: we now get these twice. Perhaps they should be cached? - let (_otp, otp_project_apps) = Otp::discover(otp_root.clone()); + let (_otp, otp_project_apps) = Otp::discover(otp_root.clone(), &elp_config.otp); include_mapping.add_otp(&otp_project_apps); Ok(( project, @@ -448,8 +461,6 @@ pub struct BuckTarget { /// to build the graph. #[serde(default)] extra_includes: Vec, - #[serde(default)] - origin: BuckTargetOrigin, } impl BuckTarget { @@ -460,6 +471,155 @@ impl BuckTarget { AppName(self.name.clone()) } } + + fn is_generated(&self) -> bool { + self.labels.contains("generated") + } +} + +#[derive(Debug, PartialEq, Eq)] +enum BuckTargetType { + App, + Test, + Other(String), +} + +impl<'de> Deserialize<'de> for BuckTargetType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + match s.as_str() { + "prelude//rules.bzl:erlang_app" => Ok(BuckTargetType::App), + "prelude//rules.bzl:erlang_test" => Ok(BuckTargetType::Test), + other => { + log::info!("Ignoring buck target type: {}", &other); + Ok(BuckTargetType::Other(other.to_string())) + } + } + } +} + +/// The interface type used in reading the output of running `buck2 target --json` +#[derive(Deserialize, Debug)] +pub struct BuckTargetBare { + // Note that some of the fields are of type `serde_json::Value`. + // + // This is because for some target types that we are not + // interested in they are not simple lists of strings, so fail + // serialization, and there is no point having a complex rust type + // for a thing we don't care about. + // + // We can only make this decision after extracting the `buck_type` + // field and filtering for the target types we care about, so we + // initially deserialize the problematic fields to `Value`, and + // complete it when we use them. + // + // This also gives much better error messages, since `serde_json` + // is optimised for this, whereas deserializing from a `Value` + // gives no useful information. + name: String, + #[serde(default)] + app_name: Option, + + #[serde(rename = "buck.package")] + buck_package: String, + + // Note: we are not using the following available fields + // _includes_target + // buck.deps + // buck.inputs + #[serde(rename = "buck.type")] + buck_type: BuckTargetType, + #[serde(default)] + labels: serde_json::Value, + + #[serde(default)] + applications: serde_json::Value, + #[serde(default)] + deps: serde_json::Value, + #[serde(default)] + extra_includes: Vec, + #[serde(default)] + included_applications: Vec, + #[serde(default)] + includes: Vec, + #[serde(default)] + srcs: serde_json::Value, + #[serde(default)] + suite: Option, +} + +impl BuckTargetBare { + fn target_full_name(&self) -> String { + if let Some(name) = &self.app_name { + format!("{}:{}", &self.buck_package, &name) + } else { + format!("{}:{}", &self.buck_package, &self.name) + } + } + + fn as_buck_target(bare: Self, cells: &BuckCellInfo) -> BuckTarget { + let srcs = match bare.srcs { + serde_json::Value::Array(values) => values + .iter() + .flat_map(|v| match v { + serde_json::Value::String(s) => Some(cells.make_absolute(s)), + _ => None, + }) + .collect(), + _ => vec![], + }; + let deps = Self::json_value_to_strings(&bare.deps); + let apps = Self::json_value_to_strings(&bare.applications); + let labels = Self::json_value_to_strings(&bare.labels) + .into_iter() + .collect(); + BuckTarget { + name: bare.name, + app_name: bare.app_name, + suite: bare.suite.map(|tgt| cells.make_absolute(&tgt)), + srcs, + includes: includes_directories_only(&cells.make_all_absolute(&bare.includes)), + labels, + gen_srcs: vec![], + deps, + apps, + included_apps: bare.included_applications, + extra_includes: bare + .extra_includes + .iter() + .map(|inc| { + inc.strip_suffix("_includes_only") + .unwrap_or(inc) + .to_string() + }) + .collect::>(), + } + } + + fn json_value_to_strings(val: &serde_json::Value) -> Vec { + match val { + serde_json::Value::Array(values) => values + .iter() + .flat_map(|v| match v { + serde_json::Value::String(s) => Some(s.clone()), + _ => None, + }) + .collect(), + _ => vec![], + } + } + + fn skipped_target_type(&self) -> bool { + match self.buck_type { + BuckTargetType::App => false, + BuckTargetType::Test => false, + + BuckTargetType::Other(_) => true, + } + } } #[derive(Debug, Eq, PartialEq, Clone)] @@ -479,6 +639,8 @@ pub struct Target { pub target_type: TargetType, /// true if there are .hrl files in the src dir pub private_header: bool, + /// true if generated via elp.bxl + pub buck_generated: bool, } impl Target { @@ -491,16 +653,20 @@ impl Target { } } - fn include_files(&self) -> Vec { - let mut include_files = self.include_files.clone(); + fn include_dirs(&self) -> Vec { + let mut include_dirs = FxHashSet::from_iter( + self.include_files + .iter() + .map(|path| include_path_from_file(path)), + ); if self.private_header { self.src_files.iter().for_each(|path| { if Some("hrl") == path.extension() { - include_files.push(include_path_from_file(path)); + include_dirs.insert(include_path_from_file(path)); } }); } - include_files + include_dirs.iter().cloned().collect() } } @@ -513,9 +679,23 @@ pub enum TargetType { ErlangTestUtils, } +fn includes_directories_only(includes: &[String]) -> Vec { + let mut set = FxHashSet::default(); + for inc in includes { + let full_path = Path::new(inc); + let path = full_path + .extension() + .and_then(|_| full_path.parent()) + .and_then(|p| p.to_str()) + .unwrap_or(inc); + set.insert(path); + } + set.iter().map(|s| s.to_string()).collect() +} + fn load_buck_targets_bxl( buck_config: &BuckConfig, - build: &BuckQueryConfig, + query_config: &BuckQueryConfig, report_progress: &impl Fn(&str), ) -> Result { let _timer = timeit!("loading info from buck"); @@ -528,26 +708,35 @@ fn load_buck_targets_bxl( FxHashMap::default() }; - match build { + match query_config { BuckQueryConfig::BuildGeneratedCode => { report_progress("Querying and generating buck targets") } - BuckQueryConfig::NoBuildGeneratedCode => report_progress("Querying buck targets"), + BuckQueryConfig::NoBuildGeneratedCode => { + report_progress("Querying buck targets without codegen") + } + BuckQueryConfig::BuckTargetsOnly => report_progress("Querying buck targets, phase 1"), } - let buck_targets = query_buck_targets(buck_config, build)?; + let result = query_buck_targets(buck_config, query_config)?; + let buck_targets = filter_buck_targets(buck_config, result)?; report_progress("Making target info"); let mut target_info = TargetInfo::default(); let mut used_deps = FxHashSet::default(); + let targets_include_prelude = buck_config + .included_targets + .iter() + .any(|t| t.starts_with("prelude//")); for (name, buck_target) in &buck_targets { if let Ok(target) = make_buck_target( root, name, buck_target, - buck_config.build_deps, + buck_config, + targets_include_prelude, &mut dep_path, &mut target_info, ) { @@ -567,55 +756,54 @@ fn make_buck_target( root: &AbsPathBuf, name: &String, target: &BuckTarget, - build_deps: bool, + buck_config: &BuckConfig, + targets_include_prelude: bool, dep_path: &mut FxHashMap, target_info: &mut TargetInfo, ) -> Result { let dir = find_app_root_bxl(root, name, target).expect("could not find app root"); - let (src_files, include_files, target_type, private_header, ebin) = - if let Some(ref suite) = target.suite { - let src_file = buck_path_to_abs_path(root, suite)?; - let src = vec![src_file.clone()]; - target_info - .path_to_target_name - .insert(src_file, name.clone()); - let mut include_files = vec![]; - for include in &target.includes { - if let Ok(inc) = AbsPathBuf::try_from(include.as_str()) { - include_files.push(inc); - } - } - (src, include_files, TargetType::ErlangTest, false, None) - } else { - let mut private_header = false; - let target_type = compute_target_type(name, target); - let mut src_files = vec![]; - for src in &target.srcs { - let src = buck_path_to_abs_path(root, src).unwrap(); - if Some("hrl") == src.extension() { - private_header = true; - } - src_files.push(src); - } - let mut include_files = vec![]; - for include in &target.includes { - let mut inc = buck_path_to_abs_path(root, include).unwrap(); - if inc.extension().is_some() { - inc.pop(); - } - include_files.push(inc); + let (src_files, target_type, private_header, ebin) = if let Some(ref suite) = target.suite { + let src_file = json::canonicalize(buck_path_to_abs_path(root, suite)?)?; + let src = vec![src_file.clone()]; + target_info + .path_to_target_name + .insert(src_file, name.clone()); + (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 mut src_files = vec![]; + for src in &target.srcs { + let src = json::canonicalize(buck_path_to_abs_path(root, src).unwrap())?; + if Some("hrl") == src.extension() { + private_header = true; } + src_files.push(src); + } - let ebin = match target_type { - TargetType::ThirdParty if build_deps => dep_path - .remove(name) - .map(|dir| dir.join(Utf8PathBuf::from("ebin"))), - TargetType::ThirdParty => Some(dir.clone()), - _ => None, - }; - (src_files, include_files, target_type, private_header, ebin) + let ebin = match target_type { + TargetType::ThirdParty if buck_config.build_deps => dep_path + .remove(name) + .map(|dir| dir.join(Utf8PathBuf::from("ebin"))), + TargetType::ThirdParty => Some(dir.clone()), + _ => None, }; + (src_files, target_type, private_header, ebin) + }; + let mut include_files = vec![]; + for include in &target.includes { + if let Ok(inc_abs) = buck_path_to_abs_path(root, include) + && let Ok(inc) = json::canonicalize(inc_abs) + { + include_files.push(inc); + } + } let gen_src_files = target .gen_srcs .iter() @@ -635,22 +823,28 @@ fn make_buck_target( ebin, target_type, private_header, + buck_generated: target.is_generated(), }) } -fn compute_target_type(name: &TargetFullName, target: &BuckTarget) -> TargetType { - if target.origin != BuckTargetOrigin::App && (name.starts_with("prelude//")) - || name.contains("//third-party") - { +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 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, + let is_test_application = test_application_labels + .iter() + .any(|label| target.labels.contains(label)); + if is_test_application { + TargetType::ErlangTestUtils + } else { + TargetType::ErlangApp } } } @@ -690,15 +884,24 @@ fn find_root(buck_config: &BuckConfig) -> Result { pub enum BuckQueryConfig { BuildGeneratedCode, NoBuildGeneratedCode, + /// Instead of using elp.bxl, use `buck2 targets`. + BuckTargetsOnly, } -fn query_buck_targets( - buck_config: &BuckConfig, - query_config: &BuckQueryConfig, -) -> Result> { - let _timer = timeit!("load buck targets"); - let result = query_buck_targets_bxl(buck_config, query_config)?; +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, +) -> Result> { let result = result .into_iter() .filter(|(name, _)| { @@ -718,7 +921,21 @@ fn query_buck_targets( Ok(result) } -pub fn query_buck_targets_bxl( +pub fn query_buck_targets( + buck_config: &BuckConfig, + query_config: &BuckQueryConfig, +) -> Result> { + let _timer = timeit!("load buck targets"); + let result = match query_config { + BuckQueryConfig::BuildGeneratedCode | BuckQueryConfig::NoBuildGeneratedCode => { + query_buck_targets_bxl(buck_config, query_config)? + } + BuckQueryConfig::BuckTargetsOnly => query_buck_targets_bare(buck_config)?, + }; + Ok(result) +} + +fn query_buck_targets_bxl( buck_config: &BuckConfig, build: &BuckQueryConfig, ) -> Result> { @@ -754,6 +971,12 @@ struct BuckCellInfo { } impl BuckCellInfo { + fn make_all_absolute(&self, list: &[String]) -> Vec { + list.iter() + .map(|buck_path| self.make_absolute(buck_path)) + .collect() + } + fn make_absolute(&self, target: &str) -> String { self.make_absolute_maybe(target) .unwrap_or(target.to_string()) @@ -834,6 +1057,41 @@ fn run_buck_command(mut command: CommandProxy<'_>) -> Result { Ok(output) } +fn query_buck_targets_bare(buck_config: &BuckConfig) -> Result> { + let cells = buck_cell_info()?; + + let bare_targets_apps = do_buck_query_bare(buck_config, &buck_config.included_targets)?; + let bare_targets_deps = do_buck_query_bare(buck_config, &buck_config.deps_targets)?; + + let mut result = FxHashMap::default(); + + let mut do_one = |bare: BuckTargetBare| { + if !bare.skipped_target_type() { + let target_full_name = bare.target_full_name(); + let target: BuckTarget = BuckTargetBare::as_buck_target(bare, &cells); + result.insert(target_full_name, target); + } + }; + for bare in bare_targets_apps { + do_one(bare); + } + for bare in bare_targets_deps { + do_one(bare); + } + Ok(result) +} + +fn do_buck_query_bare(buck_config: &BuckConfig, targets: &[String]) -> Result> { + let mut command = buck_config.buck_command(); + command.arg("targets").arg("--json").args(targets); + let output = run_buck_command(command)?; + let string = String::from_utf8(output.stdout)?; + let bare_targets: Vec = serde_json::from_str(&string)?; + Ok(bare_targets) +} + +// --------------------------------------------------------------------- + #[derive(Error, Debug)] pub struct BuckQueryError { pub command: String, @@ -1061,15 +1319,22 @@ fn targets_to_project_data_bxl( dir: target.dir.clone(), ebin: None, extra_src_dirs: extra_src_dirs.into_iter().collect(), - include_dirs: target.include_files(), + include_dirs: target.include_dirs(), abs_src_dirs: abs_src_dirs.into_iter().collect(), macros, parse_transforms: vec![], app_type: target.app_type(), include_path: vec![], gen_src_files: Some(FxHashSet::from_iter(target.gen_src_files.clone())), - applicable_files: Some(FxHashSet::from_iter(target.src_files.clone())), + applicable_files: Some(FxHashSet::from_iter( + target + .src_files + .iter() + .cloned() + .chain(target.include_files.iter().cloned()), + )), is_test_target: Some(target.target_type == TargetType::ErlangTest), + is_buck_generated: Some(target.buck_generated), }; // Do not bother with applications that exist purely as a // handle on dependencies for include_path. @@ -1098,36 +1363,56 @@ 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 output = buck_config - .buck_command() + let mut command = buck_config.buck_command(); + command .arg("audit") .arg("cell") .arg("prelude") - .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)?; + .arg("--json"); + let raw_output = check_buck_output_success(command)?; - lazy_static! { - static ref RE: Regex = Regex::new(r"^prelude: ([^\s]+)").unwrap(); + 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) } - let string = RE - .captures_iter(&raw_output) - .next() - .map(|c| c[1].to_string()) - .unwrap(); - Ok(string) +} + +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()) } #[cfg(test)] @@ -1141,13 +1426,14 @@ mod tests { use parking_lot::MutexGuard; use paths::AbsPath; use paths::Utf8Path; + use serde_json::Value; use super::BUCK_CELL_INFO; use super::BuckCellInfo; use crate::buck::BuckConfig; use crate::buck::BuckQueryError; use crate::buck::BuckTarget; - use crate::buck::BuckTargetOrigin; + use crate::buck::BuckTargetBare; use crate::buck::buck_path_to_abs_path; use crate::buck::find_app_root_bxl; use crate::buck::get_prelude_cell; @@ -1167,6 +1453,10 @@ 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(), @@ -1180,7 +1470,6 @@ mod tests { apps: vec![], included_apps: vec![], extra_includes: vec![], - origin: BuckTargetOrigin::App, }; let actual = find_app_root_bxl(root, &target_name, &target); @@ -1196,6 +1485,10 @@ 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(), @@ -1209,7 +1502,6 @@ mod tests { apps: vec![], included_apps: vec![], extra_includes: vec![], - origin: BuckTargetOrigin::App, }; let actual = find_app_root_bxl(root, &target_name, &target); @@ -1225,6 +1517,10 @@ 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(), @@ -1238,7 +1534,6 @@ mod tests { apps: vec![], included_apps: vec![], extra_includes: vec![], - origin: BuckTargetOrigin::App, }; let actual = find_app_root_bxl(root, &target_name, &target); @@ -1275,7 +1570,6 @@ mod tests { apps: vec![], included_apps: vec![], extra_includes: vec![], - origin: BuckTargetOrigin::App, }; let actual = find_app_root_bxl(root, &target_name, &target); @@ -1309,7 +1603,6 @@ mod tests { apps: vec![], included_apps: vec![], extra_includes: vec![], - origin: BuckTargetOrigin::App, }; let actual = find_app_root_bxl(root, &target_name, &target); @@ -1326,6 +1619,10 @@ 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(), @@ -1339,7 +1636,6 @@ mod tests { apps: vec![], included_apps: vec![], extra_includes: vec![], - origin: BuckTargetOrigin::App, }; let actual = find_app_root_bxl(root, &target_name, &target); @@ -1347,71 +1643,66 @@ 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) { - 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 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]/"); + + 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 BUCK_TESTS_ENABLED { + if cfg!(feature = "buck") { check_buck_bxl_query( false, expect![[r#" { - "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:auto_gen_a": { + "root//buck_tests_2/auto_gen/auto_gen_a:auto_gen_a": { "name": "auto_gen_a", "app_name": null, "suite": null, "srcs": [ - "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl" + "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl" ], "includes": [ - "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/include" + "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/include" ], "labels": [ "user_application" @@ -1421,7 +1712,7 @@ mod tests { "included_apps": [], "origin": "app" }, - "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:generated_srcs": { + "root//buck_tests_2/auto_gen/auto_gen_a:generated_srcs": { "name": "generated_srcs", "app_name": null, "suite": null, @@ -1564,23 +1855,23 @@ mod tests { #[test] #[ignore] fn build_info_buck_bxl_generated_query() { - if BUCK_TESTS_ENABLED { + if cfg!(feature = "buck") { // Note that there is now a value for `srcs` in the - // "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:generated_srcs" + // "root//buck_tests_2/auto_gen/auto_gen_a:generated_srcs" // target check_buck_bxl_query( true, expect![[r#" { - "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:auto_gen_a": { + "root//buck_tests_2/auto_gen/auto_gen_a:auto_gen_a": { "name": "auto_gen_a", "app_name": null, "suite": null, "srcs": [ - "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl" + "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl" ], "includes": [ - "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/include" + "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/include" ], "labels": [ "user_application" @@ -1590,12 +1881,12 @@ mod tests { "included_apps": [], "origin": "app" }, - "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:generated_srcs": { + "root//buck_tests_2/auto_gen/auto_gen_a:generated_srcs": { "name": "generated_srcs", "app_name": null, "suite": null, "srcs": [ - "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl" + "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl" ], "includes": [], "labels": [ @@ -1820,4 +2111,195 @@ mod tests { "#]] .assert_debug_eq(&cells.make_absolute("cell2//a/b/c.erl")); } + + #[test] + fn deserialize_buck_target_bare() { + let string = r#" + [ + { + "_includes_target": "cell//linter:app_a_includes_only", + "app_src": "cell//linter/app_a/src/app_a.app.src", + "applications": [], + "buck.deps": [ + "cell//linter:app_a_includes_only", + "prelude//erlang/shell:buck2_shell_utils", + "toolchains//:erlang-default" + ], + "buck.inputs": [ + "cell//linter/app_a/src/app_a.app.src", + "cell//linter/app_a/include/app_a.hrl", + "cell//linter/app_a/src/app_a.erl", + "cell//linter/app_a/src/app_a_edoc.erl", + "cell//linter/app_a/src/app_a_unused_param.erl", + "cell//linter/app_a/src/expression_updates_literal.erl", + "cell//linter/app_a/src/spelling.erl" + ], + "buck.oncall": "vscode_erlang", + "buck.package": "cell//linter", + "buck.type": "prelude//rules.bzl:erlang_app", + "extra_includes": [], + "included_applications": [], + "includes": [ + "cell//linter/app_a/include/app_a.hrl" + ], + "labels": [ + "user_application" + ], + "name": "app_a_target", + "app_name":"app_a", + "srcs": [ + "cell//linter/app_a/src/app_a.erl", + "cell//linter/app_a/src/app_a_edoc.erl", + "cell//linter/app_a/src/app_a_unused_param.erl", + "cell//linter/app_a/src/expression_updates_literal.erl", + "cell//linter/app_a/src/spelling.erl" + ], + "version": "1.0.0", + "visibility": [], + "within_view": [ + "PUBLIC" + ] + } + ]"#; + let result: Vec = serde_json::from_str(string).unwrap(); + expect![[r#" + [ + BuckTargetBare { + name: "app_a_target", + app_name: Some( + "app_a", + ), + buck_package: "cell//linter", + buck_type: App, + labels: Array [ + String("user_application"), + ], + applications: Array [], + deps: Null, + extra_includes: [], + included_applications: [], + includes: [ + "cell//linter/app_a/include/app_a.hrl", + ], + srcs: Array [ + String("cell//linter/app_a/src/app_a.erl"), + String("cell//linter/app_a/src/app_a_edoc.erl"), + String("cell//linter/app_a/src/app_a_unused_param.erl"), + String("cell//linter/app_a/src/expression_updates_literal.erl"), + String("cell//linter/app_a/src/spelling.erl"), + ], + suite: None, + }, + ] + "#]] + .assert_debug_eq(&result); + + let full_target_names = result + .iter() + .map(|b| b.target_full_name()) + .collect::>(); + expect![[r#" + [ + "cell//linter:app_a", + ] + "#]] + .assert_debug_eq(&full_target_names); + + let cells = BuckCellInfo { + cells: FxHashMap::from_iter(vec![ + ("fbcode".to_string(), "/[fbcode]".to_string()), + ("prelude".to_string(), "/[prelude]".to_string()), + ]), + }; + + let converted: Vec = result + .into_iter() + .map(|bare| BuckTargetBare::as_buck_target(bare, &cells)) + .collect(); + expect![[r#" + [ + BuckTarget { + name: "app_a_target", + app_name: Some( + "app_a", + ), + suite: None, + srcs: [ + "cell//linter/app_a/src/app_a.erl", + "cell//linter/app_a/src/app_a_edoc.erl", + "cell//linter/app_a/src/app_a_unused_param.erl", + "cell//linter/app_a/src/expression_updates_literal.erl", + "cell//linter/app_a/src/spelling.erl", + ], + includes: [ + "cell//linter/app_a/include", + ], + gen_srcs: [], + labels: { + "user_application", + }, + deps: [], + apps: [], + included_apps: [], + extra_includes: [], + }, + ] + "#]] + .assert_debug_eq(&converted); + } + + #[test] + fn unusual_buck_target() { + let string = r#" + [ + + { + "buck.type":"prelude//rules.bzl:erlang_release", + "buck.deps":[ + "waserver//buck2/test/targets/apps:app_a", + "waserver//buck2/test/targets/apps:app_e", + "toolchains//:erlang-default" + ], + "buck.inputs":[], + "buck.package":"waserver//buck2/test/targets/releases", + "name":"rel4", + "visibility":["PUBLIC"], + "within_view":["PUBLIC"], + "applications":[ + "waserver//buck2/test/targets/apps:app_a", + ["waserver//buck2/test/targets/apps:app_e","load"] + ] + } + ]"#; + let v: Value = serde_json::from_str(string).unwrap(); + expect![[r#" + Array [ + Object { + "applications": Array [ + String("waserver//buck2/test/targets/apps:app_a"), + Array [ + String("waserver//buck2/test/targets/apps:app_e"), + String("load"), + ], + ], + "buck.deps": Array [ + String("waserver//buck2/test/targets/apps:app_a"), + String("waserver//buck2/test/targets/apps:app_e"), + String("toolchains//:erlang-default"), + ], + "buck.inputs": Array [], + "buck.package": String("waserver//buck2/test/targets/releases"), + "buck.type": String("prelude//rules.bzl:erlang_release"), + "name": String("rel4"), + "visibility": Array [ + String("PUBLIC"), + ], + "within_view": Array [ + String("PUBLIC"), + ], + }, + ] + "#]] + .assert_debug_eq(&v); + } } diff --git a/crates/project_model/src/eqwalizer_support.rs b/crates/project_model/src/eqwalizer_support.rs index 672b7c174d..861e9af812 100644 --- a/crates/project_model/src/eqwalizer_support.rs +++ b/crates/project_model/src/eqwalizer_support.rs @@ -49,6 +49,7 @@ pub(crate) fn eqwalizer_suppport_data(otp_root: &AbsPath) -> ProjectAppData { gen_src_files: None, applicable_files: None, is_test_target: None, + is_buck_generated: None, } } diff --git a/crates/project_model/src/json.rs b/crates/project_model/src/json.rs index 12b822ac39..c98f30e726 100644 --- a/crates/project_model/src/json.rs +++ b/crates/project_model/src/json.rs @@ -105,6 +105,7 @@ impl JsonProjectAppData { gen_src_files: None, applicable_files: None, is_test_target: None, + is_buck_generated: None, }) } @@ -229,7 +230,7 @@ pub(crate) fn gen_app_data( (apps, deps) } -fn canonicalize(path: impl AsRef) -> Result { +pub fn canonicalize(path: impl AsRef) -> Result { let abs = fs::canonicalize(path.as_ref())?; Ok(AbsPathBuf::assert( Utf8PathBuf::from_path_buf(abs).expect("Could not convert to UTF8"), diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index 73a46e7e6e..233c687afc 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs @@ -339,7 +339,13 @@ 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(r) = Self::discover_rebar(path, Some(rebar_profile), IncludeParentDirs::No)? { + 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, + )? + { return Ok(r); } if let Some(s) = Self::discover_static(path, IncludeParentDirs::No)? { @@ -385,6 +391,8 @@ pub struct ElpConfig { pub eqwalizer: EqwalizerConfig, #[serde(default)] pub rebar: ElpRebarConfig, + #[serde(default)] + pub otp: OtpConfig, } #[derive( @@ -501,6 +509,22 @@ impl Default for ElpRebarConfig { } } +#[derive( + Debug, + Default, + Clone, + PartialEq, + Eq, + Hash, + Ord, + PartialOrd, + Deserialize, + Serialize +)] +pub struct OtpConfig { + pub exclude_apps: Vec, +} + impl ElpConfig { pub fn new( config_path: AbsPathBuf, @@ -515,6 +539,7 @@ impl ElpConfig { build_info, eqwalizer, rebar, + otp: OtpConfig::default(), } } pub fn try_parse(path: &AbsPath) -> Result { @@ -877,6 +902,9 @@ pub struct ProjectAppData { // data applies to. pub applicable_files: Option>, pub is_test_target: Option, + /// Generated as part of the buck build process, via elp.bxl + /// Specifically not related to any marker tags in files + pub is_buck_generated: Option, } impl ProjectAppData { @@ -902,6 +930,7 @@ impl ProjectAppData { gen_src_files: None, applicable_files: None, is_test_target: None, + is_buck_generated: None, } } @@ -929,6 +958,7 @@ impl ProjectAppData { gen_src_files: None, applicable_files: None, is_test_target: None, + is_buck_generated: None, } } @@ -998,7 +1028,7 @@ impl Project { pub fn load( manifest: &ProjectManifest, - eqwalizer_config: EqwalizerConfig, + elp_config: &ElpConfig, query_config: &BuckQueryConfig, report_progress: &impl Fn(&str), ) -> Result { @@ -1032,7 +1062,7 @@ impl Project { ProjectManifest::TomlBuck(buck) => { // We only select this manifest if buck is actually enabled let (project, apps, otp_root, include_mapping) = - BuckProject::load_from_config(buck, query_config, report_progress)?; + BuckProject::load_from_config(buck, elp_config, query_config, report_progress)?; ( ProjectBuildData::Buck(project), apps, @@ -1061,14 +1091,14 @@ impl Project { } }; - let (otp, otp_project_apps) = Otp::discover(otp_root); + let (otp, otp_project_apps) = Otp::discover(otp_root, &elp_config.otp); project_apps.extend(otp_project_apps); report_progress("Project info loaded"); Ok(Project { otp, project_build_data: project_build_info, project_apps, - eqwalizer_config, + eqwalizer_config: elp_config.eqwalizer.clone(), include_mapping, }) } @@ -1172,6 +1202,9 @@ mod tests { rebar: ElpRebarConfig { profile: "test", }, + otp: OtpConfig { + exclude_apps: [], + }, }, Rebar( RebarConfig { @@ -1237,6 +1270,9 @@ mod tests { rebar: ElpRebarConfig { profile: "test", }, + otp: OtpConfig { + exclude_apps: [], + }, }, Json( JsonConfig { @@ -1347,6 +1383,9 @@ mod tests { rebar: ElpRebarConfig { profile: "test", }, + otp: OtpConfig { + exclude_apps: [], + }, }, JsonConfig { apps: [ @@ -1502,6 +1541,9 @@ mod tests { rebar: ElpRebarConfig { profile: "test", }, + otp: OtpConfig { + exclude_apps: [], + }, }, NoManifest( NoManifestConfig { @@ -1535,6 +1577,60 @@ 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 @@ -1571,6 +1667,9 @@ mod tests { rebar: ElpRebarConfig { profile: "test", }, + otp: OtpConfig { + exclude_apps: [], + }, }, NoManifest( NoManifestConfig { @@ -1764,6 +1863,9 @@ mod tests { rebar: ElpRebarConfig { profile: "other", }, + otp: OtpConfig { + exclude_apps: [], + }, } "#]] .assert_eq(&debug_normalise_temp_dir(dir, &elp_config)); @@ -1797,6 +1899,7 @@ 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, @@ -1807,6 +1910,7 @@ mod tests { rebar: ElpRebarConfig { profile: "my_profile".to_string(), }, + otp: OtpConfig::default(), }) .unwrap(); expect![[r#" @@ -1821,6 +1925,7 @@ 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 @@ -1829,6 +1934,9 @@ mod tests { [rebar] profile = "my_profile" + + [otp] + exclude_apps = [] "#]] .assert_eq(&result); } @@ -1891,6 +1999,9 @@ mod tests { source_root: Some( "path/to/root", ), + test_application_labels: [ + "test_application", + ], }, ), eqwalizer: EqwalizerConfig { @@ -1902,6 +2013,9 @@ mod tests { rebar: ElpRebarConfig { profile: "my_profile", }, + otp: OtpConfig { + exclude_apps: [], + }, } "#]] .assert_debug_eq(&lints); @@ -2017,4 +2131,112 @@ mod tests { } } } + + #[test] + fn test_toml_otp_exclude_apps() { + let spec = r#" + //- /.elp.toml + [otp] + exclude_apps = ["megaco", "eunit"] + //- /app_a/src/app.erl + -module(app). + "#; + let dir = FixtureWithProjectMeta::gen_project(spec); + if let Ok((elp_config, ProjectManifest::NoManifest(_))) = ProjectManifest::discover( + &to_abs_path_buf(&dir.path().join("app_a/src/app.erl")).unwrap(), + ) { + expect![[r#" + ElpConfig { + config_path: Some( + AbsPathBuf( + "TMPDIR/.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: [ + "megaco", + "eunit", + ], + }, + } + "#]] + .assert_eq(&debug_normalise_temp_dir(dir, &elp_config)); + } else { + panic!() + } + } + + #[test] + fn serde_serialize_elp_toml_with_otp() { + let result = toml::to_string::(&ElpConfig { + config_path: None, + build_info: None, + buck: None, + eqwalizer: EqwalizerConfig::default(), + rebar: ElpRebarConfig::default(), + otp: OtpConfig { + exclude_apps: vec!["megaco".to_string(), "eunit".to_string()], + }, + }) + .unwrap(); + expect![[r#" + [eqwalizer] + enable_all = true + max_tasks = 4 + ignore_modules = [] + + [rebar] + profile = "test" + + [otp] + exclude_apps = ["megaco", "eunit"] + "#]] + .assert_eq(&result); + } + + #[test] + fn serde_deserialize_elp_toml_with_otp() { + let config: ElpConfig = toml::from_str( + r#" + [otp] + exclude_apps = ["megaco", "eunit"] + "#, + ) + .unwrap(); + + expect![[r#" + ElpConfig { + config_path: None, + 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: [ + "megaco", + "eunit", + ], + }, + } + "#]] + .assert_debug_eq(&config); + } } diff --git a/crates/project_model/src/no_manifest.rs b/crates/project_model/src/no_manifest.rs index a1de933260..6a7e021342 100644 --- a/crates/project_model/src/no_manifest.rs +++ b/crates/project_model/src/no_manifest.rs @@ -71,6 +71,7 @@ impl NoManifestConfig { gen_src_files: None, applicable_files: None, is_test_target: None, + is_buck_generated: None, }; data.include_path.extend(data.include_dirs()); if let Some(path) = self.root_path.parent() { diff --git a/crates/project_model/src/otp.rs b/crates/project_model/src/otp.rs index 3d561177d8..d2cb3be6a2 100644 --- a/crates/project_model/src/otp.rs +++ b/crates/project_model/src/otp.rs @@ -22,6 +22,7 @@ use paths::Utf8Path; use paths::Utf8PathBuf; use crate::AppName; +use crate::OtpConfig; use crate::ProjectAppData; #[derive(Debug, Clone, PartialEq, Eq)] @@ -70,7 +71,7 @@ pub fn supports_eep66_sigils() -> bool { } fn get_erts_dir() -> AbsPathBuf { - let (_otp, apps) = Otp::discover(OTP_ROOT.to_path_buf()); + let (_otp, apps) = Otp::discover(OTP_ROOT.to_path_buf(), &OtpConfig::default()); for app in apps { if app.name == AppName("erts".to_string()) { return app.dir; @@ -157,8 +158,8 @@ impl Otp { Ok(val) } - pub fn discover(path: Utf8PathBuf) -> (Otp, Vec) { - let apps = Self::discover_otp_apps(&path); + pub fn discover(path: Utf8PathBuf, otp_config: &OtpConfig) -> (Otp, Vec) { + let apps = Self::discover_otp_apps(&path, otp_config); ( Otp { lib_dir: AbsPathBuf::assert(path), @@ -167,7 +168,8 @@ impl Otp { ) } - fn discover_otp_apps(path: &Utf8Path) -> Vec { + fn discover_otp_apps(path: &Utf8Path, otp_config: &OtpConfig) -> Vec { + let exclude_apps = &otp_config.exclude_apps; log::info!("Loading OTP apps from {path:?}"); if let Ok(entries) = fs::read_dir(path) { entries @@ -175,11 +177,24 @@ impl Otp { .filter_map(|entry| { let entry = entry.ok()?; let name = entry.file_name(); + let name_str = name.to_str()?; + + // Extract app name from versioned directory name (e.g., "megaco-4.5" -> "megaco") + let app_name = name_str + .split_once('-') + .map_or(name_str, |(base, _version)| base); + + // Skip excluded applications + if exclude_apps.contains(&app_name.to_string()) { + log::info!("Excluding OTP app: {}", app_name); + return None; + } + let path = fs::canonicalize(entry.path()).expect("Could not canonicalize path"); let dir = AbsPathBuf::assert( Utf8PathBuf::from_path_buf(path).expect("Could not convert to Utf8PathBuf"), ); - Some(ProjectAppData::otp_app_data(name.to_str()?, &dir)) + Some(ProjectAppData::otp_app_data(name_str, &dir)) }) .collect() } else { @@ -187,3 +202,59 @@ impl Otp { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_discover_with_excluded_apps() { + // Create a mock OTP directory structure + let temp_dir = tempfile::tempdir().unwrap(); + let otp_lib_dir = temp_dir.path().join("lib"); + std::fs::create_dir_all(&otp_lib_dir).unwrap(); + + // Create mock OTP app directories + let apps = vec![ + "kernel-9.2", + "stdlib-5.2", + "megaco-4.5", + "eunit-2.8.2", + "common_test-1.25.1", + ]; + + for app in &apps { + let app_dir = otp_lib_dir.join(app); + std::fs::create_dir_all(app_dir.join("src")).unwrap(); + std::fs::create_dir_all(app_dir.join("include")).unwrap(); + std::fs::create_dir_all(app_dir.join("ebin")).unwrap(); + } + + let otp_path = Utf8PathBuf::from_path_buf(otp_lib_dir).unwrap(); + + // Test without exclusions + let (_otp, all_apps) = Otp::discover(otp_path.clone(), &OtpConfig::default()); + let app_names: Vec<&str> = all_apps.iter().map(|app| app.name.as_str()).collect(); + assert!(app_names.contains(&"kernel")); + assert!(app_names.contains(&"stdlib")); + assert!(app_names.contains(&"megaco")); + assert!(app_names.contains(&"eunit")); + assert!(app_names.contains(&"common_test")); + + // Test with exclusions + let otp_config = OtpConfig { + exclude_apps: vec!["megaco".to_string(), "eunit".to_string()], + }; + let (_otp, filtered_apps) = Otp::discover(otp_path, &otp_config); + let filtered_names: Vec<&str> = filtered_apps.iter().map(|app| app.name.as_str()).collect(); + assert!(filtered_names.contains(&"kernel")); + assert!(filtered_names.contains(&"stdlib")); + assert!(filtered_names.contains(&"common_test")); + assert!(!filtered_names.contains(&"megaco")); + assert!(!filtered_names.contains(&"eunit")); + + // Verify the filtered list is smaller + assert!(filtered_apps.len() < all_apps.len()); + assert_eq!(filtered_apps.len(), all_apps.len() - 2); + } +} diff --git a/crates/project_model/src/rebar.rs b/crates/project_model/src/rebar.rs index 64686c26a6..bd675ffc2e 100644 --- a/crates/project_model/src/rebar.rs +++ b/crates/project_model/src/rebar.rs @@ -240,6 +240,7 @@ impl RebarProject { gen_src_files: None, applicable_files: None, is_test_target: None, + is_buck_generated: None, }) } } diff --git a/crates/project_model/src/test_fixture.rs b/crates/project_model/src/test_fixture.rs index 152595251b..140baec0ee 100644 --- a/crates/project_model/src/test_fixture.rs +++ b/crates/project_model/src/test_fixture.rs @@ -187,6 +187,7 @@ impl DiagnosticsEnabled { pub struct FixtureWithProjectMeta { pub fixture: Vec, pub diagnostics_enabled: DiagnosticsEnabled, + pub expect_parse_errors: bool, } impl FixtureWithProjectMeta { @@ -204,6 +205,7 @@ 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 @@ -232,6 +234,12 @@ 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; @@ -277,6 +285,12 @@ 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:?}" + ); } } } @@ -298,6 +312,7 @@ impl FixtureWithProjectMeta { FixtureWithProjectMeta { fixture: res, diagnostics_enabled, + expect_parse_errors, } } @@ -451,21 +466,34 @@ 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 @@ -546,10 +574,16 @@ 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)); - let &(_, idx) = prev_line_annotations + // Try to find a previous annotation at the same offset + let idx = if let Some(&(_, idx)) = prev_line_annotations .iter() .find(|&&(off, _idx)| off == offset) - .unwrap(); + { + idx + } else { + // If no exact offset match, append to the most recent annotation + res.len() - 1 + }; res[idx].1.push('\n'); res[idx].1.push_str(&content); } @@ -819,6 +853,19 @@ 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() { @@ -966,6 +1013,7 @@ bar() -> ok. gen_src_files: None, applicable_files: None, is_test_target: None, + is_buck_generated: None, }"#]] .assert_eq(format!("{:#?}", meta0.app_data).as_str()); } diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 081efa08d4..1f8d1aaa63 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -7,9 +7,6 @@ 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 af72d7de98..08b7ed9a1f 100644 --- a/crates/syntax/src/algo.rs +++ b/crates/syntax/src/algo.rs @@ -10,12 +10,8 @@ //! 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; @@ -178,157 +174,6 @@ 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. /// @@ -452,337 +297,3 @@ 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 716d46d25a..781d35aaaf 100644 --- a/crates/syntax/src/syntax_kind/generated.rs +++ b/crates/syntax/src/syntax_kind/generated.rs @@ -1,7 +1,8 @@ //! @generated file, do not edit by hand, see `xtask/src/codegen.rs` #![allow(bad_style, missing_docs, unreachable_pub)] -use num_derive::{FromPrimitive, ToPrimitive}; +use num_derive::FromPrimitive; +use num_derive::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 deleted file mode 100644 index 59d333adc7..0000000000 --- a/crates/text_edit/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[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/editors/code/README.md b/editors/code/README.md index b03ce757f2..ff5663d5ca 100644 --- a/editors/code/README.md +++ b/editors/code/README.md @@ -1,19 +1,82 @@ # Erlang Language Platform -Provide support for the [Erlang](https://www.erlang.org/) Programming Language. +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. ## Features -* Syntax Highlighting -* Go To Definition -* Find References -* Auto-completion -* Call Hierarchy -* Signature Help -* Diagnostics -* Inlay Hints -* ... +### 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 ## Documentation -See https://whatsapp.github.io/erlang-language-platform/ for more information. +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 +

diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 6e00a55203..6309d4c81e 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -1,12 +1,12 @@ { "name": "erlang-language-platform", - "version": "0.42.0", + "version": "0.47.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "erlang-language-platform", - "version": "0.42.0", + "version": "0.47.0", "hasInstallScript": true, "license": "Apache2", "devDependencies": { @@ -1448,10 +1448,11 @@ "dev": true }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -1624,9 +1625,9 @@ } }, "node_modules/mocha/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", "dependencies": { @@ -3399,9 +3400,9 @@ "dev": true }, "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "requires": { "argparse": "^2.0.1" @@ -3532,9 +3533,9 @@ } }, "glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "requires": { "foreground-child": "^3.1.0", diff --git a/editors/code/package.json b/editors/code/package.json index 0695e9e215..eb7ced3148 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1,9 +1,10 @@ { "name": "erlang-language-platform", - "description": "Erlang language server", + "displayName": "Erlang Language Platform", + "description": "Erlang Language Support for VS Code, by WhatsApp.", "author": "Meta Platforms, Inc", "license": "Apache2", - "version": "0.42.0", + "version": "0.47.0", "icon": "images/elp-logo-color.png", "homepage": "https://whatsapp.github.io/erlang-language-platform/", "repository": { @@ -20,7 +21,8 @@ "Testing" ], "keywords": [ - "elp" + "elp", + "erlang" ], "engines": { "vscode": "^1.75.0" diff --git a/elisp/dotemacs.el b/editors/emacs/dotemacs.el similarity index 100% rename from elisp/dotemacs.el rename to editors/emacs/dotemacs.el diff --git a/eqwalizer b/eqwalizer new file mode 160000 index 0000000000..0f514eb389 --- /dev/null +++ b/eqwalizer @@ -0,0 +1 @@ +Subproject commit 0f514eb3893fa7070835c83ecb49fbea31b0426d diff --git a/erlang_service/src/elp_lint.erl b/erlang_service/src/elp_lint.erl index 609e8c0712..31d2c70248 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 -% @fb-only +% @fb-only: is_format_function(wa_log, send_if) -> true; +% @fb-only: is_format_function(wa_string, format) -> true; is_format_function(M, F) when is_atom(M), is_atom(F) -> false. %% check_format_1([Arg]) -> ok | {warn,Level,Format,[Arg]}. -% @fb-only -% @fb-only +% @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]; 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 77223da49a..bc5a2faf3b 100644 --- a/erlang_service/src/erlang_service_lint.erl +++ b/erlang_service/src/erlang_service_lint.erl @@ -178,6 +178,7 @@ 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)]) @@ -189,6 +190,7 @@ 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. @@ -199,18 +201,19 @@ format_error(_Forms, SamePath, SamePath, {Location, Mod, Reason}) -> erlang_service_error_codes:make_code(Mod, Reason) } ]; -format_error(Forms, OriginalPath, Path, {Location, Mod, Reason}) -> +format_error(Forms, IncluderPath, ErrorPath, {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, Path), + IncludeLocation = inclusion_range(Forms, ErrorPath), %% 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(OriginalPath), + unicode:characters_to_list(IncluderPath), + unicode:characters_to_list(ErrorPath), % Location would be {Line, Col} for a erlc compiler error/warning, % but {ByteStart, ByteEnd} for an eqwalizer diagnostic. % This is deciphered on elp side. @@ -219,7 +222,8 @@ format_error(Forms, OriginalPath, Path, {Location, Mod, Reason}) -> erlang_service_error_codes:make_code(erlang_service_error_codes, "Issue in included file") }, { - unicode:characters_to_list(Path), + unicode:characters_to_list(IncluderPath), + unicode:characters_to_list(ErrorPath), % Location would be {Line, Col} for a erlc compiler error/warning, % but {ByteStart, ByteEnd} for an eqwalizer diagnostic. % This is deciphered on elp side. @@ -232,13 +236,96 @@ format_error(Forms, OriginalPath, Path, {Location, Mod, Reason}) -> ]. inclusion_range(Forms, Path) -> - case [Location || {attribute, Location, file, {FormPath, _}} <- Forms, FormPath == Path] of - [{Loc, _}] -> - {Loc, Loc}; + %% 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; _ -> {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/rustfmt.toml b/rustfmt.toml index 8f75064140..06998754bd 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,9 @@ -edition = "2018" +# Get help on options with `rustfmt --help=config` +# Please keep these in alphabetical order. +edition = "2024" +format_code_in_doc_comments = true +group_imports = "StdExternalCrate" +imports_granularity = "Item" merge_derives = false +style_edition = "2024" use_field_init_shorthand = true diff --git a/test/test_projects/.buckconfig b/test/test_projects/.buckconfig new file mode 100644 index 0000000000..f14e564a7d --- /dev/null +++ b/test/test_projects/.buckconfig @@ -0,0 +1,24 @@ +[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_projects/eqwalizer_tests/fault_tolerance/.eqwalizer b/test/test_projects/.buckroot similarity index 100% rename from test_projects/eqwalizer_tests/fault_tolerance/.eqwalizer rename to test/test_projects/.buckroot diff --git a/test_projects/.gitignore b/test/test_projects/.gitignore similarity index 85% rename from test_projects/.gitignore rename to test/test_projects/.gitignore index b34578734c..2672c17cc4 100644 --- a/test_projects/.gitignore +++ b/test/test_projects/.gitignore @@ -3,3 +3,4 @@ *wa.build_info *_build/ *rebar.lock +buck-out/ diff --git a/test_projects/README.md b/test/test_projects/README.md similarity index 100% rename from test_projects/README.md rename to test/test_projects/README.md diff --git a/test/test_projects/buck_bad_config/.elp.toml b/test/test_projects/buck_bad_config/.elp.toml new file mode 100644 index 0000000000..963072284c --- /dev/null +++ b/test/test_projects/buck_bad_config/.elp.toml @@ -0,0 +1,8 @@ +[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 new file mode 100644 index 0000000000..498c769dac --- /dev/null +++ b/test/test_projects/buck_bad_config/BUCK @@ -0,0 +1,14 @@ +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_projects/buck_bad_config/src/bad_app.erl b/test/test_projects/buck_bad_config/src/bad_app.erl similarity index 100% rename from test_projects/buck_bad_config/src/bad_app.erl rename to test/test_projects/buck_bad_config/src/bad_app.erl diff --git a/test/test_projects/buck_tests/.elp.toml b/test/test_projects/buck_tests/.elp.toml new file mode 100644 index 0000000000..b38d6f043f --- /dev/null +++ b/test/test_projects/buck_tests/.elp.toml @@ -0,0 +1,9 @@ +[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_projects/buck_tests/TARGETS.v2_ b/test/test_projects/buck_tests/TARGETS.v2_ similarity index 100% rename from test_projects/buck_tests/TARGETS.v2_ rename to test/test_projects/buck_tests/TARGETS.v2_ diff --git a/test_projects/buck_tests/test_elp/TARGETS.v2_ b/test/test_projects/buck_tests/test_elp/TARGETS.v2_ similarity index 77% rename from test_projects/buck_tests/test_elp/TARGETS.v2_ rename to test/test_projects/buck_tests/test_elp/TARGETS.v2_ index 83089813da..7e5bd95db5 100644 --- a/test_projects/buck_tests/test_elp/TARGETS.v2_ +++ b/test/test_projects/buck_tests/test_elp/TARGETS.v2_ @@ -7,11 +7,11 @@ erlang_application( ]), app_src = "src/test_elp.app.src", applications = [ - "//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", + "//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", ], includes = glob(["include/*.hrl"]), version = "1.0.0", diff --git a/test_projects/buck_tests/test_elp/include/test_elp.hrl b/test/test_projects/buck_tests/test_elp/include/test_elp.hrl similarity index 100% rename from test_projects/buck_tests/test_elp/include/test_elp.hrl rename to test/test_projects/buck_tests/test_elp/include/test_elp.hrl diff --git a/test_projects/buck_tests/test_elp/src/test_elp.app.src b/test/test_projects/buck_tests/test_elp/src/test_elp.app.src similarity index 100% rename from test_projects/buck_tests/test_elp/src/test_elp.app.src rename to test/test_projects/buck_tests/test_elp/src/test_elp.app.src diff --git a/test_projects/buck_tests/test_elp/src/test_elp.erl b/test/test_projects/buck_tests/test_elp/src/test_elp.erl similarity index 100% rename from test_projects/buck_tests/test_elp/src/test_elp.erl rename to test/test_projects/buck_tests/test_elp/src/test_elp.erl diff --git a/test_projects/buck_tests/test_elp/test/test_elp_SUITE.erl b/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE.erl similarity index 100% rename from test_projects/buck_tests/test_elp/test/test_elp_SUITE.erl rename to test/test_projects/buck_tests/test_elp/test/test_elp_SUITE.erl diff --git a/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test1.json b/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test1.json similarity index 100% rename from test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test1.json rename to test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test1.json diff --git a/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test2.json b/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test2.json similarity index 100% rename from test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test2.json rename to test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test2.json diff --git a/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_header.hrl b/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_header.hrl similarity index 100% rename from test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_header.hrl rename to test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_header.hrl diff --git a/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_module.erl b/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_module.erl similarity index 100% rename from test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_module.erl rename to test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_module.erl diff --git a/test_projects/buck_tests/test_elp/test/test_elp_test_utils.erl b/test/test_projects/buck_tests/test_elp/test/test_elp_test_utils.erl similarity index 100% rename from test_projects/buck_tests/test_elp/test/test_elp_test_utils.erl rename to test/test_projects/buck_tests/test_elp/test/test_elp_test_utils.erl diff --git a/test_projects/buck_tests/test_elp/test/test_elp_test_utils.hrl b/test/test_projects/buck_tests/test_elp/test/test_elp_test_utils.hrl similarity index 100% rename from test_projects/buck_tests/test_elp/test/test_elp_test_utils.hrl rename to test/test_projects/buck_tests/test_elp/test/test_elp_test_utils.hrl diff --git a/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ b/test/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ similarity index 62% rename from test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ rename to test/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ index d0fea8149b..a752b99087 100644 --- a/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ +++ b/test/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ @@ -5,10 +5,10 @@ erlang_application( "src/*.hrl", ]), applications = [ - "//whatsapp/elp/test_projects/buck_tests/test_elp_transitive_dep:test_elp_transitive_dep", + "//buck_tests/test_elp_transitive_dep:test_elp_transitive_dep", ], extra_includes = [ - "//whatsapp/elp/test_projects/buck_tests/test_elp:test_elp", + "//buck_tests/test_elp:test_elp", ], includes = glob(["include/*.hrl"]), version = "1.0.0", diff --git a/test_projects/buck_tests/test_elp_direct_dep/include/test_elp_direct_dep.hrl b/test/test_projects/buck_tests/test_elp_direct_dep/include/test_elp_direct_dep.hrl similarity index 100% rename from test_projects/buck_tests/test_elp_direct_dep/include/test_elp_direct_dep.hrl rename to test/test_projects/buck_tests/test_elp_direct_dep/include/test_elp_direct_dep.hrl diff --git a/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep.erl b/test/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep.erl similarity index 100% rename from test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep.erl rename to test/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep.erl diff --git a/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep_private.hrl b/test/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep_private.hrl similarity index 100% rename from test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep_private.hrl rename to test/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep_private.hrl diff --git a/test_projects/buck_tests/test_elp_flat_inside_target/TARGETS.v2_ b/test/test_projects/buck_tests/test_elp_flat_inside_target/TARGETS.v2_ similarity index 100% rename from test_projects/buck_tests/test_elp_flat_inside_target/TARGETS.v2_ rename to test/test_projects/buck_tests/test_elp_flat_inside_target/TARGETS.v2_ diff --git a/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.erl b/test/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.erl similarity index 100% rename from test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.erl rename to test/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.erl diff --git a/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.hrl b/test/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.hrl similarity index 100% rename from test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.hrl rename to test/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.hrl diff --git a/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.erl b/test/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.erl similarity index 100% rename from test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.erl rename to test/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.erl diff --git a/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.hrl b/test/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.hrl similarity index 100% rename from test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.hrl rename to test/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.hrl diff --git a/test_projects/buck_tests/test_elp_ignored/test_elp_ignored.erl b/test/test_projects/buck_tests/test_elp_ignored/test_elp_ignored.erl similarity index 100% rename from test_projects/buck_tests/test_elp_ignored/test_elp_ignored.erl rename to test/test_projects/buck_tests/test_elp_ignored/test_elp_ignored.erl diff --git a/test_projects/buck_tests/test_elp_no_private_headers/include/test_elp_no_private_headers.hrl b/test/test_projects/buck_tests/test_elp_no_private_headers/include/test_elp_no_private_headers.hrl similarity index 100% rename from test_projects/buck_tests/test_elp_no_private_headers/include/test_elp_no_private_headers.hrl rename to test/test_projects/buck_tests/test_elp_no_private_headers/include/test_elp_no_private_headers.hrl diff --git a/test_projects/buck_tests/test_elp_no_private_headers/src/test_elp_no_private_headers.erl b/test/test_projects/buck_tests/test_elp_no_private_headers/src/test_elp_no_private_headers.erl similarity index 100% rename from test_projects/buck_tests/test_elp_no_private_headers/src/test_elp_no_private_headers.erl rename to test/test_projects/buck_tests/test_elp_no_private_headers/src/test_elp_no_private_headers.erl diff --git a/test_projects/buck_tests/test_elp_no_public_headers/src/test_elp_no_headers.erl b/test/test_projects/buck_tests/test_elp_no_public_headers/src/test_elp_no_headers.erl similarity index 100% rename from test_projects/buck_tests/test_elp_no_public_headers/src/test_elp_no_headers.erl rename to test/test_projects/buck_tests/test_elp_no_public_headers/src/test_elp_no_headers.erl diff --git a/test_projects/buck_tests/test_elp_transitive_dep/TARGETS.v2_ b/test/test_projects/buck_tests/test_elp_transitive_dep/TARGETS.v2_ similarity index 100% rename from test_projects/buck_tests/test_elp_transitive_dep/TARGETS.v2_ rename to test/test_projects/buck_tests/test_elp_transitive_dep/TARGETS.v2_ diff --git a/test_projects/buck_tests/test_elp_transitive_dep/include/test_elp_transitive_dep.hrl b/test/test_projects/buck_tests/test_elp_transitive_dep/include/test_elp_transitive_dep.hrl similarity index 100% rename from test_projects/buck_tests/test_elp_transitive_dep/include/test_elp_transitive_dep.hrl rename to test/test_projects/buck_tests/test_elp_transitive_dep/include/test_elp_transitive_dep.hrl diff --git a/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep.erl b/test/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep.erl similarity index 100% rename from test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep.erl rename to test/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep.erl diff --git a/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep_private.hrl b/test/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep_private.hrl similarity index 100% rename from test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep_private.hrl rename to test/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep_private.hrl diff --git a/test/test_projects/buck_tests_2/.elp.toml b/test/test_projects/buck_tests_2/.elp.toml new file mode 100644 index 0000000000..e71eb6a819 --- /dev/null +++ b/test/test_projects/buck_tests_2/.elp.toml @@ -0,0 +1,12 @@ +[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 new file mode 100644 index 0000000000..b01fdb868c --- /dev/null +++ b/test/test_projects/buck_tests_2/BUCK @@ -0,0 +1,41 @@ +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 new file mode 100644 index 0000000000..f021317020 --- /dev/null +++ b/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/BUCK @@ -0,0 +1,25 @@ +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_projects/buck_tests_2/auto_gen/auto_gen_a/include/auto_gen_a.hrl b/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/include/auto_gen_a.hrl similarity index 100% rename from test_projects/buck_tests_2/auto_gen/auto_gen_a/include/auto_gen_a.hrl rename to test/test_projects/buck_tests_2/auto_gen/auto_gen_a/include/auto_gen_a.hrl diff --git a/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl b/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl similarity index 100% rename from test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl rename to test/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl diff --git a/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl b/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl similarity index 100% rename from test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl rename to test/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.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 new file mode 100644 index 0000000000..6f12fdb31d --- /dev/null +++ b/test/test_projects/buck_tests_2/check_include/src/top_includer.erl @@ -0,0 +1,15 @@ +-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 new file mode 100644 index 0000000000..82ab343676 --- /dev/null +++ b/test/test_projects/buck_tests_2/check_include_separate_1/include/include_with_bug.hrl @@ -0,0 +1,5 @@ +%% 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 new file mode 100644 index 0000000000..b67b5b8b2b --- /dev/null +++ b/test/test_projects/buck_tests_2/check_include_separate_1/include/top_includer.hrl @@ -0,0 +1,6 @@ + +-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 new file mode 100644 index 0000000000..1e0c48bf56 --- /dev/null +++ b/test/test_projects/buck_tests_2/check_include_separate_2/include/separate_include.hrl @@ -0,0 +1,2 @@ + +-define(SECOND, ok). diff --git a/test/test_projects/buck_tests_2/generated/BUCK b/test/test_projects/buck_tests_2/generated/BUCK new file mode 100644 index 0000000000..8eec40830b --- /dev/null +++ b/test/test_projects/buck_tests_2/generated/BUCK @@ -0,0 +1,12 @@ +oncall("vscode_erlang") + +erlang_application( + name = "generated_headers", + includes = [ + "out/generated_header.hrl", + ], + labels = ["generated"], + visibility = [ + "PUBLIC", + ], +) diff --git a/test_projects/buck_tests_2/generated/out/generated_header.hrl b/test/test_projects/buck_tests_2/generated/out/generated_header.hrl similarity index 100% rename from test_projects/buck_tests_2/generated/out/generated_header.hrl rename to test/test_projects/buck_tests_2/generated/out/generated_header.hrl diff --git a/test/test_projects/buck_tests_2/util/app_a/BUCK b/test/test_projects/buck_tests_2/util/app_a/BUCK new file mode 100644 index 0000000000..4231c1c6e8 --- /dev/null +++ b/test/test_projects/buck_tests_2/util/app_a/BUCK @@ -0,0 +1,16 @@ +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_projects/buck_tests_2/util/app_a/include/junk.hrl b/test/test_projects/buck_tests_2/util/app_a/include/junk.hrl similarity index 100% rename from test_projects/buck_tests_2/util/app_a/include/junk.hrl rename to test/test_projects/buck_tests_2/util/app_a/include/junk.hrl diff --git a/test_projects/buck_tests_2/util/app_a/src/app_a.erl b/test/test_projects/buck_tests_2/util/app_a/src/app_a.erl similarity index 100% rename from test_projects/buck_tests_2/util/app_a/src/app_a.erl rename to test/test_projects/buck_tests_2/util/app_a/src/app_a.erl diff --git a/test_projects/end_to_end/.elp.toml b/test/test_projects/codegen_test/.elp.toml similarity index 50% rename from test_projects/end_to_end/.elp.toml rename to test/test_projects/codegen_test/.elp.toml index f015956e45..f21fe1bc73 100644 --- a/test_projects/end_to_end/.elp.toml +++ b/test/test_projects/codegen_test/.elp.toml @@ -1,7 +1,7 @@ [buck] enabled = true build_deps = false -included_targets = ["fbcode//whatsapp/elp/test_projects/end_to_end/..."] +included_targets = ["root//codegen_test/..."] [eqwalizer] enable_all = false diff --git a/test/test_projects/codegen_test/BUCK b/test/test_projects/codegen_test/BUCK new file mode 100644 index 0000000000..1df5f86eba --- /dev/null +++ b/test/test_projects/codegen_test/BUCK @@ -0,0 +1,73 @@ +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 new file mode 100644 index 0000000000..1f73475d9d --- /dev/null +++ b/test/test_projects/codegen_test/README.md @@ -0,0 +1,138 @@ +# 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 new file mode 100644 index 0000000000..7a38d49a24 --- /dev/null +++ b/test/test_projects/codegen_test/app_a/src/codegen_test.app.src @@ -0,0 +1,14 @@ +{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 new file mode 100644 index 0000000000..a624c2089b --- /dev/null +++ b/test/test_projects/codegen_test/app_a/src/example_usage.erl @@ -0,0 +1,51 @@ +-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 new file mode 100644 index 0000000000..3c0135dcee --- /dev/null +++ b/test/test_projects/codegen_test/app_a/test/codegen_test_SUITE.erl @@ -0,0 +1,73 @@ +%%% 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 new file mode 100644 index 0000000000..6b38c39425 --- /dev/null +++ b/test/test_projects/codegen_test/generated/example_service_client.erl @@ -0,0 +1,37 @@ +%%%------------------------------------------------------------------- +%%% @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 new file mode 100644 index 0000000000..3f89adcba9 --- /dev/null +++ b/test/test_projects/codegen_test/generated/example_service_types.erl @@ -0,0 +1,55 @@ +%%%------------------------------------------------------------------- +%%% @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 new file mode 100644 index 0000000000..4c957a0906 --- /dev/null +++ b/test/test_projects/codegen_test/generated/example_service_types.hrl @@ -0,0 +1,27 @@ +%%%------------------------------------------------------------------- +%%% @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 new file mode 100644 index 0000000000..ab30a89f74 --- /dev/null +++ b/test/test_projects/codegen_test/templates/example_service_client.erl @@ -0,0 +1,38 @@ +%%%------------------------------------------------------------------- +%%% @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 new file mode 100644 index 0000000000..833df167c6 --- /dev/null +++ b/test/test_projects/codegen_test/templates/example_service_types.erl @@ -0,0 +1,56 @@ +%%%------------------------------------------------------------------- +%%% @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 new file mode 100644 index 0000000000..88a2e7aed2 --- /dev/null +++ b/test/test_projects/codegen_test/templates/example_service_types.hrl @@ -0,0 +1,28 @@ +%%%------------------------------------------------------------------- +%%% @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_projects/custom_build_tool/.elp.toml b/test/test_projects/custom_build_tool/.elp.toml similarity index 100% rename from test_projects/custom_build_tool/.elp.toml rename to test/test_projects/custom_build_tool/.elp.toml diff --git a/test_projects/custom_build_tool/apps/app_a/include/app_a.hrl b/test/test_projects/custom_build_tool/apps/app_a/include/app_a.hrl similarity index 100% rename from test_projects/custom_build_tool/apps/app_a/include/app_a.hrl rename to test/test_projects/custom_build_tool/apps/app_a/include/app_a.hrl diff --git a/test_projects/custom_build_tool/apps/app_a/src/app_a.erl b/test/test_projects/custom_build_tool/apps/app_a/src/app_a.erl similarity index 100% rename from test_projects/custom_build_tool/apps/app_a/src/app_a.erl rename to test/test_projects/custom_build_tool/apps/app_a/src/app_a.erl diff --git a/test_projects/custom_build_tool/apps/app_b/src/app_b.erl b/test/test_projects/custom_build_tool/apps/app_b/src/app_b.erl similarity index 100% rename from test_projects/custom_build_tool/apps/app_b/src/app_b.erl rename to test/test_projects/custom_build_tool/apps/app_b/src/app_b.erl diff --git a/test/test_projects/diagnostics/.elp.toml b/test/test_projects/diagnostics/.elp.toml new file mode 100644 index 0000000000..504ef547af --- /dev/null +++ b/test/test_projects/diagnostics/.elp.toml @@ -0,0 +1,8 @@ +[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 new file mode 100644 index 0000000000..19c15e5acf --- /dev/null +++ b/test/test_projects/diagnostics/BUCK @@ -0,0 +1,20 @@ +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_projects/diagnostics/README.md b/test/test_projects/diagnostics/README.md similarity index 100% rename from test_projects/diagnostics/README.md rename to test/test_projects/diagnostics/README.md diff --git a/test_projects/diagnostics/app_a/extra/app_a.erl b/test/test_projects/diagnostics/app_a/extra/app_a.erl similarity index 100% rename from test_projects/diagnostics/app_a/extra/app_a.erl rename to test/test_projects/diagnostics/app_a/extra/app_a.erl diff --git a/test_projects/diagnostics/app_a/include/app_a.hrl b/test/test_projects/diagnostics/app_a/include/app_a.hrl similarity index 100% rename from test_projects/diagnostics/app_a/include/app_a.hrl rename to test/test_projects/diagnostics/app_a/include/app_a.hrl diff --git a/test_projects/diagnostics/app_a/include/broken_diagnostics.hrl b/test/test_projects/diagnostics/app_a/include/broken_diagnostics.hrl similarity index 100% rename from test_projects/diagnostics/app_a/include/broken_diagnostics.hrl rename to test/test_projects/diagnostics/app_a/include/broken_diagnostics.hrl diff --git a/test_projects/diagnostics/app_a/include/diagnostics.hrl b/test/test_projects/diagnostics/app_a/include/diagnostics.hrl similarity index 100% rename from test_projects/diagnostics/app_a/include/diagnostics.hrl rename to test/test_projects/diagnostics/app_a/include/diagnostics.hrl diff --git a/test_projects/diagnostics/app_a/src/app_a.app.src b/test/test_projects/diagnostics/app_a/src/app_a.app.src similarity index 100% rename from test_projects/diagnostics/app_a/src/app_a.app.src rename to test/test_projects/diagnostics/app_a/src/app_a.app.src diff --git a/test_projects/diagnostics/app_a/src/app_a.erl b/test/test_projects/diagnostics/app_a/src/app_a.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/app_a.erl rename to test/test_projects/diagnostics/app_a/src/app_a.erl diff --git a/test_projects/diagnostics/app_a/src/broken_parse_trans.erl b/test/test_projects/diagnostics/app_a/src/broken_parse_trans.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/broken_parse_trans.erl rename to test/test_projects/diagnostics/app_a/src/broken_parse_trans.erl diff --git a/test_projects/diagnostics/app_a/src/cascading.erl b/test/test_projects/diagnostics/app_a/src/cascading.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/cascading.erl rename to test/test_projects/diagnostics/app_a/src/cascading.erl diff --git a/test_projects/diagnostics/app_a/src/crlf.erl b/test/test_projects/diagnostics/app_a/src/crlf.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/crlf.erl rename to test/test_projects/diagnostics/app_a/src/crlf.erl diff --git a/test_projects/diagnostics/app_a/src/diagnostics.erl b/test/test_projects/diagnostics/app_a/src/diagnostics.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/diagnostics.erl rename to test/test_projects/diagnostics/app_a/src/diagnostics.erl diff --git a/test_projects/diagnostics/app_a/src/diagnostics.escript b/test/test_projects/diagnostics/app_a/src/diagnostics.escript similarity index 100% rename from test_projects/diagnostics/app_a/src/diagnostics.escript rename to test/test_projects/diagnostics/app_a/src/diagnostics.escript diff --git a/test_projects/diagnostics/app_a/src/diagnostics_errors.escript b/test/test_projects/diagnostics/app_a/src/diagnostics_errors.escript similarity index 100% rename from test_projects/diagnostics/app_a/src/diagnostics_errors.escript rename to test/test_projects/diagnostics/app_a/src/diagnostics_errors.escript diff --git a/test_projects/diagnostics/app_a/src/diagnostics_warnings.escript b/test/test_projects/diagnostics/app_a/src/diagnostics_warnings.escript similarity index 100% rename from test_projects/diagnostics/app_a/src/diagnostics_warnings.escript rename to test/test_projects/diagnostics/app_a/src/diagnostics_warnings.escript diff --git a/test_projects/diagnostics/app_a/src/erlang_diagnostics_errors_gen.erl b/test/test_projects/diagnostics/app_a/src/erlang_diagnostics_errors_gen.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/erlang_diagnostics_errors_gen.erl rename to test/test_projects/diagnostics/app_a/src/erlang_diagnostics_errors_gen.erl diff --git a/test_projects/diagnostics/app_a/src/file_attribute.erl b/test/test_projects/diagnostics/app_a/src/file_attribute.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/file_attribute.erl rename to test/test_projects/diagnostics/app_a/src/file_attribute.erl diff --git a/test_projects/diagnostics/app_a/src/lint_recursive.erl b/test/test_projects/diagnostics/app_a/src/lint_recursive.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/lint_recursive.erl rename to test/test_projects/diagnostics/app_a/src/lint_recursive.erl diff --git a/test_projects/diagnostics/app_a/src/lints.erl b/test/test_projects/diagnostics/app_a/src/lints.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/lints.erl rename to test/test_projects/diagnostics/app_a/src/lints.erl diff --git a/test_projects/diagnostics/app_a/src/otp27_docstrings.erl b/test/test_projects/diagnostics/app_a/src/otp27_docstrings.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/otp27_docstrings.erl rename to test/test_projects/diagnostics/app_a/src/otp27_docstrings.erl diff --git a/test_projects/diagnostics/app_a/src/otp27_sigils.erl b/test/test_projects/diagnostics/app_a/src/otp27_sigils.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/otp27_sigils.erl rename to test/test_projects/diagnostics/app_a/src/otp27_sigils.erl diff --git a/test_projects/diagnostics/app_a/src/otp_7655.erl b/test/test_projects/diagnostics/app_a/src/otp_7655.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/otp_7655.erl rename to test/test_projects/diagnostics/app_a/src/otp_7655.erl diff --git a/test_projects/diagnostics/app_a/src/parse_error_a_cascade.erl b/test/test_projects/diagnostics/app_a/src/parse_error_a_cascade.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/parse_error_a_cascade.erl rename to test/test_projects/diagnostics/app_a/src/parse_error_a_cascade.erl diff --git a/test_projects/diagnostics/app_a/src/suppressed.erl b/test/test_projects/diagnostics/app_a/src/suppressed.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/suppressed.erl rename to test/test_projects/diagnostics/app_a/src/suppressed.erl diff --git a/test_projects/diagnostics/app_a/src/syntax.erl b/test/test_projects/diagnostics/app_a/src/syntax.erl similarity index 100% rename from test_projects/diagnostics/app_a/src/syntax.erl rename to test/test_projects/diagnostics/app_a/src/syntax.erl diff --git a/test_projects/diagnostics/app_a/test/app_a_SUITE.erl b/test/test_projects/diagnostics/app_a/test/app_a_SUITE.erl similarity index 100% rename from test_projects/diagnostics/app_a/test/app_a_SUITE.erl rename to test/test_projects/diagnostics/app_a/test/app_a_SUITE.erl diff --git a/test_projects/diagnostics/erlang_ls.config b/test/test_projects/diagnostics/erlang_ls.config similarity index 100% rename from test_projects/diagnostics/erlang_ls.config rename to test/test_projects/diagnostics/erlang_ls.config diff --git a/test_projects/diagnostics/rebar.config b/test/test_projects/diagnostics/rebar.config similarity index 100% rename from test_projects/diagnostics/rebar.config rename to test/test_projects/diagnostics/rebar.config diff --git a/test_projects/diagnostics/test_build_info.json b/test/test_projects/diagnostics/test_build_info.json similarity index 100% rename from test_projects/diagnostics/test_build_info.json rename to test/test_projects/diagnostics/test_build_info.json diff --git a/test/test_projects/end_to_end/.elp.toml b/test/test_projects/end_to_end/.elp.toml new file mode 100644 index 0000000000..acbcd6146f --- /dev/null +++ b/test/test_projects/end_to_end/.elp.toml @@ -0,0 +1,7 @@ +[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 new file mode 100644 index 0000000000..60d39de125 --- /dev/null +++ b/test/test_projects/end_to_end/assist_examples/BUCK @@ -0,0 +1,14 @@ +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_projects/end_to_end/assist_examples/src/add_doc.erl b/test/test_projects/end_to_end/assist_examples/src/add_doc.erl similarity index 100% rename from test_projects/end_to_end/assist_examples/src/add_doc.erl rename to test/test_projects/end_to_end/assist_examples/src/add_doc.erl diff --git a/test_projects/end_to_end/assist_examples/src/assist_examples.app.src b/test/test_projects/end_to_end/assist_examples/src/assist_examples.app.src similarity index 100% rename from test_projects/end_to_end/assist_examples/src/assist_examples.app.src rename to test/test_projects/end_to_end/assist_examples/src/assist_examples.app.src diff --git a/test_projects/end_to_end/assist_examples/src/code_completion.erl b/test/test_projects/end_to_end/assist_examples/src/code_completion.erl similarity index 100% rename from test_projects/end_to_end/assist_examples/src/code_completion.erl rename to test/test_projects/end_to_end/assist_examples/src/code_completion.erl diff --git a/test_projects/end_to_end/assist_examples/src/extract_function.erl b/test/test_projects/end_to_end/assist_examples/src/extract_function.erl similarity index 100% rename from test_projects/end_to_end/assist_examples/src/extract_function.erl rename to test/test_projects/end_to_end/assist_examples/src/extract_function.erl diff --git a/test_projects/end_to_end/assist_examples/src/head_mismatch.erl b/test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl similarity index 100% rename from test_projects/end_to_end/assist_examples/src/head_mismatch.erl rename to test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl diff --git a/test_projects/end_to_end/caf/configerator/source/whatsapp/my_caf.erl b/test/test_projects/end_to_end/caf/configerator/source/whatsapp/my_caf.erl similarity index 100% rename from test_projects/end_to_end/caf/configerator/source/whatsapp/my_caf.erl rename to test/test_projects/end_to_end/caf/configerator/source/whatsapp/my_caf.erl diff --git a/test/test_projects/end_to_end/definitions/BUCK b/test/test_projects/end_to_end/definitions/BUCK new file mode 100644 index 0000000000..c9e6b204f4 --- /dev/null +++ b/test/test_projects/end_to_end/definitions/BUCK @@ -0,0 +1,14 @@ +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_projects/end_to_end/definitions/README.md b/test/test_projects/end_to_end/definitions/README.md similarity index 100% rename from test_projects/end_to_end/definitions/README.md rename to test/test_projects/end_to_end/definitions/README.md diff --git a/test_projects/end_to_end/definitions/src/definitions.app.src b/test/test_projects/end_to_end/definitions/src/definitions.app.src similarity index 100% rename from test_projects/end_to_end/definitions/src/definitions.app.src rename to test/test_projects/end_to_end/definitions/src/definitions.app.src diff --git a/test_projects/end_to_end/definitions/src/local_def.erl b/test/test_projects/end_to_end/definitions/src/local_def.erl similarity index 100% rename from test_projects/end_to_end/definitions/src/local_def.erl rename to test/test_projects/end_to_end/definitions/src/local_def.erl diff --git a/test/test_projects/end_to_end/docs/BUCK b/test/test_projects/end_to_end/docs/BUCK new file mode 100644 index 0000000000..7429863b6e --- /dev/null +++ b/test/test_projects/end_to_end/docs/BUCK @@ -0,0 +1,16 @@ +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_projects/end_to_end/docs/src/docs.app.src b/test/test_projects/end_to_end/docs/src/docs.app.src similarity index 100% rename from test_projects/end_to_end/docs/src/docs.app.src rename to test/test_projects/end_to_end/docs/src/docs.app.src diff --git a/test_projects/end_to_end/docs/src/docs.erl b/test/test_projects/end_to_end/docs/src/docs.erl similarity index 100% rename from test_projects/end_to_end/docs/src/docs.erl rename to test/test_projects/end_to_end/docs/src/docs.erl diff --git a/test_projects/end_to_end/erlang_ls.config b/test/test_projects/end_to_end/erlang_ls.config similarity index 100% rename from test_projects/end_to_end/erlang_ls.config rename to test/test_projects/end_to_end/erlang_ls.config diff --git a/test_projects/end_to_end/fixtures/erlang-stacktrace.txt b/test/test_projects/end_to_end/fixtures/erlang-stacktrace.txt similarity index 100% rename from test_projects/end_to_end/fixtures/erlang-stacktrace.txt rename to test/test_projects/end_to_end/fixtures/erlang-stacktrace.txt diff --git a/test/test_projects/end_to_end/hover/BUCK b/test/test_projects/end_to_end/hover/BUCK new file mode 100644 index 0000000000..7732dc473e --- /dev/null +++ b/test/test_projects/end_to_end/hover/BUCK @@ -0,0 +1,14 @@ +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_projects/end_to_end/hover/README.md b/test/test_projects/end_to_end/hover/README.md similarity index 100% rename from test_projects/end_to_end/hover/README.md rename to test/test_projects/end_to_end/hover/README.md diff --git a/test_projects/end_to_end/hover/src/doc_examples.erl b/test/test_projects/end_to_end/hover/src/doc_examples.erl similarity index 100% rename from test_projects/end_to_end/hover/src/doc_examples.erl rename to test/test_projects/end_to_end/hover/src/doc_examples.erl diff --git a/test_projects/end_to_end/hover/src/hover.app.src b/test/test_projects/end_to_end/hover/src/hover.app.src similarity index 100% rename from test_projects/end_to_end/hover/src/hover.app.src rename to test/test_projects/end_to_end/hover/src/hover.app.src diff --git a/test_projects/end_to_end/rebar.config b/test/test_projects/end_to_end/rebar.config similarity index 100% rename from test_projects/end_to_end/rebar.config rename to test/test_projects/end_to_end/rebar.config diff --git a/test/test_projects/end_to_end/single_errors/BUCK b/test/test_projects/end_to_end/single_errors/BUCK new file mode 100644 index 0000000000..a8f6e478b0 --- /dev/null +++ b/test/test_projects/end_to_end/single_errors/BUCK @@ -0,0 +1,14 @@ +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_projects/end_to_end/single_errors/README.md b/test/test_projects/end_to_end/single_errors/README.md similarity index 100% rename from test_projects/end_to_end/single_errors/README.md rename to test/test_projects/end_to_end/single_errors/README.md diff --git a/test_projects/end_to_end/single_errors/src/as_you_type.erl b/test/test_projects/end_to_end/single_errors/src/as_you_type.erl similarity index 100% rename from test_projects/end_to_end/single_errors/src/as_you_type.erl rename to test/test_projects/end_to_end/single_errors/src/as_you_type.erl diff --git a/test_projects/end_to_end/single_errors/src/compiler_diagnostics.erl b/test/test_projects/end_to_end/single_errors/src/compiler_diagnostics.erl similarity index 100% rename from test_projects/end_to_end/single_errors/src/compiler_diagnostics.erl rename to test/test_projects/end_to_end/single_errors/src/compiler_diagnostics.erl diff --git a/test_projects/end_to_end/single_errors/src/single_errors.app.src b/test/test_projects/end_to_end/single_errors/src/single_errors.app.src similarity index 100% rename from test_projects/end_to_end/single_errors/src/single_errors.app.src rename to test/test_projects/end_to_end/single_errors/src/single_errors.app.src diff --git a/test_projects/end_to_end/single_errors/src/spec_mismatch.erl b/test/test_projects/end_to_end/single_errors/src/spec_mismatch.erl similarity index 100% rename from test_projects/end_to_end/single_errors/src/spec_mismatch.erl rename to test/test_projects/end_to_end/single_errors/src/spec_mismatch.erl diff --git a/test_projects/end_to_end/single_errors/src/spec_mismatch.erl.2 b/test/test_projects/end_to_end/single_errors/src/spec_mismatch.erl.2 similarity index 100% rename from test_projects/end_to_end/single_errors/src/spec_mismatch.erl.2 rename to test/test_projects/end_to_end/single_errors/src/spec_mismatch.erl.2 diff --git a/test_projects/end_to_end/single_errors/src/types_on_hover.erl b/test/test_projects/end_to_end/single_errors/src/types_on_hover.erl similarity index 100% rename from test_projects/end_to_end/single_errors/src/types_on_hover.erl rename to test/test_projects/end_to_end/single_errors/src/types_on_hover.erl diff --git a/test_projects/end_to_end/single_errors/src/unused_macro.erl b/test/test_projects/end_to_end/single_errors/src/unused_macro.erl similarity index 100% rename from test_projects/end_to_end/single_errors/src/unused_macro.erl rename to test/test_projects/end_to_end/single_errors/src/unused_macro.erl diff --git a/test_projects/eqwalizer/src/eqwalizer.app.src b/test/test_projects/eqwalizer/src/eqwalizer.app.src similarity index 100% rename from test_projects/eqwalizer/src/eqwalizer.app.src rename to test/test_projects/eqwalizer/src/eqwalizer.app.src diff --git a/test_projects/eqwalizer/src/eqwalizer_specs.erl b/test/test_projects/eqwalizer/src/eqwalizer_specs.erl similarity index 100% rename from test_projects/eqwalizer/src/eqwalizer_specs.erl rename to test/test_projects/eqwalizer/src/eqwalizer_specs.erl diff --git a/test/test_projects/eqwalizer_callers/.elp.toml b/test/test_projects/eqwalizer_callers/.elp.toml new file mode 100644 index 0000000000..68476bcf2e --- /dev/null +++ b/test/test_projects/eqwalizer_callers/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "root//eqwalizer_callers/..." ] +source_root = "eqwalizer_callers" diff --git a/test_projects/eqwalizer_callers/.gitignore b/test/test_projects/eqwalizer_callers/.gitignore similarity index 100% rename from test_projects/eqwalizer_callers/.gitignore rename to test/test_projects/eqwalizer_callers/.gitignore diff --git a/test/test_projects/eqwalizer_callers/BUCK b/test/test_projects/eqwalizer_callers/BUCK new file mode 100644 index 0000000000..32012a0dc0 --- /dev/null +++ b/test/test_projects/eqwalizer_callers/BUCK @@ -0,0 +1,19 @@ +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_projects/eqwalizer_callers/app_a/include/app_a.hrl b/test/test_projects/eqwalizer_callers/app_a/include/app_a.hrl similarity index 100% rename from test_projects/eqwalizer_callers/app_a/include/app_a.hrl rename to test/test_projects/eqwalizer_callers/app_a/include/app_a.hrl diff --git a/test_projects/eqwalizer_callers/app_a/src/app_a.app.src b/test/test_projects/eqwalizer_callers/app_a/src/app_a.app.src similarity index 100% rename from test_projects/eqwalizer_callers/app_a/src/app_a.app.src rename to test/test_projects/eqwalizer_callers/app_a/src/app_a.app.src diff --git a/test_projects/eqwalizer_callers/app_a/src/app_a.erl b/test/test_projects/eqwalizer_callers/app_a/src/app_a.erl similarity index 100% rename from test_projects/eqwalizer_callers/app_a/src/app_a.erl rename to test/test_projects/eqwalizer_callers/app_a/src/app_a.erl diff --git a/test_projects/eqwalizer_callers/app_a/src/app_b.erl b/test/test_projects/eqwalizer_callers/app_a/src/app_b.erl similarity index 100% rename from test_projects/eqwalizer_callers/app_a/src/app_b.erl rename to test/test_projects/eqwalizer_callers/app_a/src/app_b.erl diff --git a/test_projects/eqwalizer_callers/app_a/test/app_a_SUITE.erl b/test/test_projects/eqwalizer_callers/app_a/test/app_a_SUITE.erl similarity index 100% rename from test_projects/eqwalizer_callers/app_a/test/app_a_SUITE.erl rename to test/test_projects/eqwalizer_callers/app_a/test/app_a_SUITE.erl diff --git a/test_projects/eqwalizer_callers/rebar.config b/test/test_projects/eqwalizer_callers/rebar.config similarity index 100% rename from test_projects/eqwalizer_callers/rebar.config rename to test/test_projects/eqwalizer_callers/rebar.config diff --git a/test_projects/eqwalizer_ignore_modules/.elp.toml b/test/test_projects/eqwalizer_ignore_modules/.elp.toml similarity index 100% rename from test_projects/eqwalizer_ignore_modules/.elp.toml rename to test/test_projects/eqwalizer_ignore_modules/.elp.toml diff --git a/test_projects/eqwalizer_ignore_modules/apps/app_a/include/app_a.hrl b/test/test_projects/eqwalizer_ignore_modules/apps/app_a/include/app_a.hrl similarity index 100% rename from test_projects/eqwalizer_ignore_modules/apps/app_a/include/app_a.hrl rename to test/test_projects/eqwalizer_ignore_modules/apps/app_a/include/app_a.hrl diff --git a/test_projects/eqwalizer_ignore_modules/apps/app_a/src/another_module_a.erl b/test/test_projects/eqwalizer_ignore_modules/apps/app_a/src/another_module_a.erl similarity index 100% rename from test_projects/eqwalizer_ignore_modules/apps/app_a/src/another_module_a.erl rename to test/test_projects/eqwalizer_ignore_modules/apps/app_a/src/another_module_a.erl diff --git a/test_projects/eqwalizer_ignore_modules/apps/app_a/src/app_a.erl b/test/test_projects/eqwalizer_ignore_modules/apps/app_a/src/app_a.erl similarity index 100% rename from test_projects/eqwalizer_ignore_modules/apps/app_a/src/app_a.erl rename to test/test_projects/eqwalizer_ignore_modules/apps/app_a/src/app_a.erl diff --git a/test_projects/eqwalizer_ignore_modules/apps/app_b/src/app_b.erl b/test/test_projects/eqwalizer_ignore_modules/apps/app_b/src/app_b.erl similarity index 100% rename from test_projects/eqwalizer_ignore_modules/apps/app_b/src/app_b.erl rename to test/test_projects/eqwalizer_ignore_modules/apps/app_b/src/app_b.erl diff --git a/test/test_projects/eqwalizer_tests/.elp.toml b/test/test_projects/eqwalizer_tests/.elp.toml new file mode 100644 index 0000000000..5dac3aa6a6 --- /dev/null +++ b/test/test_projects/eqwalizer_tests/.elp.toml @@ -0,0 +1,8 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "root//eqwalizer_tests/..." ] +source_root = "eqwalizer_tests" + +[eqwalizer] +enable_all = true diff --git a/test_projects/eqwalizer_tests/.gitignore b/test/test_projects/eqwalizer_tests/.gitignore similarity index 100% rename from test_projects/eqwalizer_tests/.gitignore rename to test/test_projects/eqwalizer_tests/.gitignore diff --git a/test_projects/eqwalizer_tests/.rebar.root b/test/test_projects/eqwalizer_tests/.rebar.root similarity index 100% rename from test_projects/eqwalizer_tests/.rebar.root rename to test/test_projects/eqwalizer_tests/.rebar.root diff --git a/test/test_projects/eqwalizer_tests/BUCK b/test/test_projects/eqwalizer_tests/BUCK new file mode 100644 index 0000000000..0817873cb0 --- /dev/null +++ b/test/test_projects/eqwalizer_tests/BUCK @@ -0,0 +1,77 @@ +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_projects/eqwalizer_tests/check/include/my_header.hrl b/test/test_projects/eqwalizer_tests/check/include/my_header.hrl similarity index 100% rename from test_projects/eqwalizer_tests/check/include/my_header.hrl rename to test/test_projects/eqwalizer_tests/check/include/my_header.hrl diff --git a/test_projects/eqwalizer_tests/check/src/any_fun_type.erl b/test/test_projects/eqwalizer_tests/check/src/any_fun_type.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/any_fun_type.erl rename to test/test_projects/eqwalizer_tests/check/src/any_fun_type.erl diff --git a/test_projects/eqwalizer_tests/check/src/apply_none.erl b/test/test_projects/eqwalizer_tests/check/src/apply_none.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/apply_none.erl rename to test/test_projects/eqwalizer_tests/check/src/apply_none.erl diff --git a/test_projects/eqwalizer_tests/check/src/approx.erl b/test/test_projects/eqwalizer_tests/check/src/approx.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/approx.erl rename to test/test_projects/eqwalizer_tests/check/src/approx.erl diff --git a/test_projects/eqwalizer_tests/check/src/as_pat.erl b/test/test_projects/eqwalizer_tests/check/src/as_pat.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/as_pat.erl rename to test/test_projects/eqwalizer_tests/check/src/as_pat.erl diff --git a/test_projects/eqwalizer_tests/check/src/auto_imports.erl b/test/test_projects/eqwalizer_tests/check/src/auto_imports.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/auto_imports.erl rename to test/test_projects/eqwalizer_tests/check/src/auto_imports.erl diff --git a/test_projects/eqwalizer_tests/check/src/behave.erl b/test/test_projects/eqwalizer_tests/check/src/behave.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/behave.erl rename to test/test_projects/eqwalizer_tests/check/src/behave.erl diff --git a/test_projects/eqwalizer_tests/check/src/binaries.erl b/test/test_projects/eqwalizer_tests/check/src/binaries.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/binaries.erl rename to test/test_projects/eqwalizer_tests/check/src/binaries.erl diff --git a/test_projects/eqwalizer_tests/check/src/booleans.erl b/test/test_projects/eqwalizer_tests/check/src/booleans.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/booleans.erl rename to test/test_projects/eqwalizer_tests/check/src/booleans.erl diff --git a/test_projects/eqwalizer_tests/check/src/callbacks1_pos.erl b/test/test_projects/eqwalizer_tests/check/src/callbacks1_pos.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/callbacks1_pos.erl rename to test/test_projects/eqwalizer_tests/check/src/callbacks1_pos.erl diff --git a/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl b/test/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl similarity index 70% rename from test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl rename to test/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl index a8495b8755..854feec923 100644 --- a/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl +++ b/test/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl @@ -3,11 +3,12 @@ %%% 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). +-module(callbacks3_neg). % @OTP27Only -export([ init/1, handle_call/3, - handle_cast/2 + handle_cast/2, + handle_info/2 ]). -behavior(gen_server). @@ -19,3 +20,7 @@ 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_projects/eqwalizer_tests/check/src/callbacks4_neg.erl b/test/test_projects/eqwalizer_tests/check/src/callbacks4_neg.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/callbacks4_neg.erl rename to test/test_projects/eqwalizer_tests/check/src/callbacks4_neg.erl diff --git a/test_projects/eqwalizer_tests/check/src/callbacks5_neg.erl b/test/test_projects/eqwalizer_tests/check/src/callbacks5_neg.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/callbacks5_neg.erl rename to test/test_projects/eqwalizer_tests/check/src/callbacks5_neg.erl diff --git a/test_projects/eqwalizer_tests/check/src/callbacks6_neg.erl b/test/test_projects/eqwalizer_tests/check/src/callbacks6_neg.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/callbacks6_neg.erl rename to test/test_projects/eqwalizer_tests/check/src/callbacks6_neg.erl diff --git a/test_projects/eqwalizer_tests/check/src/callbacks7_overload_pos.erl b/test/test_projects/eqwalizer_tests/check/src/callbacks7_overload_pos.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/callbacks7_overload_pos.erl rename to test/test_projects/eqwalizer_tests/check/src/callbacks7_overload_pos.erl diff --git a/test_projects/eqwalizer_tests/check/src/case_predicates.erl b/test/test_projects/eqwalizer_tests/check/src/case_predicates.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/case_predicates.erl rename to test/test_projects/eqwalizer_tests/check/src/case_predicates.erl diff --git a/test_projects/eqwalizer_tests/check/src/check.app.src b/test/test_projects/eqwalizer_tests/check/src/check.app.src similarity index 100% rename from test_projects/eqwalizer_tests/check/src/check.app.src rename to test/test_projects/eqwalizer_tests/check/src/check.app.src diff --git a/test_projects/eqwalizer_tests/check/src/compiler_macro.erl b/test/test_projects/eqwalizer_tests/check/src/compiler_macro.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/compiler_macro.erl rename to test/test_projects/eqwalizer_tests/check/src/compiler_macro.erl diff --git a/test_projects/eqwalizer_tests/check/src/complex_maps.erl b/test/test_projects/eqwalizer_tests/check/src/complex_maps.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/complex_maps.erl rename to test/test_projects/eqwalizer_tests/check/src/complex_maps.erl diff --git a/test_projects/eqwalizer_tests/check/src/comprehensions.erl b/test/test_projects/eqwalizer_tests/check/src/comprehensions.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/comprehensions.erl rename to test/test_projects/eqwalizer_tests/check/src/comprehensions.erl diff --git a/test_projects/eqwalizer_tests/check/src/contravariant.erl b/test/test_projects/eqwalizer_tests/check/src/contravariant.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/contravariant.erl rename to test/test_projects/eqwalizer_tests/check/src/contravariant.erl diff --git a/test_projects/eqwalizer_tests/check/src/custom.erl b/test/test_projects/eqwalizer_tests/check/src/custom.erl similarity index 99% rename from test_projects/eqwalizer_tests/check/src/custom.erl rename to test/test_projects/eqwalizer_tests/check/src/custom.erl index 77aef06bce..b6910b0fc7 100644 --- a/test_projects/eqwalizer_tests/check/src/custom.erl +++ b/test/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). +-module(custom). % @OTP27Only -import(maps, [get/2, get/3]). -compile([export_all, nowarn_export_all]). @@ -2713,3 +2713,13 @@ maps_foreach_neg(M) -> end, M ). + +-spec maps_map_2_13( + #{ka => va, kb => vb, kc => vc} +) -> + #{ka => va2, kb => vb, kc => vc}. +maps_map_2_13(M) -> + maps:map(fun + (ka, va) -> va2; + (_K, V) -> V + end, M). diff --git a/test_projects/eqwalizer_tests/check/src/detached_specs1.erl b/test/test_projects/eqwalizer_tests/check/src/detached_specs1.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/detached_specs1.erl rename to test/test_projects/eqwalizer_tests/check/src/detached_specs1.erl diff --git a/test_projects/eqwalizer_tests/check/src/detached_specs2.erl b/test/test_projects/eqwalizer_tests/check/src/detached_specs2.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/detached_specs2.erl rename to test/test_projects/eqwalizer_tests/check/src/detached_specs2.erl diff --git a/test_projects/eqwalizer_tests/check/src/dyn_calls.erl b/test/test_projects/eqwalizer_tests/check/src/dyn_calls.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/dyn_calls.erl rename to test/test_projects/eqwalizer_tests/check/src/dyn_calls.erl diff --git a/test_projects/eqwalizer_tests/check/src/dyn_remote_funs.erl b/test/test_projects/eqwalizer_tests/check/src/dyn_remote_funs.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/dyn_remote_funs.erl rename to test/test_projects/eqwalizer_tests/check/src/dyn_remote_funs.erl diff --git a/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_1.erl b/test/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_1.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/dynamic_callbacks_1.erl rename to test/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_1.erl diff --git a/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_2.erl b/test/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_2.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/dynamic_callbacks_2.erl rename to test/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_2.erl diff --git a/test_projects/eqwalizer_tests/check/src/dynamic_calls.erl b/test/test_projects/eqwalizer_tests/check/src/dynamic_calls.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/dynamic_calls.erl rename to test/test_projects/eqwalizer_tests/check/src/dynamic_calls.erl diff --git a/test_projects/eqwalizer_tests/check/src/dynamic_catch.erl b/test/test_projects/eqwalizer_tests/check/src/dynamic_catch.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/dynamic_catch.erl rename to test/test_projects/eqwalizer_tests/check/src/dynamic_catch.erl diff --git a/test_projects/eqwalizer_tests/check/src/dynamic_fun.erl b/test/test_projects/eqwalizer_tests/check/src/dynamic_fun.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/dynamic_fun.erl rename to test/test_projects/eqwalizer_tests/check/src/dynamic_fun.erl diff --git a/test_projects/eqwalizer_tests/check/src/dynamic_generics.erl b/test/test_projects/eqwalizer_tests/check/src/dynamic_generics.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/dynamic_generics.erl rename to test/test_projects/eqwalizer_tests/check/src/dynamic_generics.erl diff --git a/test_projects/eqwalizer_tests/check/src/dynamic_local_funs.erl b/test/test_projects/eqwalizer_tests/check/src/dynamic_local_funs.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/dynamic_local_funs.erl rename to test/test_projects/eqwalizer_tests/check/src/dynamic_local_funs.erl diff --git a/test_projects/eqwalizer_tests/check/src/dynamic_receive.erl b/test/test_projects/eqwalizer_tests/check/src/dynamic_receive.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/dynamic_receive.erl rename to test/test_projects/eqwalizer_tests/check/src/dynamic_receive.erl diff --git a/test_projects/eqwalizer_tests/check/src/dynamic_refine.erl b/test/test_projects/eqwalizer_tests/check/src/dynamic_refine.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/dynamic_refine.erl rename to test/test_projects/eqwalizer_tests/check/src/dynamic_refine.erl diff --git a/test_projects/eqwalizer_tests/check/src/dynamic_try_catch.erl b/test/test_projects/eqwalizer_tests/check/src/dynamic_try_catch.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/dynamic_try_catch.erl rename to test/test_projects/eqwalizer_tests/check/src/dynamic_try_catch.erl diff --git a/test_projects/eqwalizer_tests/check/src/elab_clause.erl b/test/test_projects/eqwalizer_tests/check/src/elab_clause.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/elab_clause.erl rename to test/test_projects/eqwalizer_tests/check/src/elab_clause.erl diff --git a/test_projects/eqwalizer_tests/check/src/error_messages.erl b/test/test_projects/eqwalizer_tests/check/src/error_messages.erl similarity index 64% rename from test_projects/eqwalizer_tests/check/src/error_messages.erl rename to test/test_projects/eqwalizer_tests/check/src/error_messages.erl index edeab66990..73f64ae814 100644 --- a/test_projects/eqwalizer_tests/check/src/error_messages.erl +++ b/test/test_projects/eqwalizer_tests/check/src/error_messages.erl @@ -31,3 +31,11 @@ no_record_conversion_2(Foo) -> Foo. -spec record_conversion(#foo{}) -> {foo, binary(), atom()}. record_conversion(Foo) -> Foo. + +-spec no_good_map_candidate_1(#{foo => #{large_map_key_a => large_map_val_a, large_map_key_b => large_map_val_b}}) + -> #{foo => #{large_map_key_c => large_map_val_c} | #{large_map_key_d => large_map_val_d}}. +no_good_map_candidate_1(M) -> M. + +-spec no_good_map_candidate_2(#{foo => #{large_map_key_a => large_map_val_a, large_map_key_b => large_map_val_b}}) + -> #{foo => #{large_map_key_c => large_map_val_c, large_map_key_d => large_map_val_d} | any}. +no_good_map_candidate_2(M) -> M. diff --git a/test_projects/eqwalizer_tests/check/src/fancy_generics.erl b/test/test_projects/eqwalizer_tests/check/src/fancy_generics.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/fancy_generics.erl rename to test/test_projects/eqwalizer_tests/check/src/fancy_generics.erl diff --git a/test_projects/eqwalizer_tests/check/src/format.erl b/test/test_projects/eqwalizer_tests/check/src/format.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/format.erl rename to test/test_projects/eqwalizer_tests/check/src/format.erl diff --git a/test_projects/eqwalizer_tests/check/src/fun_stats.erl b/test/test_projects/eqwalizer_tests/check/src/fun_stats.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/fun_stats.erl rename to test/test_projects/eqwalizer_tests/check/src/fun_stats.erl diff --git a/test_projects/eqwalizer_tests/check/src/fun_stats2.erl b/test/test_projects/eqwalizer_tests/check/src/fun_stats2.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/fun_stats2.erl rename to test/test_projects/eqwalizer_tests/check/src/fun_stats2.erl diff --git a/test_projects/eqwalizer_tests/check/src/funs.erl b/test/test_projects/eqwalizer_tests/check/src/funs.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/funs.erl rename to test/test_projects/eqwalizer_tests/check/src/funs.erl diff --git a/test_projects/eqwalizer_tests/check/src/funs2.erl b/test/test_projects/eqwalizer_tests/check/src/funs2.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/funs2.erl rename to test/test_projects/eqwalizer_tests/check/src/funs2.erl diff --git a/test_projects/eqwalizer_tests/check/src/funs_uncommon.erl b/test/test_projects/eqwalizer_tests/check/src/funs_uncommon.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/funs_uncommon.erl rename to test/test_projects/eqwalizer_tests/check/src/funs_uncommon.erl diff --git a/test_projects/eqwalizer_tests/check/src/generic_fun_application.erl b/test/test_projects/eqwalizer_tests/check/src/generic_fun_application.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/generic_fun_application.erl rename to test/test_projects/eqwalizer_tests/check/src/generic_fun_application.erl diff --git a/test_projects/eqwalizer_tests/check/src/generics_with_unions.erl b/test/test_projects/eqwalizer_tests/check/src/generics_with_unions.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/generics_with_unions.erl rename to test/test_projects/eqwalizer_tests/check/src/generics_with_unions.erl diff --git a/test_projects/eqwalizer_tests/check/src/gradual_bounded.erl b/test/test_projects/eqwalizer_tests/check/src/gradual_bounded.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/gradual_bounded.erl rename to test/test_projects/eqwalizer_tests/check/src/gradual_bounded.erl diff --git a/test_projects/eqwalizer_tests/check/src/gradual_complex_types.erl b/test/test_projects/eqwalizer_tests/check/src/gradual_complex_types.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/gradual_complex_types.erl rename to test/test_projects/eqwalizer_tests/check/src/gradual_complex_types.erl diff --git a/test_projects/eqwalizer_tests/check/src/gradual_custom.erl b/test/test_projects/eqwalizer_tests/check/src/gradual_custom.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/gradual_custom.erl rename to test/test_projects/eqwalizer_tests/check/src/gradual_custom.erl diff --git a/test_projects/eqwalizer_tests/check/src/gradual_lambdas.erl b/test/test_projects/eqwalizer_tests/check/src/gradual_lambdas.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/gradual_lambdas.erl rename to test/test_projects/eqwalizer_tests/check/src/gradual_lambdas.erl diff --git a/test_projects/eqwalizer_tests/check/src/gradual_maybe.erl b/test/test_projects/eqwalizer_tests/check/src/gradual_maybe.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/gradual_maybe.erl rename to test/test_projects/eqwalizer_tests/check/src/gradual_maybe.erl diff --git a/test_projects/eqwalizer_tests/check/src/gradual_misc.erl b/test/test_projects/eqwalizer_tests/check/src/gradual_misc.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/gradual_misc.erl rename to test/test_projects/eqwalizer_tests/check/src/gradual_misc.erl diff --git a/test_projects/eqwalizer_tests/check/src/gradual_overloaded.erl b/test/test_projects/eqwalizer_tests/check/src/gradual_overloaded.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/gradual_overloaded.erl rename to test/test_projects/eqwalizer_tests/check/src/gradual_overloaded.erl diff --git a/test_projects/eqwalizer_tests/check/src/gradual_regression_01.erl b/test/test_projects/eqwalizer_tests/check/src/gradual_regression_01.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/gradual_regression_01.erl rename to test/test_projects/eqwalizer_tests/check/src/gradual_regression_01.erl diff --git a/test_projects/eqwalizer_tests/check/src/gradual_untyped.erl b/test/test_projects/eqwalizer_tests/check/src/gradual_untyped.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/gradual_untyped.erl rename to test/test_projects/eqwalizer_tests/check/src/gradual_untyped.erl diff --git a/test_projects/eqwalizer_tests/check/src/guard_b_connections.erl b/test/test_projects/eqwalizer_tests/check/src/guard_b_connections.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/guard_b_connections.erl rename to test/test_projects/eqwalizer_tests/check/src/guard_b_connections.erl diff --git a/test_projects/eqwalizer_tests/check/src/guards.erl b/test/test_projects/eqwalizer_tests/check/src/guards.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/guards.erl rename to test/test_projects/eqwalizer_tests/check/src/guards.erl diff --git a/test_projects/eqwalizer_tests/check/src/guards_logic.erl b/test/test_projects/eqwalizer_tests/check/src/guards_logic.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/guards_logic.erl rename to test/test_projects/eqwalizer_tests/check/src/guards_logic.erl diff --git a/test_projects/eqwalizer_tests/check/src/guards_simple.erl b/test/test_projects/eqwalizer_tests/check/src/guards_simple.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/guards_simple.erl rename to test/test_projects/eqwalizer_tests/check/src/guards_simple.erl diff --git a/test_projects/eqwalizer_tests/check/src/hints.erl b/test/test_projects/eqwalizer_tests/check/src/hints.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/hints.erl rename to test/test_projects/eqwalizer_tests/check/src/hints.erl diff --git a/test_projects/eqwalizer_tests/check/src/index1.erl b/test/test_projects/eqwalizer_tests/check/src/index1.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/index1.erl rename to test/test_projects/eqwalizer_tests/check/src/index1.erl diff --git a/test_projects/eqwalizer_tests/check/src/index2.erl b/test/test_projects/eqwalizer_tests/check/src/index2.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/index2.erl rename to test/test_projects/eqwalizer_tests/check/src/index2.erl diff --git a/test_projects/eqwalizer_tests/check/src/iolists.erl b/test/test_projects/eqwalizer_tests/check/src/iolists.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/iolists.erl rename to test/test_projects/eqwalizer_tests/check/src/iolists.erl diff --git a/test_projects/eqwalizer_tests/check/src/kp_01.erl b/test/test_projects/eqwalizer_tests/check/src/kp_01.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/kp_01.erl rename to test/test_projects/eqwalizer_tests/check/src/kp_01.erl diff --git a/test_projects/eqwalizer_tests/check/src/kp_02.erl b/test/test_projects/eqwalizer_tests/check/src/kp_02.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/kp_02.erl rename to test/test_projects/eqwalizer_tests/check/src/kp_02.erl diff --git a/test_projects/eqwalizer_tests/check/src/lists_tests.erl b/test/test_projects/eqwalizer_tests/check/src/lists_tests.erl similarity index 66% rename from test_projects/eqwalizer_tests/check/src/lists_tests.erl rename to test/test_projects/eqwalizer_tests/check/src/lists_tests.erl index b50a598a24..56d03b7859 100644 --- a/test_projects/eqwalizer_tests/check/src/lists_tests.erl +++ b/test/test_projects/eqwalizer_tests/check/src/lists_tests.erl @@ -14,3 +14,15 @@ lists_union_neg(V1, V2) -> [V1, V2]. -spec lists_union_2_neg (atom(), [atom()] | [binary()]) -> [atom()] | [binary()]. lists_union_2_neg(V, L) -> [V | L]. + +-type union1() :: a | b. +-type union2() :: union1() | c. + +-spec unit_list1(union2()) -> [a] | [b] | [c]. +unit_list1(X) -> [X]. + +-spec unit_list2(union2()) -> [union2()]. +unit_list2(X) -> [X]. + +-spec unit_list3(union2()) -> [union1()] | [c]. +unit_list3(X) -> [X]. diff --git a/test_projects/eqwalizer_tests/check/src/misc.erl b/test/test_projects/eqwalizer_tests/check/src/misc.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/misc.erl rename to test/test_projects/eqwalizer_tests/check/src/misc.erl diff --git a/test_projects/eqwalizer_tests/check/src/misc_lib.erl b/test/test_projects/eqwalizer_tests/check/src/misc_lib.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/misc_lib.erl rename to test/test_projects/eqwalizer_tests/check/src/misc_lib.erl diff --git a/test_projects/eqwalizer_tests/check/src/my_behaviour.erl b/test/test_projects/eqwalizer_tests/check/src/my_behaviour.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/my_behaviour.erl rename to test/test_projects/eqwalizer_tests/check/src/my_behaviour.erl diff --git a/test_projects/eqwalizer_tests/check/src/my_gradual_behaviour.erl b/test/test_projects/eqwalizer_tests/check/src/my_gradual_behaviour.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/my_gradual_behaviour.erl rename to test/test_projects/eqwalizer_tests/check/src/my_gradual_behaviour.erl diff --git a/test_projects/eqwalizer_tests/check/src/my_header.erl b/test/test_projects/eqwalizer_tests/check/src/my_header.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/my_header.erl rename to test/test_projects/eqwalizer_tests/check/src/my_header.erl diff --git a/test_projects/eqwalizer_tests/check/src/neg.erl b/test/test_projects/eqwalizer_tests/check/src/neg.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/neg.erl rename to test/test_projects/eqwalizer_tests/check/src/neg.erl diff --git a/test_projects/eqwalizer_tests/check/src/nested1/misc_nested1.erl b/test/test_projects/eqwalizer_tests/check/src/nested1/misc_nested1.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/nested1/misc_nested1.erl rename to test/test_projects/eqwalizer_tests/check/src/nested1/misc_nested1.erl diff --git a/test_projects/eqwalizer_tests/check/src/nested1/nested2/misc_nested2.erl b/test/test_projects/eqwalizer_tests/check/src/nested1/nested2/misc_nested2.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/nested1/nested2/misc_nested2.erl rename to test/test_projects/eqwalizer_tests/check/src/nested1/nested2/misc_nested2.erl diff --git a/test_projects/eqwalizer_tests/check/src/nowarn.erl b/test/test_projects/eqwalizer_tests/check/src/nowarn.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/nowarn.erl rename to test/test_projects/eqwalizer_tests/check/src/nowarn.erl diff --git a/test_projects/eqwalizer_tests/check/src/number_comparisons.erl b/test/test_projects/eqwalizer_tests/check/src/number_comparisons.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/number_comparisons.erl rename to test/test_projects/eqwalizer_tests/check/src/number_comparisons.erl diff --git a/test_projects/eqwalizer_tests/check/src/numbers.erl b/test/test_projects/eqwalizer_tests/check/src/numbers.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/numbers.erl rename to test/test_projects/eqwalizer_tests/check/src/numbers.erl diff --git a/test_projects/eqwalizer_tests/check/src/opaque.erl b/test/test_projects/eqwalizer_tests/check/src/opaque.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/opaque.erl rename to test/test_projects/eqwalizer_tests/check/src/opaque.erl diff --git a/test_projects/eqwalizer_tests/check/src/other.erl b/test/test_projects/eqwalizer_tests/check/src/other.erl similarity index 88% rename from test_projects/eqwalizer_tests/check/src/other.erl rename to test/test_projects/eqwalizer_tests/check/src/other.erl index edb0c04186..7ac109e673 100644 --- a/test_projects/eqwalizer_tests/check/src/other.erl +++ b/test/test_projects/eqwalizer_tests/check/src/other.erl @@ -52,3 +52,9 @@ elab_var_scope(_) -> -spec map_with_dup_keys(#{ak => av1, bk => bv1, ak => av2}) -> #{ak => av1, bk => bv1}. map_with_dup_keys(M) -> M. + +% none() unions are simplified from literals too +-spec with_none(integer() | none()) -> ok. +with_none(X) -> + eqwalizer:reveal_type(X), + ok. diff --git a/test_projects/eqwalizer_tests/check/src/otp28.erl b/test/test_projects/eqwalizer_tests/check/src/otp28.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/otp28.erl rename to test/test_projects/eqwalizer_tests/check/src/otp28.erl diff --git a/test_projects/eqwalizer_tests/check/src/otp_opaques.erl b/test/test_projects/eqwalizer_tests/check/src/otp_opaques.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/otp_opaques.erl rename to test/test_projects/eqwalizer_tests/check/src/otp_opaques.erl diff --git a/test_projects/eqwalizer_tests/check/src/overloaded.erl b/test/test_projects/eqwalizer_tests/check/src/overloaded.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/overloaded.erl rename to test/test_projects/eqwalizer_tests/check/src/overloaded.erl diff --git a/test_projects/eqwalizer_tests/check/src/overloaded_specs_union.erl b/test/test_projects/eqwalizer_tests/check/src/overloaded_specs_union.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/overloaded_specs_union.erl rename to test/test_projects/eqwalizer_tests/check/src/overloaded_specs_union.erl diff --git a/test_projects/eqwalizer_tests/check/src/parametricity.erl b/test/test_projects/eqwalizer_tests/check/src/parametricity.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/parametricity.erl rename to test/test_projects/eqwalizer_tests/check/src/parametricity.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/pats.erl b/test/test_projects/eqwalizer_tests/check/src/pats.erl new file mode 100644 index 0000000000..6e8e7f1185 --- /dev/null +++ b/test/test_projects/eqwalizer_tests/check/src/pats.erl @@ -0,0 +1,31 @@ +%%% Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved. +%%% +%%% 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(pats). + +-compile([export_all, nowarn_export_all]). + +-spec return_map() -> #{a => ok} | error. +return_map() -> #{a => ok}. + +-spec patmatch1() -> ok. +patmatch1() -> + #{a := V} = _M = return_map(), + V. + +-spec patmatch2() -> ok. +patmatch2() -> + #{a := _V} = M = return_map(), + maps:get(a, M). + +-spec patmatch3_neg() -> ok. +patmatch3_neg() -> + _V = M = return_map(), + maps:get(a, M). + +-spec patmatch4() -> ok. +patmatch4() -> + M = #{a := _V} = return_map(), + maps:get(a, M). diff --git a/test_projects/eqwalizer_tests/check/src/pinned.erl b/test/test_projects/eqwalizer_tests/check/src/pinned.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/pinned.erl rename to test/test_projects/eqwalizer_tests/check/src/pinned.erl diff --git a/test_projects/eqwalizer_tests/check/src/pos.erl b/test/test_projects/eqwalizer_tests/check/src/pos.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/pos.erl rename to test/test_projects/eqwalizer_tests/check/src/pos.erl diff --git a/test_projects/eqwalizer_tests/check/src/records.erl b/test/test_projects/eqwalizer_tests/check/src/records.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/records.erl rename to test/test_projects/eqwalizer_tests/check/src/records.erl diff --git a/test_projects/eqwalizer_tests/check/src/recursive_aliases.erl b/test/test_projects/eqwalizer_tests/check/src/recursive_aliases.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/recursive_aliases.erl rename to test/test_projects/eqwalizer_tests/check/src/recursive_aliases.erl diff --git a/test_projects/eqwalizer_tests/check/src/refine.erl b/test/test_projects/eqwalizer_tests/check/src/refine.erl similarity index 94% rename from test_projects/eqwalizer_tests/check/src/refine.erl rename to test/test_projects/eqwalizer_tests/check/src/refine.erl index a887d82535..4140ba4495 100644 --- a/test_projects/eqwalizer_tests/check/src/refine.erl +++ b/test/test_projects/eqwalizer_tests/check/src/refine.erl @@ -170,33 +170,6 @@ exploit_recursive() -> refine_recursive_neg({cons, nil}) + 1, ok. -% returns a number --spec opaque1_neg( - gb_sets:set(atom())) -> - pid(). -opaque1_neg({X, _}) -> X. - -% returns a tuple --spec opaque2_neg( - erl_anno:anno()) -> - pid(). -opaque2_neg([X, _]) -> X. - -% returns an atom --spec opaque_3_neg( - sets:set(atom()) -) -> pid(). -opaque_3_neg({ - X, _, _, _, _, _, _, _, _ -}) -> X. - -% returns a 2-tuple --spec opaque_4_neg( - gb_sets:set(atom()), - {term(), term()} -) -> pid(). -opaque_4_neg(X, X) -> X. - -spec record_as_tuple1_neg (#my_rec{}, tuple()) -> none(). record_as_tuple1_neg(R, R) -> R. diff --git a/test_projects/eqwalizer_tests/check/src/scoping.erl b/test/test_projects/eqwalizer_tests/check/src/scoping.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/scoping.erl rename to test/test_projects/eqwalizer_tests/check/src/scoping.erl diff --git a/test_projects/eqwalizer_tests/check/src/skip.erl b/test/test_projects/eqwalizer_tests/check/src/skip.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/skip.erl rename to test/test_projects/eqwalizer_tests/check/src/skip.erl diff --git a/test_projects/eqwalizer_tests/check/src/static_maybe.erl b/test/test_projects/eqwalizer_tests/check/src/static_maybe.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/static_maybe.erl rename to test/test_projects/eqwalizer_tests/check/src/static_maybe.erl diff --git a/test_projects/eqwalizer_tests/check/src/strict_complex_types.erl b/test/test_projects/eqwalizer_tests/check/src/strict_complex_types.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/strict_complex_types.erl rename to test/test_projects/eqwalizer_tests/check/src/strict_complex_types.erl diff --git a/test_projects/eqwalizer_tests/check/src/strict_fun.erl b/test/test_projects/eqwalizer_tests/check/src/strict_fun.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/strict_fun.erl rename to test/test_projects/eqwalizer_tests/check/src/strict_fun.erl diff --git a/test_projects/eqwalizer_tests/check/src/strict_receive.erl b/test/test_projects/eqwalizer_tests/check/src/strict_receive.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/strict_receive.erl rename to test/test_projects/eqwalizer_tests/check/src/strict_receive.erl diff --git a/test_projects/eqwalizer_tests/check/src/subtype_neg.erl b/test/test_projects/eqwalizer_tests/check/src/subtype_neg.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/subtype_neg.erl rename to test/test_projects/eqwalizer_tests/check/src/subtype_neg.erl diff --git a/test_projects/eqwalizer_tests/check/src/subtype_pos.erl b/test/test_projects/eqwalizer_tests/check/src/subtype_pos.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/subtype_pos.erl rename to test/test_projects/eqwalizer_tests/check/src/subtype_pos.erl diff --git a/test_projects/eqwalizer_tests/check/src/t_maps.erl b/test/test_projects/eqwalizer_tests/check/src/t_maps.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/t_maps.erl rename to test/test_projects/eqwalizer_tests/check/src/t_maps.erl diff --git a/test_projects/eqwalizer_tests/check/src/tagged_tuples.erl b/test/test_projects/eqwalizer_tests/check/src/tagged_tuples.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/tagged_tuples.erl rename to test/test_projects/eqwalizer_tests/check/src/tagged_tuples.erl diff --git a/test_projects/eqwalizer_tests/check/src/test.erl b/test/test_projects/eqwalizer_tests/check/src/test.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/test.erl rename to test/test_projects/eqwalizer_tests/check/src/test.erl diff --git a/test_projects/eqwalizer_tests/check/src/tries.erl b/test/test_projects/eqwalizer_tests/check/src/tries.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/tries.erl rename to test/test_projects/eqwalizer_tests/check/src/tries.erl diff --git a/test_projects/eqwalizer_tests/check/src/tuple_union.erl b/test/test_projects/eqwalizer_tests/check/src/tuple_union.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/tuple_union.erl rename to test/test_projects/eqwalizer_tests/check/src/tuple_union.erl diff --git a/test_projects/eqwalizer_tests/check/src/type_aliases.erl b/test/test_projects/eqwalizer_tests/check/src/type_aliases.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/type_aliases.erl rename to test/test_projects/eqwalizer_tests/check/src/type_aliases.erl diff --git a/test_projects/eqwalizer_tests/check/src/type_asserts.erl b/test/test_projects/eqwalizer_tests/check/src/type_asserts.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/type_asserts.erl rename to test/test_projects/eqwalizer_tests/check/src/type_asserts.erl diff --git a/test_projects/eqwalizer_tests/check/src/type_predicates.erl b/test/test_projects/eqwalizer_tests/check/src/type_predicates.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/type_predicates.erl rename to test/test_projects/eqwalizer_tests/check/src/type_predicates.erl diff --git a/test_projects/eqwalizer_tests/check/src/united_fun.erl b/test/test_projects/eqwalizer_tests/check/src/united_fun.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/united_fun.erl rename to test/test_projects/eqwalizer_tests/check/src/united_fun.erl diff --git a/test_projects/eqwalizer_tests/check/src/unspecced.erl b/test/test_projects/eqwalizer_tests/check/src/unspecced.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/unspecced.erl rename to test/test_projects/eqwalizer_tests/check/src/unspecced.erl diff --git a/test_projects/eqwalizer_tests/check/src/use_dynamic_gradual.erl b/test/test_projects/eqwalizer_tests/check/src/use_dynamic_gradual.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/use_dynamic_gradual.erl rename to test/test_projects/eqwalizer_tests/check/src/use_dynamic_gradual.erl diff --git a/test_projects/eqwalizer_tests/check/src/use_dynamic_strict.erl b/test/test_projects/eqwalizer_tests/check/src/use_dynamic_strict.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/use_dynamic_strict.erl rename to test/test_projects/eqwalizer_tests/check/src/use_dynamic_strict.erl diff --git a/test_projects/eqwalizer_tests/check/src/vars1.erl b/test/test_projects/eqwalizer_tests/check/src/vars1.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/vars1.erl rename to test/test_projects/eqwalizer_tests/check/src/vars1.erl diff --git a/test_projects/eqwalizer_tests/check/src/vars2.erl b/test/test_projects/eqwalizer_tests/check/src/vars2.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/src/vars2.erl rename to test/test_projects/eqwalizer_tests/check/src/vars2.erl diff --git a/test_projects/eqwalizer_tests/check/test/check_SUITE.erl b/test/test_projects/eqwalizer_tests/check/test/check_SUITE.erl similarity index 100% rename from test_projects/eqwalizer_tests/check/test/check_SUITE.erl rename to test/test_projects/eqwalizer_tests/check/test/check_SUITE.erl diff --git a/test_projects/eqwalizer_tests/debug/include/debug_header.hrl b/test/test_projects/eqwalizer_tests/debug/include/debug_header.hrl similarity index 100% rename from test_projects/eqwalizer_tests/debug/include/debug_header.hrl rename to test/test_projects/eqwalizer_tests/debug/include/debug_header.hrl diff --git a/test_projects/eqwalizer_tests/debug/src/attributes.erl b/test/test_projects/eqwalizer_tests/debug/src/attributes.erl similarity index 100% rename from test_projects/eqwalizer_tests/debug/src/attributes.erl rename to test/test_projects/eqwalizer_tests/debug/src/attributes.erl diff --git a/test_projects/eqwalizer_tests/debug/src/debug.app.src b/test/test_projects/eqwalizer_tests/debug/src/debug.app.src similarity index 100% rename from test_projects/eqwalizer_tests/debug/src/debug.app.src rename to test/test_projects/eqwalizer_tests/debug/src/debug.app.src diff --git a/test_projects/eqwalizer_tests/debug/src/debug_header.erl b/test/test_projects/eqwalizer_tests/debug/src/debug_header.erl similarity index 100% rename from test_projects/eqwalizer_tests/debug/src/debug_header.erl rename to test/test_projects/eqwalizer_tests/debug/src/debug_header.erl diff --git a/test_projects/eqwalizer_tests/debug/src/expand.erl b/test/test_projects/eqwalizer_tests/debug/src/expand.erl similarity index 100% rename from test_projects/eqwalizer_tests/debug/src/expand.erl rename to test/test_projects/eqwalizer_tests/debug/src/expand.erl diff --git a/test_projects/eqwalizer_tests/debug/src/expr1.erl b/test/test_projects/eqwalizer_tests/debug/src/expr1.erl similarity index 100% rename from test_projects/eqwalizer_tests/debug/src/expr1.erl rename to test/test_projects/eqwalizer_tests/debug/src/expr1.erl diff --git a/test_projects/eqwalizer_tests/debug/src/expr2.erl b/test/test_projects/eqwalizer_tests/debug/src/expr2.erl similarity index 100% rename from test_projects/eqwalizer_tests/debug/src/expr2.erl rename to test/test_projects/eqwalizer_tests/debug/src/expr2.erl diff --git a/test_projects/eqwalizer_tests/debug/src/records_wip.erl b/test/test_projects/eqwalizer_tests/debug/src/records_wip.erl similarity index 100% rename from test_projects/eqwalizer_tests/debug/src/records_wip.erl rename to test/test_projects/eqwalizer_tests/debug/src/records_wip.erl diff --git a/test_projects/eqwalizer_tests/debug/src/types1.erl b/test/test_projects/eqwalizer_tests/debug/src/types1.erl similarity index 100% rename from test_projects/eqwalizer_tests/debug/src/types1.erl rename to test/test_projects/eqwalizer_tests/debug/src/types1.erl diff --git a/test_projects/eqwalizer_tests/debug/src/types2.erl b/test/test_projects/eqwalizer_tests/debug/src/types2.erl similarity index 100% rename from test_projects/eqwalizer_tests/debug/src/types2.erl rename to test/test_projects/eqwalizer_tests/debug/src/types2.erl diff --git a/test_projects/eqwalizer_tests/debug/src/wip_maps.erl b/test/test_projects/eqwalizer_tests/debug/src/wip_maps.erl similarity index 100% rename from test_projects/eqwalizer_tests/debug/src/wip_maps.erl rename to test/test_projects/eqwalizer_tests/debug/src/wip_maps.erl diff --git a/test_projects/eqwalizer_tests/elm_core/src/basics.erl b/test/test_projects/eqwalizer_tests/elm_core/src/basics.erl similarity index 100% rename from test_projects/eqwalizer_tests/elm_core/src/basics.erl rename to test/test_projects/eqwalizer_tests/elm_core/src/basics.erl diff --git a/test_projects/eqwalizer_tests/elm_core/src/elm_core.app.src b/test/test_projects/eqwalizer_tests/elm_core/src/elm_core.app.src similarity index 100% rename from test_projects/eqwalizer_tests/elm_core/src/elm_core.app.src rename to test/test_projects/eqwalizer_tests/elm_core/src/elm_core.app.src diff --git a/test_projects/eqwalizer_tests/elm_core/src/list.erl b/test/test_projects/eqwalizer_tests/elm_core/src/list.erl similarity index 100% rename from test_projects/eqwalizer_tests/elm_core/src/list.erl rename to test/test_projects/eqwalizer_tests/elm_core/src/list.erl diff --git a/test_projects/eqwalizer_tests/elm_core/src/map.erl b/test/test_projects/eqwalizer_tests/elm_core/src/map.erl similarity index 100% rename from test_projects/eqwalizer_tests/elm_core/src/map.erl rename to test/test_projects/eqwalizer_tests/elm_core/src/map.erl diff --git a/test_projects/eqwalizer_tests/elm_core/src/map_ffi.erl b/test/test_projects/eqwalizer_tests/elm_core/src/map_ffi.erl similarity index 100% rename from test_projects/eqwalizer_tests/elm_core/src/map_ffi.erl rename to test/test_projects/eqwalizer_tests/elm_core/src/map_ffi.erl diff --git a/test_projects/eqwalizer_tests/elm_core/src/maybe.erl b/test/test_projects/eqwalizer_tests/elm_core/src/maybe.erl similarity index 100% rename from test_projects/eqwalizer_tests/elm_core/src/maybe.erl rename to test/test_projects/eqwalizer_tests/elm_core/src/maybe.erl diff --git a/test_projects/eqwalizer_tests/elm_core/src/result.erl b/test/test_projects/eqwalizer_tests/elm_core/src/result.erl similarity index 100% rename from test_projects/eqwalizer_tests/elm_core/src/result.erl rename to test/test_projects/eqwalizer_tests/elm_core/src/result.erl diff --git a/test_projects/eqwalizer_tests/elm_core/src/tuple.erl b/test/test_projects/eqwalizer_tests/elm_core/src/tuple.erl similarity index 100% rename from test_projects/eqwalizer_tests/elm_core/src/tuple.erl rename to test/test_projects/eqwalizer_tests/elm_core/src/tuple.erl diff --git a/test_projects/eqwalizer_tests/eqwalizer/include/eqwalizer.hrl b/test/test_projects/eqwalizer_tests/eqwalizer/include/eqwalizer.hrl similarity index 100% rename from test_projects/eqwalizer_tests/eqwalizer/include/eqwalizer.hrl rename to test/test_projects/eqwalizer_tests/eqwalizer/include/eqwalizer.hrl diff --git a/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.app.src b/test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.app.src similarity index 100% rename from test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.app.src rename to test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.app.src diff --git a/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.erl b/test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.erl similarity index 100% rename from test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.erl rename to test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.erl diff --git a/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer_specs.erl b/test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer_specs.erl similarity index 100% rename from test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer_specs.erl rename to test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer_specs.erl diff --git a/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_build_info_prv.erl b/test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_build_info_prv.erl similarity index 100% rename from test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_build_info_prv.erl rename to test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_build_info_prv.erl diff --git a/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.app.src b/test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.app.src similarity index 100% rename from test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.app.src rename to test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.app.src diff --git a/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.erl b/test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.erl similarity index 100% rename from test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.erl rename to test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.erl diff --git a/test_projects/eqwalizer_tests/eqwater/readme.md b/test/test_projects/eqwalizer_tests/eqwater/readme.md similarity index 100% rename from test_projects/eqwalizer_tests/eqwater/readme.md rename to test/test_projects/eqwalizer_tests/eqwater/readme.md diff --git a/test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl b/test/test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl similarity index 85% rename from test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl rename to test/test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl index ff4a3a1d84..b7a5f8b81b 100644 --- a/test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl +++ b/test/test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl @@ -30,3 +30,9 @@ test3_neg({{Tag1, _}, {_, _}}) -> -> none(). test4_neg({{_, _}, {Tag2, _}}) -> Tag2. + +-record(foo, {f1 :: atom(), f2 :: atom()}). + +-spec test5(#foo{} | {ok, a | ok}) -> ok. +test5({ok, a}) -> ok; +test5({ok, V}) -> V. diff --git a/test_projects/eqwalizer_tests/eqwater/src/eqwater.app.src b/test/test_projects/eqwalizer_tests/eqwater/src/eqwater.app.src similarity index 100% rename from test_projects/eqwalizer_tests/eqwater/src/eqwater.app.src rename to test/test_projects/eqwalizer_tests/eqwater/src/eqwater.app.src diff --git a/test_projects/eqwalizer_tests/eqwater/src/eqwater.erl b/test/test_projects/eqwalizer_tests/eqwater/src/eqwater.erl similarity index 98% rename from test_projects/eqwalizer_tests/eqwater/src/eqwater.erl rename to test/test_projects/eqwalizer_tests/eqwater/src/eqwater.erl index f63202453a..839cc3d8c5 100644 --- a/test_projects/eqwalizer_tests/eqwater/src/eqwater.erl +++ b/test/test_projects/eqwalizer_tests/eqwater/src/eqwater.erl @@ -1300,3 +1300,11 @@ negate_number(N) -> N. (dynamic(), ok | err) -> ok. refine_dynamic(D, A) when is_atom(D) andalso A == err -> ok; refine_dynamic(D, A) when is_atom(D) -> A. + +-spec negate_fun(F :: fun((number(), number()) -> term()) | ok) -> ok. +negate_fun(F) when is_function(F, 2) -> ok; +negate_fun(F) -> F. + +-spec negate_fun_neg(F :: fun((number(), number()) -> term()) | ok) -> ok. +negate_fun_neg(F) when is_function(F, 2) -> F; +negate_fun_neg(F) -> F. diff --git a/test_projects/eqwalizer_tests/eqwater/src/eqwater_aliases.erl b/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_aliases.erl similarity index 100% rename from test_projects/eqwalizer_tests/eqwater/src/eqwater_aliases.erl rename to test/test_projects/eqwalizer_tests/eqwater/src/eqwater_aliases.erl diff --git a/test_projects/eqwalizer_tests/eqwater/src/eqwater_generics.erl b/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_generics.erl similarity index 100% rename from test_projects/eqwalizer_tests/eqwater/src/eqwater_generics.erl rename to test/test_projects/eqwalizer_tests/eqwater/src/eqwater_generics.erl diff --git a/test_projects/eqwalizer_tests/eqwater/src/eqwater_lists.erl b/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_lists.erl similarity index 100% rename from test_projects/eqwalizer_tests/eqwater/src/eqwater_lists.erl rename to test/test_projects/eqwalizer_tests/eqwater/src/eqwater_lists.erl diff --git a/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl b/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl similarity index 89% rename from test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl rename to test/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl index 78ae852b8a..68d938f790 100644 --- a/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl +++ b/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl @@ -59,3 +59,13 @@ 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_projects/eqwalizer_tests/eqwater/src/eqwater_records.erl b/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_records.erl similarity index 100% rename from test_projects/eqwalizer_tests/eqwater/src/eqwater_records.erl rename to test/test_projects/eqwalizer_tests/eqwater/src/eqwater_records.erl diff --git a/test_projects/eqwalizer_tests/eqwater/src/eqwater_sound.erl b/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_sound.erl similarity index 100% rename from test_projects/eqwalizer_tests/eqwater/src/eqwater_sound.erl rename to test/test_projects/eqwalizer_tests/eqwater/src/eqwater_sound.erl diff --git a/test_projects/eqwalizer_tests/eqwater/src/unlimited_refinement.erl b/test/test_projects/eqwalizer_tests/eqwater/src/unlimited_refinement.erl similarity index 100% rename from test_projects/eqwalizer_tests/eqwater/src/unlimited_refinement.erl rename to test/test_projects/eqwalizer_tests/eqwater/src/unlimited_refinement.erl diff --git a/test_projects/standard/app_a/.eqwalizer b/test/test_projects/eqwalizer_tests/fault_tolerance/.eqwalizer similarity index 100% rename from test_projects/standard/app_a/.eqwalizer rename to test/test_projects/eqwalizer_tests/fault_tolerance/.eqwalizer diff --git a/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.app.src b/test/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.app.src similarity index 100% rename from test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.app.src rename to test/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.app.src diff --git a/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.erl b/test/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.erl similarity index 100% rename from test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.erl rename to test/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.erl diff --git a/test_projects/eqwalizer_tests/options/src/bad_maps.erl b/test/test_projects/eqwalizer_tests/options/src/bad_maps.erl similarity index 100% rename from test_projects/eqwalizer_tests/options/src/bad_maps.erl rename to test/test_projects/eqwalizer_tests/options/src/bad_maps.erl diff --git a/test_projects/eqwalizer_tests/options/src/dynamic_lambdas.erl b/test/test_projects/eqwalizer_tests/options/src/dynamic_lambdas.erl similarity index 100% rename from test_projects/eqwalizer_tests/options/src/dynamic_lambdas.erl rename to test/test_projects/eqwalizer_tests/options/src/dynamic_lambdas.erl diff --git a/test_projects/eqwalizer_tests/options/src/options.app.src b/test/test_projects/eqwalizer_tests/options/src/options.app.src similarity index 100% rename from test_projects/eqwalizer_tests/options/src/options.app.src rename to test/test_projects/eqwalizer_tests/options/src/options.app.src diff --git a/test_projects/eqwalizer_tests/options/src/overloaded_specs_dynamic_result.erl b/test/test_projects/eqwalizer_tests/options/src/overloaded_specs_dynamic_result.erl similarity index 100% rename from test_projects/eqwalizer_tests/options/src/overloaded_specs_dynamic_result.erl rename to test/test_projects/eqwalizer_tests/options/src/overloaded_specs_dynamic_result.erl diff --git a/test_projects/eqwalizer_tests/options/src/redundant_guards.erl b/test/test_projects/eqwalizer_tests/options/src/redundant_guards.erl similarity index 100% rename from test_projects/eqwalizer_tests/options/src/redundant_guards.erl rename to test/test_projects/eqwalizer_tests/options/src/redundant_guards.erl diff --git a/test_projects/eqwalizer_tests/options/src/uncovered_clauses.erl b/test/test_projects/eqwalizer_tests/options/src/uncovered_clauses.erl similarity index 100% rename from test_projects/eqwalizer_tests/options/src/uncovered_clauses.erl rename to test/test_projects/eqwalizer_tests/options/src/uncovered_clauses.erl diff --git a/test_projects/eqwalizer_tests/rebar.config b/test/test_projects/eqwalizer_tests/rebar.config similarity index 100% rename from test_projects/eqwalizer_tests/rebar.config rename to test/test_projects/eqwalizer_tests/rebar.config diff --git a/test/test_projects/hierarchical_config/.elp.toml b/test/test_projects/hierarchical_config/.elp.toml new file mode 100644 index 0000000000..e4d04eb6e0 --- /dev/null +++ b/test/test_projects/hierarchical_config/.elp.toml @@ -0,0 +1,5 @@ +[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 new file mode 100644 index 0000000000..6cc536f399 --- /dev/null +++ b/test/test_projects/hierarchical_config/.elp_lint.toml @@ -0,0 +1,5 @@ +enabled_lints = [] +disabled_lints = [ + "W0012", + "W0046" +] diff --git a/test/test_projects/hierarchical_config/BUCK b/test/test_projects/hierarchical_config/BUCK new file mode 100644 index 0000000000..bc78a42d57 --- /dev/null +++ b/test/test_projects/hierarchical_config/BUCK @@ -0,0 +1,23 @@ +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 new file mode 100644 index 0000000000..7445514e73 --- /dev/null +++ b/test/test_projects/hierarchical_config/app_a/.elp_lint.toml @@ -0,0 +1,4 @@ +enabled_lints = [] +disabled_lints = [ + "W0002" +] diff --git a/test_projects/in_place_tests/app_a/src/app_a.app.src b/test/test_projects/hierarchical_config/app_a/src/app_a.app.src similarity index 100% rename from test_projects/in_place_tests/app_a/src/app_a.app.src rename to test/test_projects/hierarchical_config/app_a/src/app_a.app.src 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 new file mode 100644 index 0000000000..5b856d4f02 --- /dev/null +++ b/test/test_projects/hierarchical_config/app_a/src/app_a.erl @@ -0,0 +1,7 @@ +-module(app_a). + +-define(MACRO_A, 1). +-define(MACRO_B, 1). + +main() -> + ?MACRO_A. diff --git a/test_projects/linter/app_b/src/app_b.app.src b/test/test_projects/hierarchical_config/app_b/src/app_b.app.src similarity index 100% rename from test_projects/linter/app_b/src/app_b.app.src rename to test/test_projects/hierarchical_config/app_b/src/app_b.app.src 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 new file mode 100644 index 0000000000..ad2453d0de --- /dev/null +++ b/test/test_projects/hierarchical_config/app_b/src/app_b.erl @@ -0,0 +1,7 @@ +-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 new file mode 100644 index 0000000000..2dcacbc5b3 --- /dev/null +++ b/test/test_projects/hierarchical_config/rebar.config @@ -0,0 +1,7 @@ +{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 new file mode 100644 index 0000000000..70edcc3f03 --- /dev/null +++ b/test/test_projects/in_place_tests/.elp.toml @@ -0,0 +1,5 @@ +[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 new file mode 100644 index 0000000000..f4f354e7ee --- /dev/null +++ b/test/test_projects/in_place_tests/BUCK @@ -0,0 +1,19 @@ +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_projects/in_place_tests/README.md b/test/test_projects/in_place_tests/README.md similarity index 100% rename from test_projects/in_place_tests/README.md rename to test/test_projects/in_place_tests/README.md diff --git a/test_projects/in_place_tests/app_a/extra/app_a.erl b/test/test_projects/in_place_tests/app_a/extra/app_a.erl similarity index 100% rename from test_projects/in_place_tests/app_a/extra/app_a.erl rename to test/test_projects/in_place_tests/app_a/extra/app_a.erl diff --git a/test_projects/in_place_tests/app_a/include/app_a.hrl b/test/test_projects/in_place_tests/app_a/include/app_a.hrl similarity index 100% rename from test_projects/in_place_tests/app_a/include/app_a.hrl rename to test/test_projects/in_place_tests/app_a/include/app_a.hrl diff --git a/test_projects/in_place_tests/app_a/include/broken_diagnostics.hrl b/test/test_projects/in_place_tests/app_a/include/broken_diagnostics.hrl similarity index 100% rename from test_projects/in_place_tests/app_a/include/broken_diagnostics.hrl rename to test/test_projects/in_place_tests/app_a/include/broken_diagnostics.hrl diff --git a/test_projects/in_place_tests/app_a/include/diagnostics.hrl b/test/test_projects/in_place_tests/app_a/include/diagnostics.hrl similarity index 100% rename from test_projects/in_place_tests/app_a/include/diagnostics.hrl rename to test/test_projects/in_place_tests/app_a/include/diagnostics.hrl diff --git a/test_projects/linter/app_a/src/app_a.app.src b/test/test_projects/in_place_tests/app_a/src/app_a.app.src similarity index 100% rename from test_projects/linter/app_a/src/app_a.app.src rename to test/test_projects/in_place_tests/app_a/src/app_a.app.src diff --git a/test_projects/in_place_tests/app_a/src/app_a.erl b/test/test_projects/in_place_tests/app_a/src/app_a.erl similarity index 100% rename from test_projects/in_place_tests/app_a/src/app_a.erl rename to test/test_projects/in_place_tests/app_a/src/app_a.erl diff --git a/test_projects/in_place_tests/app_a/src/lints.erl b/test/test_projects/in_place_tests/app_a/src/lints.erl similarity index 100% rename from test_projects/in_place_tests/app_a/src/lints.erl rename to test/test_projects/in_place_tests/app_a/src/lints.erl diff --git a/test_projects/in_place_tests/app_a/test/app_a_SUITE.erl b/test/test_projects/in_place_tests/app_a/test/app_a_SUITE.erl similarity index 100% rename from test_projects/in_place_tests/app_a/test/app_a_SUITE.erl rename to test/test_projects/in_place_tests/app_a/test/app_a_SUITE.erl diff --git a/test_projects/in_place_tests/erlang_ls.config b/test/test_projects/in_place_tests/erlang_ls.config similarity index 100% rename from test_projects/in_place_tests/erlang_ls.config rename to test/test_projects/in_place_tests/erlang_ls.config diff --git a/test_projects/in_place_tests/rebar.config b/test/test_projects/in_place_tests/rebar.config similarity index 100% rename from test_projects/in_place_tests/rebar.config rename to test/test_projects/in_place_tests/rebar.config diff --git a/test/test_projects/include_lib_dependency_test/.elp.toml b/test/test_projects/include_lib_dependency_test/.elp.toml new file mode 100644 index 0000000000..9d1c859339 --- /dev/null +++ b/test/test_projects/include_lib_dependency_test/.elp.toml @@ -0,0 +1,5 @@ +[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 new file mode 100644 index 0000000000..54b81c47b5 --- /dev/null +++ b/test/test_projects/include_lib_dependency_test/BUCK @@ -0,0 +1,43 @@ +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_projects/include_lib_dependency_test/external_app/include/external_header.hrl b/test/test_projects/include_lib_dependency_test/external_app/include/external_header.hrl similarity index 100% rename from test_projects/include_lib_dependency_test/external_app/include/external_header.hrl rename to test/test_projects/include_lib_dependency_test/external_app/include/external_header.hrl diff --git a/test_projects/include_lib_dependency_test/external_app/src/external_app.app.src b/test/test_projects/include_lib_dependency_test/external_app/src/external_app.app.src similarity index 100% rename from test_projects/include_lib_dependency_test/external_app/src/external_app.app.src rename to test/test_projects/include_lib_dependency_test/external_app/src/external_app.app.src diff --git a/test_projects/include_lib_dependency_test/external_app/src/external_app.erl b/test/test_projects/include_lib_dependency_test/external_app/src/external_app.erl similarity index 100% rename from test_projects/include_lib_dependency_test/external_app/src/external_app.erl rename to test/test_projects/include_lib_dependency_test/external_app/src/external_app.erl diff --git a/test_projects/include_lib_dependency_test/extra_app/include/extra_header.hrl b/test/test_projects/include_lib_dependency_test/extra_app/include/extra_header.hrl similarity index 100% rename from test_projects/include_lib_dependency_test/extra_app/include/extra_header.hrl rename to test/test_projects/include_lib_dependency_test/extra_app/include/extra_header.hrl diff --git a/test_projects/include_lib_dependency_test/extra_app/src/extra_app.app.src b/test/test_projects/include_lib_dependency_test/extra_app/src/extra_app.app.src similarity index 100% rename from test_projects/include_lib_dependency_test/extra_app/src/extra_app.app.src rename to test/test_projects/include_lib_dependency_test/extra_app/src/extra_app.app.src diff --git a/test_projects/include_lib_dependency_test/extra_app/src/extra_app.erl b/test/test_projects/include_lib_dependency_test/extra_app/src/extra_app.erl similarity index 100% rename from test_projects/include_lib_dependency_test/extra_app/src/extra_app.erl rename to test/test_projects/include_lib_dependency_test/extra_app/src/extra_app.erl diff --git a/test_projects/include_lib_dependency_test/main_app/src/main_app.app.src b/test/test_projects/include_lib_dependency_test/main_app/src/main_app.app.src similarity index 100% rename from test_projects/include_lib_dependency_test/main_app/src/main_app.app.src rename to test/test_projects/include_lib_dependency_test/main_app/src/main_app.app.src diff --git a/test_projects/include_lib_dependency_test/main_app/src/main_app.erl b/test/test_projects/include_lib_dependency_test/main_app/src/main_app.erl similarity index 100% rename from test_projects/include_lib_dependency_test/main_app/src/main_app.erl rename to test/test_projects/include_lib_dependency_test/main_app/src/main_app.erl diff --git a/test_projects/include_lib_dependency_test/normal_dep/include/assert.hrl b/test/test_projects/include_lib_dependency_test/normal_dep/include/assert.hrl similarity index 100% rename from test_projects/include_lib_dependency_test/normal_dep/include/assert.hrl rename to test/test_projects/include_lib_dependency_test/normal_dep/include/assert.hrl diff --git a/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.app.src b/test/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.app.src similarity index 100% rename from test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.app.src rename to test/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.app.src diff --git a/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.erl b/test/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.erl similarity index 100% rename from test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.erl rename to test/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.erl diff --git a/test_projects/include_lib_dependency_test/rebar.config b/test/test_projects/include_lib_dependency_test/rebar.config similarity index 100% rename from test_projects/include_lib_dependency_test/rebar.config rename to test/test_projects/include_lib_dependency_test/rebar.config diff --git a/test/test_projects/linter/.elp.toml b/test/test_projects/linter/.elp.toml new file mode 100644 index 0000000000..4820625b2d --- /dev/null +++ b/test/test_projects/linter/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "root//linter/..." ] +source_root = "linter" diff --git a/test_projects/linter/.elp_lint.toml b/test/test_projects/linter/.elp_lint.toml similarity index 100% rename from test_projects/linter/.elp_lint.toml rename to test/test_projects/linter/.elp_lint.toml diff --git a/test_projects/linter/.gitignore b/test/test_projects/linter/.gitignore similarity index 100% rename from test_projects/linter/.gitignore rename to test/test_projects/linter/.gitignore diff --git a/test/test_projects/linter/BUCK b/test/test_projects/linter/BUCK new file mode 100644 index 0000000000..2db8750582 --- /dev/null +++ b/test/test_projects/linter/BUCK @@ -0,0 +1,41 @@ +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_projects/linter/app_a/include/app_a.hrl b/test/test_projects/linter/app_a/include/app_a.hrl similarity index 100% rename from test_projects/linter/app_a/include/app_a.hrl rename to test/test_projects/linter/app_a/include/app_a.hrl diff --git a/test_projects/linter_bad_config/app_a/src/app_a.app.src b/test/test_projects/linter/app_a/src/app_a.app.src similarity index 100% rename from test_projects/linter_bad_config/app_a/src/app_a.app.src rename to test/test_projects/linter/app_a/src/app_a.app.src diff --git a/test_projects/linter/app_a/src/app_a.erl b/test/test_projects/linter/app_a/src/app_a.erl similarity index 70% rename from test_projects/linter/app_a/src/app_a.erl rename to test/test_projects/linter/app_a/src/app_a.erl index 167b8e6d6d..86593395dd 100644 --- a/test_projects/linter/app_a/src/app_a.erl +++ b/test/test_projects/linter/app_a/src/app_a.erl @@ -14,3 +14,9 @@ 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_projects/linter/app_a/src/app_a_edoc.erl b/test/test_projects/linter/app_a/src/app_a_edoc.erl similarity index 100% rename from test_projects/linter/app_a/src/app_a_edoc.erl rename to test/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/test_projects/linter/app_a/src/app_a_ssr.erl new file mode 100644 index 0000000000..a7f6970376 --- /dev/null +++ b/test/test_projects/linter/app_a/src/app_a_ssr.erl @@ -0,0 +1,11 @@ +-module(app_a_ssr). + +-export([bar/1, bar2/0]). + +%% Used for testing visible parens matching +bar(X) -> + X = ((3)), + X = (4). + +-define(BAR(X), {X}). +bar2() -> ?BAR(4). diff --git a/test_projects/linter/app_a/src/app_a_unused_param.erl b/test/test_projects/linter/app_a/src/app_a_unused_param.erl similarity index 100% rename from test_projects/linter/app_a/src/app_a_unused_param.erl rename to test/test_projects/linter/app_a/src/app_a_unused_param.erl diff --git a/test_projects/linter/app_a/src/custom_function_matches.erl b/test/test_projects/linter/app_a/src/custom_function_matches.erl similarity index 100% rename from test_projects/linter/app_a/src/custom_function_matches.erl rename to test/test_projects/linter/app_a/src/custom_function_matches.erl diff --git a/test_projects/linter/app_a/src/expression_updates_literal.erl b/test/test_projects/linter/app_a/src/expression_updates_literal.erl similarity index 100% rename from test_projects/linter/app_a/src/expression_updates_literal.erl rename to test/test_projects/linter/app_a/src/expression_updates_literal.erl diff --git a/test_projects/linter/app_a/src/spelling.erl b/test/test_projects/linter/app_a/src/spelling.erl similarity index 100% rename from test_projects/linter/app_a/src/spelling.erl rename to test/test_projects/linter/app_a/src/spelling.erl diff --git a/test_projects/linter/app_a/test/app_a_SUITE.erl b/test/test_projects/linter/app_a/test/app_a_SUITE.erl similarity index 100% rename from test_projects/linter/app_a/test/app_a_SUITE.erl rename to test/test_projects/linter/app_a/test/app_a_SUITE.erl diff --git a/test_projects/linter/app_a/test/app_a_test_helpers.erl b/test/test_projects/linter/app_a/test/app_a_test_helpers.erl similarity index 100% rename from test_projects/linter/app_a/test/app_a_test_helpers.erl rename to test/test_projects/linter/app_a/test/app_a_test_helpers.erl diff --git a/test_projects/linter/app_a/test/app_a_test_helpers_not_opted_in.erl b/test/test_projects/linter/app_a/test/app_a_test_helpers_not_opted_in.erl similarity index 100% rename from test_projects/linter/app_a/test/app_a_test_helpers_not_opted_in.erl rename to test/test_projects/linter/app_a/test/app_a_test_helpers_not_opted_in.erl diff --git a/test_projects/linter/app_a/test/app_a_unreachable_test_SUITE.erl b/test/test_projects/linter/app_a/test/app_a_unreachable_test_SUITE.erl similarity index 100% rename from test_projects/linter/app_a/test/app_a_unreachable_test_SUITE.erl rename to test/test_projects/linter/app_a/test/app_a_unreachable_test_SUITE.erl diff --git a/test_projects/linter/app_a/test/app_test_helpers_no_errors.erl b/test/test_projects/linter/app_a/test/app_test_helpers_no_errors.erl similarity index 100% rename from test_projects/linter/app_a/test/app_test_helpers_no_errors.erl rename to test/test_projects/linter/app_a/test/app_test_helpers_no_errors.erl diff --git a/test_projects/linter_bad_config/linter/app_b/src/app_b.app.src b/test/test_projects/linter/app_b/src/app_b.app.src similarity index 100% rename from test_projects/linter_bad_config/linter/app_b/src/app_b.app.src rename to test/test_projects/linter/app_b/src/app_b.app.src diff --git a/test_projects/linter/app_b/src/app_b.erl b/test/test_projects/linter/app_b/src/app_b.erl similarity index 100% rename from test_projects/linter/app_b/src/app_b.erl rename to test/test_projects/linter/app_b/src/app_b.erl diff --git a/test_projects/linter/app_b/src/app_b_unused_param.erl b/test/test_projects/linter/app_b/src/app_b_unused_param.erl similarity index 100% rename from test_projects/linter/app_b/src/app_b_unused_param.erl rename to test/test_projects/linter/app_b/src/app_b_unused_param.erl diff --git a/test_projects/linter/elp_lint_adhoc.toml b/test/test_projects/linter/elp_lint_adhoc.toml similarity index 100% rename from test_projects/linter/elp_lint_adhoc.toml rename to test/test_projects/linter/elp_lint_adhoc.toml diff --git a/test_projects/linter/elp_lint_custom_function_matches.toml b/test/test_projects/linter/elp_lint_custom_function_matches.toml similarity index 100% rename from test_projects/linter/elp_lint_custom_function_matches.toml rename to test/test_projects/linter/elp_lint_custom_function_matches.toml diff --git a/test/test_projects/linter/elp_lint_ssr_adhoc.toml b/test/test_projects/linter/elp_lint_ssr_adhoc.toml new file mode 100644 index 0000000000..2aa4491ab2 --- /dev/null +++ b/test/test_projects/linter/elp_lint_ssr_adhoc.toml @@ -0,0 +1,5 @@ +enabled_lints = ["ad-hoc: ssr-match"] + +[[ad_hoc_lints.lints]] +type = "LintMatchSsr" +ssr_pattern = "ssr: {_@A, _@B}." diff --git a/test/test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml b/test/test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml new file mode 100644 index 0000000000..c4bee7057f --- /dev/null +++ b/test/test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml @@ -0,0 +1,5 @@ +enabled_lints = ["ad-hoc: ssr-match"] + +[[ad_hoc_lints.lints]] +type = "LintMatchSsr" +ssr_pattern = "ssr: {_@A, = 10}." diff --git a/test_projects/linter/elp_lint_test1.toml b/test/test_projects/linter/elp_lint_test1.toml similarity index 100% rename from test_projects/linter/elp_lint_test1.toml rename to test/test_projects/linter/elp_lint_test1.toml diff --git a/test_projects/linter/elp_lint_test2.toml b/test/test_projects/linter/elp_lint_test2.toml similarity index 54% rename from test_projects/linter/elp_lint_test2.toml rename to test/test_projects/linter/elp_lint_test2.toml index 22878a22a6..0b70173c8b 100644 --- a/test_projects/linter/elp_lint_test2.toml +++ b/test/test_projects/linter/elp_lint_test2.toml @@ -1,2 +1,5 @@ enabled_lints =['L1268', 'W0011', 'W0012'] disabled_lints = [] + +[linters.compile-warn-missing-spec] +enabled = true diff --git a/test_projects/linter/elp_lint_test_ignore.toml b/test/test_projects/linter/elp_lint_test_ignore.toml similarity index 100% rename from test_projects/linter/elp_lint_test_ignore.toml rename to test/test_projects/linter/elp_lint_test_ignore.toml diff --git a/test_projects/linter/elp_lint_warnings_as_errors.toml b/test/test_projects/linter/elp_lint_warnings_as_errors.toml similarity index 100% rename from test_projects/linter/elp_lint_warnings_as_errors.toml rename to test/test_projects/linter/elp_lint_warnings_as_errors.toml diff --git a/test_projects/linter/rebar.config b/test/test_projects/linter/rebar.config similarity index 100% rename from test_projects/linter/rebar.config rename to test/test_projects/linter/rebar.config diff --git a/test/test_projects/linter_bad_config/.elp.toml b/test/test_projects/linter_bad_config/.elp.toml new file mode 100644 index 0000000000..4820625b2d --- /dev/null +++ b/test/test_projects/linter_bad_config/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "root//linter/..." ] +source_root = "linter" diff --git a/test_projects/linter_bad_config/.elp_lint.toml b/test/test_projects/linter_bad_config/.elp_lint.toml similarity index 100% rename from test_projects/linter_bad_config/.elp_lint.toml rename to test/test_projects/linter_bad_config/.elp_lint.toml diff --git a/test_projects/linter_bad_config/.gitignore b/test/test_projects/linter_bad_config/.gitignore similarity index 100% rename from test_projects/linter_bad_config/.gitignore rename to test/test_projects/linter_bad_config/.gitignore diff --git a/test/test_projects/linter_bad_config/BUCK b/test/test_projects/linter_bad_config/BUCK new file mode 100644 index 0000000000..a0817a6ad6 --- /dev/null +++ b/test/test_projects/linter_bad_config/BUCK @@ -0,0 +1,12 @@ +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_projects/linter_bad_config/app_a/include/app_a.hrl b/test/test_projects/linter_bad_config/app_a/include/app_a.hrl similarity index 100% rename from test_projects/linter_bad_config/app_a/include/app_a.hrl rename to test/test_projects/linter_bad_config/app_a/include/app_a.hrl diff --git a/test_projects/linter_bad_config/linter/app_a/src/app_a.app.src b/test/test_projects/linter_bad_config/app_a/src/app_a.app.src similarity index 100% rename from test_projects/linter_bad_config/linter/app_a/src/app_a.app.src rename to test/test_projects/linter_bad_config/app_a/src/app_a.app.src diff --git a/test_projects/linter_bad_config/app_a/src/app_a.erl b/test/test_projects/linter_bad_config/app_a/src/app_a.erl similarity index 100% rename from test_projects/linter_bad_config/app_a/src/app_a.erl rename to test/test_projects/linter_bad_config/app_a/src/app_a.erl diff --git a/test/test_projects/linter_bad_config/linter/.elp.toml b/test/test_projects/linter_bad_config/linter/.elp.toml new file mode 100644 index 0000000000..4820625b2d --- /dev/null +++ b/test/test_projects/linter_bad_config/linter/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "root//linter/..." ] +source_root = "linter" diff --git a/test_projects/linter_bad_config/linter/.elp_lint.toml b/test/test_projects/linter_bad_config/linter/.elp_lint.toml similarity index 100% rename from test_projects/linter_bad_config/linter/.elp_lint.toml rename to test/test_projects/linter_bad_config/linter/.elp_lint.toml diff --git a/test_projects/linter_bad_config/linter/.gitignore b/test/test_projects/linter_bad_config/linter/.gitignore similarity index 100% rename from test_projects/linter_bad_config/linter/.gitignore rename to test/test_projects/linter_bad_config/linter/.gitignore diff --git a/test/test_projects/linter_bad_config/linter/BUCK b/test/test_projects/linter_bad_config/linter/BUCK new file mode 100644 index 0000000000..2db8750582 --- /dev/null +++ b/test/test_projects/linter_bad_config/linter/BUCK @@ -0,0 +1,41 @@ +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_projects/linter_bad_config/linter/app_a/include/app_a.hrl b/test/test_projects/linter_bad_config/linter/app_a/include/app_a.hrl similarity index 100% rename from test_projects/linter_bad_config/linter/app_a/include/app_a.hrl rename to test/test_projects/linter_bad_config/linter/app_a/include/app_a.hrl diff --git a/test_projects/standard/app_a/src/app_a.app.src b/test/test_projects/linter_bad_config/linter/app_a/src/app_a.app.src similarity index 100% rename from test_projects/standard/app_a/src/app_a.app.src rename to test/test_projects/linter_bad_config/linter/app_a/src/app_a.app.src diff --git a/test_projects/linter_bad_config/linter/app_a/src/app_a.erl b/test/test_projects/linter_bad_config/linter/app_a/src/app_a.erl similarity index 100% rename from test_projects/linter_bad_config/linter/app_a/src/app_a.erl rename to test/test_projects/linter_bad_config/linter/app_a/src/app_a.erl diff --git a/test_projects/linter_bad_config/linter/app_a/src/app_a_unused_param.erl b/test/test_projects/linter_bad_config/linter/app_a/src/app_a_unused_param.erl similarity index 100% rename from test_projects/linter_bad_config/linter/app_a/src/app_a_unused_param.erl rename to test/test_projects/linter_bad_config/linter/app_a/src/app_a_unused_param.erl diff --git a/test_projects/linter_bad_config/linter/app_a/test/app_a_SUITE.erl b/test/test_projects/linter_bad_config/linter/app_a/test/app_a_SUITE.erl similarity index 100% rename from test_projects/linter_bad_config/linter/app_a/test/app_a_SUITE.erl rename to test/test_projects/linter_bad_config/linter/app_a/test/app_a_SUITE.erl diff --git a/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers.erl b/test/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers.erl similarity index 100% rename from test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers.erl rename to test/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers.erl diff --git a/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers_not_opted_in.erl b/test/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers_not_opted_in.erl similarity index 100% rename from test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers_not_opted_in.erl rename to test/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers_not_opted_in.erl diff --git a/test_projects/linter_bad_config/linter/app_a/test/app_test_helpers_no_errors.erl b/test/test_projects/linter_bad_config/linter/app_a/test/app_test_helpers_no_errors.erl similarity index 100% rename from test_projects/linter_bad_config/linter/app_a/test/app_test_helpers_no_errors.erl rename to test/test_projects/linter_bad_config/linter/app_a/test/app_test_helpers_no_errors.erl diff --git a/test_projects/standard/app_b/src/app_b.app.src b/test/test_projects/linter_bad_config/linter/app_b/src/app_b.app.src similarity index 100% rename from test_projects/standard/app_b/src/app_b.app.src rename to test/test_projects/linter_bad_config/linter/app_b/src/app_b.app.src diff --git a/test_projects/linter_bad_config/linter/app_b/src/app_b.erl b/test/test_projects/linter_bad_config/linter/app_b/src/app_b.erl similarity index 100% rename from test_projects/linter_bad_config/linter/app_b/src/app_b.erl rename to test/test_projects/linter_bad_config/linter/app_b/src/app_b.erl diff --git a/test_projects/linter_bad_config/linter/app_b/src/app_b_unused_param.erl b/test/test_projects/linter_bad_config/linter/app_b/src/app_b_unused_param.erl similarity index 100% rename from test_projects/linter_bad_config/linter/app_b/src/app_b_unused_param.erl rename to test/test_projects/linter_bad_config/linter/app_b/src/app_b_unused_param.erl diff --git a/test_projects/linter_bad_config/linter/rebar.config b/test/test_projects/linter_bad_config/linter/rebar.config similarity index 100% rename from test_projects/linter_bad_config/linter/rebar.config rename to test/test_projects/linter_bad_config/linter/rebar.config diff --git a/test_projects/linter_bad_config/rebar.config b/test/test_projects/linter_bad_config/rebar.config similarity index 100% rename from test_projects/linter_bad_config/rebar.config rename to test/test_projects/linter_bad_config/rebar.config diff --git a/test/test_projects/linter_config/.elp.toml b/test/test_projects/linter_config/.elp.toml new file mode 100644 index 0000000000..c490cc155e --- /dev/null +++ b/test/test_projects/linter_config/.elp.toml @@ -0,0 +1,5 @@ +[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 new file mode 100644 index 0000000000..47886dd507 --- /dev/null +++ b/test/test_projects/linter_config/.elp_lint.toml @@ -0,0 +1,5 @@ +[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 new file mode 100644 index 0000000000..c1101daea2 --- /dev/null +++ b/test/test_projects/linter_config/BUCK @@ -0,0 +1,25 @@ +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 new file mode 100644 index 0000000000..1381435a46 --- /dev/null +++ b/test/test_projects/linter_config/app_a/src/app_a.app.src @@ -0,0 +1,3 @@ +{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 new file mode 100644 index 0000000000..c374c0b518 --- /dev/null +++ b/test/test_projects/linter_config/app_a/src/app_a.erl @@ -0,0 +1,4 @@ +-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 new file mode 100644 index 0000000000..4112b4129f --- /dev/null +++ b/test/test_projects/linter_config/app_b/src/app_b.app.src @@ -0,0 +1,3 @@ +{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 new file mode 100644 index 0000000000..ca7ecf985b --- /dev/null +++ b/test/test_projects/linter_config/app_b/src/app_b.erl @@ -0,0 +1,4 @@ +-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 new file mode 100644 index 0000000000..c278bbce23 --- /dev/null +++ b/test/test_projects/linter_config/app_c/src/app_c.app.src @@ -0,0 +1,3 @@ +{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 new file mode 100644 index 0000000000..57573554b6 --- /dev/null +++ b/test/test_projects/linter_config/app_c/src/app_c.erl @@ -0,0 +1,4 @@ +-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 new file mode 100644 index 0000000000..d508bd24de --- /dev/null +++ b/test/test_projects/linter_config/rebar.config @@ -0,0 +1,9 @@ +{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 new file mode 100644 index 0000000000..1a06a42f0d --- /dev/null +++ b/test/test_projects/parse_error/.elp.toml @@ -0,0 +1,8 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "root//parse_error/..." ] +source_root = "parse_error" + +[eqwalizer] +enable_all = false diff --git a/test_projects/parse_error/.gitignore b/test/test_projects/parse_error/.gitignore similarity index 100% rename from test_projects/parse_error/.gitignore rename to test/test_projects/parse_error/.gitignore diff --git a/test_projects/parse_error/.rebar.root b/test/test_projects/parse_error/.rebar.root similarity index 100% rename from test_projects/parse_error/.rebar.root rename to test/test_projects/parse_error/.rebar.root diff --git a/test/test_projects/parse_error/BUCK b/test/test_projects/parse_error/BUCK new file mode 100644 index 0000000000..ed65c267d0 --- /dev/null +++ b/test/test_projects/parse_error/BUCK @@ -0,0 +1,9 @@ +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_projects/parse_error/eqwalizer/src/eqwalizer.app.src b/test/test_projects/parse_error/eqwalizer/src/eqwalizer.app.src similarity index 100% rename from test_projects/parse_error/eqwalizer/src/eqwalizer.app.src rename to test/test_projects/parse_error/eqwalizer/src/eqwalizer.app.src diff --git a/test_projects/parse_error/eqwalizer/src/eqwalizer.erl b/test/test_projects/parse_error/eqwalizer/src/eqwalizer.erl similarity index 100% rename from test_projects/parse_error/eqwalizer/src/eqwalizer.erl rename to test/test_projects/parse_error/eqwalizer/src/eqwalizer.erl diff --git a/test_projects/parse_error/eqwalizer/src/eqwalizer_specs.erl b/test/test_projects/parse_error/eqwalizer/src/eqwalizer_specs.erl similarity index 100% rename from test_projects/parse_error/eqwalizer/src/eqwalizer_specs.erl rename to test/test_projects/parse_error/eqwalizer/src/eqwalizer_specs.erl diff --git a/test_projects/parse_error/parse_error_a/src/parse_error_a.app.src b/test/test_projects/parse_error/parse_error_a/src/parse_error_a.app.src similarity index 100% rename from test_projects/parse_error/parse_error_a/src/parse_error_a.app.src rename to test/test_projects/parse_error/parse_error_a/src/parse_error_a.app.src diff --git a/test_projects/parse_error/parse_error_a/src/parse_error_a.erl b/test/test_projects/parse_error/parse_error_a/src/parse_error_a.erl similarity index 100% rename from test_projects/parse_error/parse_error_a/src/parse_error_a.erl rename to test/test_projects/parse_error/parse_error_a/src/parse_error_a.erl diff --git a/test_projects/parse_error/parse_error_a/src/parse_error_a_bad.erl b/test/test_projects/parse_error/parse_error_a/src/parse_error_a_bad.erl similarity index 100% rename from test_projects/parse_error/parse_error_a/src/parse_error_a_bad.erl rename to test/test_projects/parse_error/parse_error_a/src/parse_error_a_bad.erl diff --git a/test_projects/parse_error/parse_error_a/src/parse_error_a_reference_bad.erl b/test/test_projects/parse_error/parse_error_a/src/parse_error_a_reference_bad.erl similarity index 100% rename from test_projects/parse_error/parse_error_a/src/parse_error_a_reference_bad.erl rename to test/test_projects/parse_error/parse_error_a/src/parse_error_a_reference_bad.erl diff --git a/test_projects/parse_error/parse_error_a/src/parse_error_a_syntax_error.erl b/test/test_projects/parse_error/parse_error_a/src/parse_error_a_syntax_error.erl similarity index 100% rename from test_projects/parse_error/parse_error_a/src/parse_error_a_syntax_error.erl rename to test/test_projects/parse_error/parse_error_a/src/parse_error_a_syntax_error.erl diff --git a/test_projects/parse_error/parse_error_a/src/parse_error_a_worst.erl b/test/test_projects/parse_error/parse_error_a/src/parse_error_a_worst.erl similarity index 100% rename from test_projects/parse_error/parse_error_a/src/parse_error_a_worst.erl rename to test/test_projects/parse_error/parse_error_a/src/parse_error_a_worst.erl diff --git a/test_projects/parse_error/rebar.config b/test/test_projects/parse_error/rebar.config similarity index 100% rename from test_projects/parse_error/rebar.config rename to test/test_projects/parse_error/rebar.config diff --git a/test/test_projects/standard/.elp.toml b/test/test_projects/standard/.elp.toml new file mode 100644 index 0000000000..f5e2ac1943 --- /dev/null +++ b/test/test_projects/standard/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "root//standard/..." ] +source_root = "standard" diff --git a/test_projects/standard/.gitignore b/test/test_projects/standard/.gitignore similarity index 100% rename from test_projects/standard/.gitignore rename to test/test_projects/standard/.gitignore diff --git a/test_projects/standard/.rebar.root b/test/test_projects/standard/.rebar.root similarity index 100% rename from test_projects/standard/.rebar.root rename to test/test_projects/standard/.rebar.root diff --git a/test/test_projects/standard/BUCK b/test/test_projects/standard/BUCK new file mode 100644 index 0000000000..3f1e9ee947 --- /dev/null +++ b/test/test_projects/standard/BUCK @@ -0,0 +1,49 @@ +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/.eqwalizer b/test/test_projects/standard/app_a/.eqwalizer new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test_projects/standard/app_a/extra/app_a.erl b/test/test_projects/standard/app_a/extra/app_a.erl similarity index 100% rename from test_projects/standard/app_a/extra/app_a.erl rename to test/test_projects/standard/app_a/extra/app_a.erl diff --git a/test_projects/standard/app_a/include/app_a.hrl b/test/test_projects/standard/app_a/include/app_a.hrl similarity index 100% rename from test_projects/standard/app_a/include/app_a.hrl rename to test/test_projects/standard/app_a/include/app_a.hrl 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 new file mode 100644 index 0000000000..1381435a46 --- /dev/null +++ b/test/test_projects/standard/app_a/src/app_a.app.src @@ -0,0 +1,3 @@ +{application, app_a, + [{description, "example app A"}, {vsn, "inplace"}, {applications, [kernel, stdlib]}] +}. diff --git a/test_projects/standard/app_a/src/app_a.erl b/test/test_projects/standard/app_a/src/app_a.erl similarity index 100% rename from test_projects/standard/app_a/src/app_a.erl rename to test/test_projects/standard/app_a/src/app_a.erl diff --git a/test_projects/standard/app_a/src/app_a_errors_generated.erl b/test/test_projects/standard/app_a/src/app_a_errors_generated.erl similarity index 100% rename from test_projects/standard/app_a/src/app_a_errors_generated.erl rename to test/test_projects/standard/app_a/src/app_a_errors_generated.erl diff --git a/test_projects/standard/app_a/src/app_a_fixme.erl b/test/test_projects/standard/app_a/src/app_a_fixme.erl similarity index 100% rename from test_projects/standard/app_a/src/app_a_fixme.erl rename to test/test_projects/standard/app_a/src/app_a_fixme.erl diff --git a/test_projects/standard/app_a/src/app_a_ignored.erl b/test/test_projects/standard/app_a/src/app_a_ignored.erl similarity index 100% rename from test_projects/standard/app_a/src/app_a_ignored.erl rename to test/test_projects/standard/app_a/src/app_a_ignored.erl diff --git a/test_projects/standard/app_a/src/app_a_lists.erl b/test/test_projects/standard/app_a/src/app_a_lists.erl similarity index 100% rename from test_projects/standard/app_a/src/app_a_lists.erl rename to test/test_projects/standard/app_a/src/app_a_lists.erl diff --git a/test_projects/standard/app_a/src/app_a_mod2.erl b/test/test_projects/standard/app_a/src/app_a_mod2.erl similarity index 100% rename from test_projects/standard/app_a/src/app_a_mod2.erl rename to test/test_projects/standard/app_a/src/app_a_mod2.erl diff --git a/test_projects/standard/app_a/src/app_a_no_errors.erl b/test/test_projects/standard/app_a/src/app_a_no_errors.erl similarity index 100% rename from test_projects/standard/app_a/src/app_a_no_errors.erl rename to test/test_projects/standard/app_a/src/app_a_no_errors.erl diff --git a/test_projects/standard/app_a/src/app_a_no_errors_generated.erl b/test/test_projects/standard/app_a/src/app_a_no_errors_generated.erl similarity index 100% rename from test_projects/standard/app_a/src/app_a_no_errors_generated.erl rename to test/test_projects/standard/app_a/src/app_a_no_errors_generated.erl diff --git a/test_projects/standard/app_a/src/app_a_no_errors_opted_in.erl b/test/test_projects/standard/app_a/src/app_a_no_errors_opted_in.erl similarity index 100% rename from test_projects/standard/app_a/src/app_a_no_errors_opted_in.erl rename to test/test_projects/standard/app_a/src/app_a_no_errors_opted_in.erl diff --git a/test_projects/standard/app_a/test/app_a_SUITE.erl b/test/test_projects/standard/app_a/test/app_a_SUITE.erl similarity index 100% rename from test_projects/standard/app_a/test/app_a_SUITE.erl rename to test/test_projects/standard/app_a/test/app_a_SUITE.erl diff --git a/test_projects/standard/app_a/test/app_a_test_helpers.erl b/test/test_projects/standard/app_a/test/app_a_test_helpers.erl similarity index 100% rename from test_projects/standard/app_a/test/app_a_test_helpers.erl rename to test/test_projects/standard/app_a/test/app_a_test_helpers.erl diff --git a/test_projects/standard/app_a/test/app_a_test_helpers_not_opted_in.erl b/test/test_projects/standard/app_a/test/app_a_test_helpers_not_opted_in.erl similarity index 100% rename from test_projects/standard/app_a/test/app_a_test_helpers_not_opted_in.erl rename to test/test_projects/standard/app_a/test/app_a_test_helpers_not_opted_in.erl diff --git a/test_projects/standard/app_a/test/app_test_helpers_no_errors.erl b/test/test_projects/standard/app_a/test/app_test_helpers_no_errors.erl similarity index 100% rename from test_projects/standard/app_a/test/app_test_helpers_no_errors.erl rename to test/test_projects/standard/app_a/test/app_test_helpers_no_errors.erl 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 new file mode 100644 index 0000000000..4112b4129f --- /dev/null +++ b/test/test_projects/standard/app_b/src/app_b.app.src @@ -0,0 +1,3 @@ +{application, app_b, + [{description, "example app B"}, {vsn, "inplace"}, {applications, [kernel, stdlib]}] +}. diff --git a/test_projects/standard/app_b/src/app_b.erl b/test/test_projects/standard/app_b/src/app_b.erl similarity index 100% rename from test_projects/standard/app_b/src/app_b.erl rename to test/test_projects/standard/app_b/src/app_b.erl diff --git a/test_projects/standard/eqwalizer/src/eqwalizer.app.src b/test/test_projects/standard/eqwalizer/src/eqwalizer.app.src similarity index 100% rename from test_projects/standard/eqwalizer/src/eqwalizer.app.src rename to test/test_projects/standard/eqwalizer/src/eqwalizer.app.src diff --git a/test_projects/standard/eqwalizer/src/eqwalizer.erl b/test/test_projects/standard/eqwalizer/src/eqwalizer.erl similarity index 100% rename from test_projects/standard/eqwalizer/src/eqwalizer.erl rename to test/test_projects/standard/eqwalizer/src/eqwalizer.erl diff --git a/test_projects/standard/eqwalizer/src/eqwalizer_specs.erl b/test/test_projects/standard/eqwalizer/src/eqwalizer_specs.erl similarity index 100% rename from test_projects/standard/eqwalizer/src/eqwalizer_specs.erl rename to test/test_projects/standard/eqwalizer/src/eqwalizer_specs.erl diff --git a/test_projects/standard/erlang_ls.config b/test/test_projects/standard/erlang_ls.config similarity index 100% rename from test_projects/standard/erlang_ls.config rename to test/test_projects/standard/erlang_ls.config diff --git a/test_projects/standard/rebar.config b/test/test_projects/standard/rebar.config similarity index 100% rename from test_projects/standard/rebar.config rename to test/test_projects/standard/rebar.config diff --git a/test/test_projects/toolchains/BUCK b/test/test_projects/toolchains/BUCK new file mode 100644 index 0000000000..770ac61f67 --- /dev/null +++ b/test/test_projects/toolchains/BUCK @@ -0,0 +1,5 @@ +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 new file mode 100644 index 0000000000..87c2f17334 --- /dev/null +++ b/test/test_projects/xref/.elp.toml @@ -0,0 +1,5 @@ +[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 new file mode 100644 index 0000000000..bf44968f02 --- /dev/null +++ b/test/test_projects/xref/BUCK @@ -0,0 +1,25 @@ +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 new file mode 100644 index 0000000000..ddf4fc00d2 --- /dev/null +++ b/test/test_projects/xref/app_a/src/unavailable_type.erl @@ -0,0 +1,12 @@ +-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 new file mode 100644 index 0000000000..d56609b179 --- /dev/null +++ b/test/test_projects/xref/app_b/src/app_b.erl @@ -0,0 +1,8 @@ +-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 new file mode 100644 index 0000000000..040f77f26f --- /dev/null +++ b/test/test_projects/xref/app_c/src/app_c.erl @@ -0,0 +1,8 @@ +-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 new file mode 100644 index 0000000000..629a5228bf --- /dev/null +++ b/test/test_projects/xref/elp_lint_unavailable_type.toml @@ -0,0 +1,2 @@ +[linters.unavailable_type] +enabled = true diff --git a/test_projects/buck_bad_config/.elp.toml b/test_projects/buck_bad_config/.elp.toml deleted file mode 100644 index a891a3dfc5..0000000000 --- a/test_projects/buck_bad_config/.elp.toml +++ /dev/null @@ -1,8 +0,0 @@ -[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_projects/buck_tests/.elp.toml b/test_projects/buck_tests/.elp.toml deleted file mode 100644 index acb0799975..0000000000 --- a/test_projects/buck_tests/.elp.toml +++ /dev/null @@ -1,9 +0,0 @@ -[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_projects/buck_tests_2/.elp.toml b/test_projects/buck_tests_2/.elp.toml deleted file mode 100644 index 4ea681809f..0000000000 --- a/test_projects/buck_tests_2/.elp.toml +++ /dev/null @@ -1,9 +0,0 @@ -[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_projects/diagnostics/.elp.toml b/test_projects/diagnostics/.elp.toml deleted file mode 100644 index e5ee70c992..0000000000 --- a/test_projects/diagnostics/.elp.toml +++ /dev/null @@ -1,8 +0,0 @@ -[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_projects/eqwalizer_callers/.elp.toml b/test_projects/eqwalizer_callers/.elp.toml deleted file mode 100644 index f4b7f6f6ac..0000000000 --- a/test_projects/eqwalizer_callers/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[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_projects/eqwalizer_tests/.elp.toml b/test_projects/eqwalizer_tests/.elp.toml deleted file mode 100644 index ed5c60502f..0000000000 --- a/test_projects/eqwalizer_tests/.elp.toml +++ /dev/null @@ -1,8 +0,0 @@ -[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_projects/in_place_tests/.elp.toml b/test_projects/in_place_tests/.elp.toml deleted file mode 100644 index b6c251f03c..0000000000 --- a/test_projects/in_place_tests/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[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_projects/include_lib_dependency_test/.elp.toml b/test_projects/include_lib_dependency_test/.elp.toml deleted file mode 100644 index 65e106a9e2..0000000000 --- a/test_projects/include_lib_dependency_test/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[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_projects/linter/.elp.toml b/test_projects/linter/.elp.toml deleted file mode 100644 index a887ab835c..0000000000 --- a/test_projects/linter/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[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_projects/linter_bad_config/.elp.toml b/test_projects/linter_bad_config/.elp.toml deleted file mode 100644 index a887ab835c..0000000000 --- a/test_projects/linter_bad_config/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[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_projects/linter_bad_config/linter/.elp.toml b/test_projects/linter_bad_config/linter/.elp.toml deleted file mode 100644 index a887ab835c..0000000000 --- a/test_projects/linter_bad_config/linter/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[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_projects/parse_error/.elp.toml b/test_projects/parse_error/.elp.toml deleted file mode 100644 index bf2c1ad580..0000000000 --- a/test_projects/parse_error/.elp.toml +++ /dev/null @@ -1,8 +0,0 @@ -[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_projects/standard/.elp.toml b/test_projects/standard/.elp.toml deleted file mode 100644 index 09ff5a4d5a..0000000000 --- a/test_projects/standard/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "fbcode//whatsapp/elp/test_projects/standard/..." ] -source_root = "whatsapp/elp/test_projects/standard" diff --git a/website/docs/erlang-error-index/w/W0045.md b/website/docs/erlang-error-index/w/W0045.md index 13c908d8a0..c68f83ef4d 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: Duplicate module name + %% ^^^^^^^^^ warning: A module with this name exists elsewhere ``` ## Explanation diff --git a/website/docs/erlang-error-index/w/W0048.md b/website/docs/erlang-error-index/w/W0048.md index 42d21cec9c..a6e1631148 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 -dialyzer attribute. +%% ^^^^^^^^^ 💡 warning: Avoid using the -dialyzer attribute. ``` ## Explanation diff --git a/website/docs/erlang-error-index/w/W0050.md b/website/docs/erlang-error-index/w/W0050.md index a0d43d7171..8c8210dcca 100644 --- a/website/docs/erlang-error-index/w/W0050.md +++ b/website/docs/erlang-error-index/w/W0050.md @@ -20,40 +20,26 @@ size(Input) -> ## Explanation -The [`size/1`](https://www.erlang.org/doc/apps/erts/erlang#size/1) BIF returns -the size for both tuples and binaries. +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 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). +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). -When one knows that the value being tested must be a tuple, `tuple_size/1` -should always be preferred. +What to do instead: -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 tuples, use `tuple_size/1`. -For the above use case, a better approach would be: +- 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_: ```erlang --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). +4 = byte_size(<<0:25>>). +3 = size(<<0:25>>). ``` 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 new file mode 100644 index 0000000000..14848f5898 --- /dev/null +++ b/website/docs/erlang-error-index/w/W0056.md @@ -0,0 +1,45 @@ +--- +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 new file mode 100644 index 0000000000..990c4648b6 --- /dev/null +++ b/website/docs/erlang-error-index/w/W0057.md @@ -0,0 +1,106 @@ +--- +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 new file mode 100644 index 0000000000..acad4c2d79 --- /dev/null +++ b/website/docs/erlang-error-index/w/W0058.md @@ -0,0 +1,108 @@ +--- +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 new file mode 100644 index 0000000000..fd2e990cb3 --- /dev/null +++ b/website/docs/erlang-error-index/w/W0059.md @@ -0,0 +1,37 @@ +--- +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 new file mode 100644 index 0000000000..91b972dacf --- /dev/null +++ b/website/docs/erlang-error-index/w/W0060.md @@ -0,0 +1,48 @@ +--- +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 557027a138..90a9eb5f1e 100644 --- a/website/docs/get-started/configure-project/elp-toml.md +++ b/website/docs/get-started/configure-project/elp-toml.md @@ -32,6 +32,9 @@ enabled = false [rebar] profile = "test" + +[otp] +exclude_apps = ["megaco", "eunit"] ``` ## Configuration Sections @@ -108,9 +111,21 @@ 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 | -| ------- | ------- | -------------------------------- | -| enabled | Boolean | Discover the project using 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"] +``` :::warning @@ -126,3 +141,22 @@ Configure ELP for [rebar3](https://rebar3.org/)-based projects. | Key | Type | Description | Default | | ------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------ | ------- | | profile | String | The `rebar3` profile to use for project discovery. Only used if the `file` property is specified in the [build_info](#build-info) section. | test | + +### \[otp\] {#otp} + +Configure ELP's interaction with OTP (Open Telecom Platform) applications. + +| Key | Type | Description | Default | +| ------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------ | ------- | +| exclude_apps | Array of Strings | List of OTP application names to exclude from indexing. This can help improve performance by not loading rarely used OTP apps. | [] | + +The `exclude_apps` setting allows you to specify OTP applications that should not be indexed by ELP. This can be useful for: + +- Improving performance by excluding rarely used OTP applications like `megaco` +- Reducing memory usage when working on projects that don't need certain OTP libraries + +Example usage: +```toml +[otp] +exclude_apps = ["diameter", "megaco"] +``` diff --git a/website/docs/get-started/editors/emacs.md b/website/docs/get-started/editors/emacs.md index 5b19fd09f2..fab357f4a4 100644 --- a/website/docs/get-started/editors/emacs.md +++ b/website/docs/get-started/editors/emacs.md @@ -4,15 +4,107 @@ 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 [lsp-mode](https://emacs-lsp.github.io/lsp-mode/) LSP client. +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. -## Requirements +## Eglot -### `lsp-mode` +Eglot is part of Emacs core since Emacs 29. For earlier versions it can be +installed with the `eglot` package. -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 -## Configure Emacs +```elisp +(use-package eglot + :ensure t + :hook ((erlang-mode . eglot-ensure)) + + :config + ;; Remove default LSP server + (setopt eglot-server-programs + (assq-delete-all 'erlang-mode eglot-server-programs)) + + ;; Enable ELP + (add-to-list 'eglot-server-programs + '(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))))) +``` + +## 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. + +### Configuration Add the following to your emacs `.emacs` file or equivalent. @@ -32,13 +124,21 @@ 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/). +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. ## 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 84f903cd64..74cc3b9159 100644 --- a/website/docs/get-started/install.md +++ b/website/docs/get-started/install.md @@ -4,9 +4,26 @@ sidebar_position: 2 # Install ELP -The easiest way to install to ELP is [from binary](#from-binary). It is also +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 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 @@ -51,18 +68,14 @@ correctly installed. ## From Source -### Prerequisites - -To be able to compile ELP from source, you need a copy of the -[eqWAlizer](https://github.com/WhatsApp/eqwalizer) typechecker for Erlang. - -Clone the eqWAlizer repository: +Clone the ELP repository, including submodules: ``` -git clone https://github.com/WhatsApp/eqwalizer.git +git clone --recurse-submodules https://github.com/WhatsApp/erlang-language-platform.git +cd erlang-language-platform ``` -Enter the `eqwalizer` repository and build it. Notice the double `eqwalizer` in +Enter the `eqwalizer` submodule and build it. Notice the double `eqwalizer` in the `pushd` command. ``` @@ -71,43 +84,38 @@ sbt assembly popd ``` -Get the path of the produced `eqwalizer.jar` file: +Point the `ELP_EQWALIZER_PATH` environment variable to the path of the produced +`eqwalizer.jar` file: ``` -find . -name eqwalizer.jar | readlink -f +export ELP_EQWALIZER_PATH=$(find "$(pwd)" -name eqwalizer.jar) ``` -Point the `ELP_EQWALIZER_PATH` environment variable to the path returned above: +Point the `EQWALIZER_DIR` environment variable to the path of the +`eqwalizer_support` directory: ``` -export ELP_EQWALIZER_PATH=/path/to/eqwalizer.jar +export EQWALIZER_DIR=$(find "$(pwd)" -name eqwalizer_support) ``` -Note: The ELP build assumes that you clone the eqwalizer and ELP -repositories from the same starting directory, so they are -"siblings". This is because there is a cross-reference within ELP to -`../eqwalizer/eqwalizer_support`. If you are unable to do this, set +Now we can compile ELP: + +:::tip + +The commands below will produce a release build, which has the best runtime +performance, at the price of a slower compilation time. If you are developing +ELP, consider using `cargo build --profile release-thin`, as it provides a much +faster development loop while still producing a performant binary. You will find +the corresponding binary in `target/release-thin/elp`. + +::: ``` -export EQWALIZER_DIR=
/eqwalizer_support -``` - -### Compile ELP - -Clone the ELP repository: - -``` -git clone https://github.com/WhatsApp/erlang-language-platform.git -``` - -Enter the ELP repo and compile it: - -``` -cd erlang-language-platform cargo build --release ``` -The produced executable will be available in: `target/release/elp`, so ensure it is included in your `PATH`. E.g.: +The produced executable will be available in: `target/release/elp`, so ensure it +is included in your `PATH`. E.g.: ``` mkdir -p ~/bin diff --git a/website/package.json b/website/package.json index 4053a7477f..49a34973ca 100644 --- a/website/package.json +++ b/website/package.json @@ -16,12 +16,12 @@ "write-heading-ids": "docusaurus write-heading-ids" }, "dependencies": { - "@docusaurus/core": "3.6.3", - "@docusaurus/preset-classic": "3.6.3", + "@docusaurus/core": "3.9.2", + "@docusaurus/preset-classic": "3.9.2", "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", - "prism-react-renderer": "^2.3.0", "docusaurus-plugin-internaldocs-fb": "^1.18.4", + "prism-react-renderer": "^2.3.0", "react": "^18.0.0", "react-dom": "^18.0.0" }, @@ -62,6 +62,11 @@ "brace-expansion": ">=1.1.12", "webpack-dev-server": ">=5.2.1", "on-headers": ">=1.1.0", - "mermaid": ">=11.10.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" } } diff --git a/website/yarn.lock b/website/yarn.lock index c07cd453c7..1ac9f2033a 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -2,274 +2,191 @@ # yarn lockfile v1 -"@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== +"@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== dependencies: - "@algolia/autocomplete-plugin-algolia-insights" "1.17.7" - "@algolia/autocomplete-shared" "1.17.7" + "@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": - 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== +"@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== dependencies: - "@algolia/autocomplete-shared" "1.17.7" + "@ai-sdk/provider" "2.0.0" + "@standard-schema/spec" "^1.0.0" + eventsource-parser "^3.0.6" -"@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== +"@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== dependencies: - "@algolia/autocomplete-shared" "1.17.7" + json-schema "^0.4.0" -"@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== +"@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== dependencies: - "@algolia/cache-common" "4.24.0" + "@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": - 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== +"@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== dependencies: - "@algolia/cache-common" "4.24.0" + "@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-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== +"@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== 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/autocomplete-plugin-algolia-insights" "1.19.2" + "@algolia/autocomplete-shared" "1.19.2" -"@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== +"@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== dependencies: - "@algolia/client-common" "4.24.0" - "@algolia/client-search" "4.24.0" - "@algolia/transporter" "4.24.0" + "@algolia/autocomplete-shared" "1.19.2" -"@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== +"@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== dependencies: - "@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-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-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== +"@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== 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-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": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.24.0.tgz#77c46eee42b9444a1d1c1583a83f7df4398a649d" - integrity sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA== +"@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== dependencies: - "@algolia/requester-common" "4.24.0" - "@algolia/transporter" "4.24.0" + "@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-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== +"@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.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" + "@algolia/requester-browser-xhr" "5.44.0" + "@algolia/requester-fetch" "5.44.0" + "@algolia/requester-node-http" "5.44.0" -"@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== +"@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== dependencies: - "@algolia/client-common" "4.24.0" - "@algolia/requester-common" "4.24.0" - "@algolia/transporter" "4.24.0" + "@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-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== +"@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== 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/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/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.15.0": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@algolia/ingestion/-/ingestion-1.15.0.tgz#a3f3ec2139042f8597c2a975430a6f77cd764db3" - integrity sha512-MkqkAxBQxtQ5if/EX2IPqFA7LothghVyvPoRNA/meS2AW2qkHwcxjuiBxv4H6mnAVEPfJlhu9rkdVz9LgCBgJg== +"@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== 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-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/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== +"@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/logger-common" "4.24.0" + "@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/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== +"@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== 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-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/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== +"@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== dependencies: - "@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/client-common" "5.44.0" -"@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== +"@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== 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-common" "5.44.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== +"@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== 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" + "@algolia/client-common" "5.44.0" "@ampproject/remapping@^2.2.0": version "2.3.0" @@ -292,7 +209,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.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": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2": version "7.26.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== @@ -1246,92 +1163,136 @@ 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.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/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/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/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/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-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-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== +"@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== dependencies: - "@csstools/color-helpers" "^5.0.1" - "@csstools/css-calc" "^2.1.0" + "@csstools/color-helpers" "^5.1.0" + "@csstools/css-calc" "^2.1.4" -"@csstools/css-parser-algorithms@^3.0.4": +"@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": version "3.0.4" - resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz#74426e93bd1c4dcab3e441f5cc7ba4fb35d94356" - integrity sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A== + resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz#333fedabc3fd1a8e5d0100013731cf19e6a8c5d3" + integrity sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw== -"@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/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/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-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/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== +"@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== dependencies: "@csstools/selector-specificity" "^5.0.0" postcss-selector-parser "^7.0.0" -"@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== +"@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== dependencies: - "@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/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-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== +"@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== dependencies: - "@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/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.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== +"@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== dependencies: - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@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.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== +"@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== dependencies: - "@csstools/css-calc" "^2.1.0" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" + "@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/postcss-font-format-keywords@^4.0.0": version "4.0.0" @@ -1341,67 +1302,67 @@ "@csstools/utilities" "^2.0.0" postcss-value-parser "^4.2.0" -"@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== +"@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== dependencies: - "@csstools/css-color-parser" "^3.0.6" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" + "@csstools/css-color-parser" "^3.1.0" + "@csstools/css-parser-algorithms" "^3.0.5" + "@csstools/css-tokenizer" "^3.0.4" -"@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== +"@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== dependencies: - "@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/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-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== +"@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== dependencies: - "@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/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-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== +"@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== dependencies: - "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/postcss-progressive-custom-properties" "^4.2.1" "@csstools/utilities" "^2.0.0" postcss-value-parser "^4.2.0" -"@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-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-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== +"@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== dependencies: "@csstools/selector-specificity" "^5.0.0" postcss-selector-parser "^7.0.0" -"@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== +"@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== dependencies: - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/postcss-progressive-custom-properties" "^4.0.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-logical-float-and-clear@^3.0.0": @@ -1426,32 +1387,32 @@ dependencies: postcss-value-parser "^4.2.0" -"@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== +"@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== dependencies: - "@csstools/css-tokenizer" "^3.0.3" + "@csstools/css-tokenizer" "^3.0.4" "@csstools/utilities" "^2.0.0" -"@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== +"@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== dependencies: - "@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/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/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== +"@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== dependencies: - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/media-query-list-parser" "^4.0.2" + "@csstools/css-parser-algorithms" "^3.0.5" + "@csstools/css-tokenizer" "^3.0.4" + "@csstools/media-query-list-parser" "^4.0.3" "@csstools/postcss-nested-calc@^4.0.0": version "4.0.0" @@ -1468,42 +1429,42 @@ dependencies: postcss-value-parser "^4.2.0" -"@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== +"@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== dependencies: - "@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/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-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== +"@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== dependencies: postcss-value-parser "^4.2.0" -"@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== +"@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== dependencies: - "@csstools/css-calc" "^2.1.0" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" + "@csstools/css-calc" "^2.1.4" + "@csstools/css-parser-algorithms" "^3.0.5" + "@csstools/css-tokenizer" "^3.0.4" -"@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== +"@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== dependencies: - "@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/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-scope-pseudo-class@^4.0.1": @@ -1513,50 +1474,50 @@ dependencies: postcss-selector-parser "^7.0.0" -"@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== +"@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== dependencies: - "@csstools/css-calc" "^2.1.0" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" + "@csstools/css-calc" "^2.1.4" + "@csstools/css-parser-algorithms" "^3.0.5" + "@csstools/css-tokenizer" "^3.0.4" -"@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== +"@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== dependencies: - "@csstools/css-calc" "^2.1.0" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" + "@csstools/css-calc" "^2.1.4" + "@csstools/css-parser-algorithms" "^3.0.5" + "@csstools/css-tokenizer" "^3.0.4" -"@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== +"@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== dependencies: - "@csstools/color-helpers" "^5.0.1" + "@csstools/color-helpers" "^5.1.0" postcss-value-parser "^4.2.0" -"@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== +"@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== dependencies: - "@csstools/css-calc" "^2.1.0" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" + "@csstools/css-calc" "^2.1.4" + "@csstools/css-parser-algorithms" "^3.0.5" + "@csstools/css-tokenizer" "^3.0.4" "@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.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-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-specificity@^5.0.0": version "5.0.0" @@ -1573,25 +1534,34 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@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/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/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== +"@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== dependencies: - "@algolia/autocomplete-core" "1.17.7" - "@algolia/autocomplete-preset-algolia" "1.17.7" - "@docsearch/css" "3.8.0" - algoliasearch "^5.12.0" + "@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" -"@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== +"@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== dependencies: "@babel/core" "^7.25.9" "@babel/generator" "^7.25.9" @@ -1603,55 +1573,54 @@ "@babel/runtime" "^7.25.9" "@babel/runtime-corejs3" "^7.25.9" "@babel/traverse" "^7.25.9" - "@docusaurus/logger" "3.6.3" - "@docusaurus/utils" "3.6.3" + "@docusaurus/logger" "3.9.2" + "@docusaurus/utils" "3.9.2" babel-plugin-dynamic-import-node "^2.3.3" fs-extra "^11.1.1" tslib "^2.6.0" -"@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== +"@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== dependencies: "@babel/core" "^7.25.9" - "@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" + "@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" babel-loader "^9.2.1" - clean-css "^5.3.2" + clean-css "^5.3.3" copy-webpack-plugin "^11.0.0" - css-loader "^6.8.1" + css-loader "^6.11.0" 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.1" + mini-css-extract-plugin "^2.9.2" null-loader "^4.0.1" - postcss "^8.4.26" - postcss-loader "^7.3.3" - postcss-preset-env "^10.1.0" - react-dev-utils "^12.0.1" + postcss "^8.5.4" + postcss-loader "^7.3.4" + postcss-preset-env "^10.2.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.6.3": - version "3.6.3" - resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-3.6.3.tgz#6bf968ee26a36d71387bab293f27ccffc0e428b6" - integrity sha512-xL7FRY9Jr5DWqB6pEnqgKqcMPJOX5V0pgWXi5lCiih11sUBmcFKM7c3+GyxcVeeWFxyYSDP3grLTWqJoP4P9Vw== +"@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== dependencies: - "@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" + "@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" boxen "^6.2.1" chalk "^4.1.2" chokidar "^3.5.3" @@ -1659,69 +1628,68 @@ 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-dev-utils "^12.0.1" - react-helmet-async "^1.3.0" + react-helmet-async "npm:@slorber/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" - shelljs "^0.8.5" + tinypool "^1.0.2" tslib "^2.6.0" update-notifier "^6.0.2" webpack "^5.95.0" webpack-bundle-analyzer "^4.10.2" - webpack-dev-server "^4.15.2" + webpack-dev-server "^5.2.2" webpack-merge "^6.0.1" -"@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== +"@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== dependencies: cssnano-preset-advanced "^6.1.2" - postcss "^8.4.38" + postcss "^8.5.4" postcss-sort-media-queries "^5.2.0" tslib "^2.6.0" -"@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== +"@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== dependencies: chalk "^4.1.2" tslib "^2.6.0" -"@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== +"@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== dependencies: - "@docusaurus/logger" "3.6.3" - "@docusaurus/utils" "3.6.3" - "@docusaurus/utils-validation" "3.6.3" + "@docusaurus/logger" "3.9.2" + "@docusaurus/utils" "3.9.2" + "@docusaurus/utils-validation" "3.9.2" "@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 "^1.0.2" + image-size "^2.0.2" mdast-util-mdx "^3.0.0" mdast-util-to-string "^4.0.0" rehype-raw "^7.0.0" @@ -1737,182 +1705,209 @@ vfile "^6.0.1" webpack "^5.88.1" -"@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== +"@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== dependencies: - "@docusaurus/types" "3.6.3" + "@docusaurus/types" "3.9.2" "@types/history" "^4.7.11" "@types/react" "*" "@types/react-router-config" "*" "@types/react-router-dom" "*" - react-helmet-async "*" + react-helmet-async "npm:@slorber/react-helmet-async@1.3.0" react-loadable "npm:@docusaurus/react-loadable@6.0.0" -"@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== +"@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== dependencies: - "@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" + "@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" cheerio "1.0.0-rc.12" feed "^4.2.2" fs-extra "^11.1.1" lodash "^4.17.21" - reading-time "^1.5.0" + schema-dts "^1.1.2" 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.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== +"@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== dependencies: - "@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" + "@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" "@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.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== +"@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== dependencies: - "@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" + "@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" fs-extra "^11.1.1" tslib "^2.6.0" webpack "^5.88.1" -"@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== +"@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== dependencies: - "@docusaurus/core" "3.6.3" - "@docusaurus/types" "3.6.3" - "@docusaurus/utils" "3.6.3" + "@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" fs-extra "^11.1.1" - react-json-view-lite "^1.2.0" + react-json-view-lite "^2.3.0" tslib "^2.6.0" -"@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== +"@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== dependencies: - "@docusaurus/core" "3.6.3" - "@docusaurus/types" "3.6.3" - "@docusaurus/utils-validation" "3.6.3" + "@docusaurus/core" "3.9.2" + "@docusaurus/types" "3.9.2" + "@docusaurus/utils-validation" "3.9.2" tslib "^2.6.0" -"@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== +"@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== dependencies: - "@docusaurus/core" "3.6.3" - "@docusaurus/types" "3.6.3" - "@docusaurus/utils-validation" "3.6.3" + "@docusaurus/core" "3.9.2" + "@docusaurus/types" "3.9.2" + "@docusaurus/utils-validation" "3.9.2" "@types/gtag.js" "^0.0.12" tslib "^2.6.0" -"@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== +"@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== dependencies: - "@docusaurus/core" "3.6.3" - "@docusaurus/types" "3.6.3" - "@docusaurus/utils-validation" "3.6.3" + "@docusaurus/core" "3.9.2" + "@docusaurus/types" "3.9.2" + "@docusaurus/utils-validation" "3.9.2" tslib "^2.6.0" -"@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== +"@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== dependencies: - "@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" + "@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" fs-extra "^11.1.1" sitemap "^7.1.1" tslib "^2.6.0" -"@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== +"@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== dependencies: - "@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/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/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== +"@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== dependencies: - "@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" + "@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" "@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.4.26" + postcss "^8.5.4" prism-react-renderer "^2.3.0" prismjs "^1.29.0" react-router-dom "^5.3.4" @@ -1920,15 +1915,15 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@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== +"@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== dependencies: - "@docusaurus/mdx-loader" "3.6.3" - "@docusaurus/module-type-aliases" "3.6.3" - "@docusaurus/utils" "3.6.3" - "@docusaurus/utils-common" "3.6.3" + "@docusaurus/mdx-loader" "3.9.2" + "@docusaurus/module-type-aliases" "3.9.2" + "@docusaurus/utils" "3.9.2" + "@docusaurus/utils-common" "3.9.2" "@types/history" "^4.7.11" "@types/react" "*" "@types/react-router-config" "*" @@ -1938,21 +1933,21 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@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== +"@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== dependencies: - "@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" + "@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" clsx "^2.0.0" eta "^2.2.0" fs-extra "^11.1.1" @@ -1960,61 +1955,62 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@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== +"@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== dependencies: fs-extra "^11.1.1" tslib "^2.6.0" -"@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== +"@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== 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 "^1.3.0" + react-helmet-async "npm:@slorber/react-helmet-async@1.3.0" utility-types "^3.10.0" webpack "^5.95.0" webpack-merge "^5.9.0" -"@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== +"@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== dependencies: - "@docusaurus/types" "3.6.3" + "@docusaurus/types" "3.9.2" tslib "^2.6.0" -"@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== +"@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== dependencies: - "@docusaurus/logger" "3.6.3" - "@docusaurus/utils" "3.6.3" - "@docusaurus/utils-common" "3.6.3" + "@docusaurus/logger" "3.9.2" + "@docusaurus/utils" "3.9.2" + "@docusaurus/utils-common" "3.9.2" 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.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== +"@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== dependencies: - "@docusaurus/logger" "3.6.3" - "@docusaurus/types" "3.6.3" - "@docusaurus/utils-common" "3.6.3" - "@svgr/webpack" "^8.1.0" + "@docusaurus/logger" "3.9.2" + "@docusaurus/types" "3.9.2" + "@docusaurus/utils-common" "3.9.2" 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" @@ -2024,9 +2020,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" @@ -2063,6 +2059,18 @@ 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" @@ -2240,6 +2248,11 @@ "@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" @@ -2312,6 +2325,11 @@ 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" @@ -2835,7 +2853,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@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": +"@types/json-schema@*", "@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== @@ -2921,11 +2939,6 @@ 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" @@ -3092,6 +3105,11 @@ 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" @@ -3233,7 +3251,15 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -accepts@~1.3.4, accepts@~1.3.8: +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: 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== @@ -3258,7 +3284,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.1.2: +address@^1.0.1: version "1.2.2" resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e" integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== @@ -3271,6 +3297,16 @@ 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" @@ -3278,7 +3314,7 @@ ajv-formats@^2.1.1: dependencies: ajv "^8.0.0" -ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: +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== @@ -3290,7 +3326,7 @@ ajv-keywords@^5.1.0: dependencies: fast-deep-equal "^3.1.3" -ajv@^6.12.2, ajv@^6.12.5: +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== @@ -3310,52 +3346,32 @@ ajv@^8.0.0, ajv@^8.9.0: json-schema-traverse "^1.0.0" require-from-string "^2.0.2" -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== +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== dependencies: "@algolia/events" "^4.0.1" -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== +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== dependencies: - "@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" + "@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" ansi-align@^3.0.1: version "3.0.1" @@ -3433,11 +3449,6 @@ 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" @@ -3459,11 +3470,6 @@ 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" @@ -3483,6 +3489,18 @@ 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" @@ -3549,6 +3567,11 @@ 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" @@ -3569,23 +3592,20 @@ 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@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== +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== dependencies: - 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" + 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" bonjour-service@^1.2.1: version "1.3.0" @@ -3628,7 +3648,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@^2.0.1: +brace-expansion@>=1.1.12, brace-expansion@^1.1.7: version "4.0.1" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-4.0.1.tgz#3387e13eaa2992025d05ea47308f77e4a8dedd1e" integrity sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA== @@ -3642,7 +3662,7 @@ braces@^3.0.3, braces@~3.0.2: dependencies: fill-range "^7.1.1" -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: +browserslist@^4.0.0, browserslist@^4.23.0, 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== @@ -3652,6 +3672,17 @@ browserslist@^4.0.0, browserslist@^4.18.1, browserslist@^4.23.0, 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" @@ -3677,7 +3708,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== @@ -3708,6 +3739,14 @@ 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" @@ -3718,6 +3757,14 @@ 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" @@ -3751,17 +3798,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: - 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== +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== 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.0, chalk@^4.1.2: +chalk@^4.0.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== @@ -3843,7 +3890,7 @@ chevrotain@~11.0.3: "@chevrotain/utils" "11.0.3" lodash-es "4.17.21" -chokidar@^3.4.2, chokidar@^3.5.3, chokidar@^3.6.0: +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== @@ -3868,7 +3915,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.2, clean-css@~5.3.2: +clean-css@^5.2.2, clean-css@^5.3.3, 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== @@ -4078,14 +4125,12 @@ 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@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-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-type@~1.0.4, content-type@~1.0.5: +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== @@ -4095,21 +4140,16 @@ 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.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== +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@0.7.1, cookie@>=0.7.0: +cookie@>=0.7.0, cookie@^0.7.1: 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" @@ -4158,17 +4198,6 @@ 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" @@ -4179,7 +4208,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.0, cross-spawn@^7.0.3: +cross-spawn@>=6.0.6, 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== @@ -4207,16 +4236,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.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== +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== dependencies: "@csstools/selector-specificity" "^5.0.0" postcss-selector-parser "^7.0.0" postcss-value-parser "^4.2.0" -css-loader@^6.8.1: +css-loader@^6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.11.0.tgz#33bae3bf6363d0a7c2cf9031c96c744ff54d85ba" integrity sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g== @@ -4295,10 +4324,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.2.1: - version "8.2.2" - resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-8.2.2.tgz#0a5bcbc47a297e6b0296e6082f60363e17b337d4" - integrity sha512-Z3kpWyvN68aKyeMxOUGmffQeHjvrzDxbre2B2ikr/WqQ4ZMkhHu2nOD6uwSeq3TpuOYU7ckvmJRAUIt6orkYUg== +cssdb@^8.4.2: + version "8.4.2" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-8.4.2.tgz#1a367ab1904c97af0bb2c7ae179764deae7b078b" + integrity sha512-PzjkRkRUS+IHDJohtxkIczlxPPZqRo0nXplsYXOMBRPjcVRjj1W4DfvRgshUYTVuUigU7ptVYkFJQ7abUB0nyg== cssesc@^3.0.0: version "3.0.0" @@ -4687,7 +4716,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.0: +debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -4701,6 +4730,13 @@ 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" @@ -4734,7 +4770,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.2.2, deepmerge@^4.3.1: +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== @@ -4785,20 +4821,6 @@ 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" @@ -4806,7 +4828,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== @@ -4816,29 +4838,16 @@ 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.0, dequal@^2.0.3: 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" @@ -5013,6 +5022,15 @@ 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" @@ -5028,6 +5046,11 @@ 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" @@ -5058,12 +5081,7 @@ emoticon@^4.0.1: resolved "https://registry.yarnpkg.com/emoticon/-/emoticon-4.1.0.tgz#d5a156868ee173095627a33de3f1e914c3dde79e" integrity sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ== -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: +encodeurl@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== @@ -5105,6 +5123,11 @@ 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" @@ -5115,6 +5138,13 @@ 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" @@ -5304,7 +5334,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== @@ -5317,7 +5347,7 @@ eval@^0.1.8: "@types/node" "*" require-like ">= 0.1.1" -eventemitter3@^4.0.0: +eventemitter3@^4.0.0, eventemitter3@^4.0.4: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== @@ -5327,47 +5357,64 @@ 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.21.2: - version "4.21.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" - integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== +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== dependencies: - 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" + 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" exsolve@^1.0.7: version "1.0.7" @@ -5455,11 +5502,6 @@ 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" @@ -5467,18 +5509,17 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" -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== +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== dependencies: - 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" + 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" find-cache-dir@^4.0.0: version "4.0.0" @@ -5488,21 +5529,6 @@ 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" @@ -5528,33 +5554,6 @@ 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" @@ -5575,10 +5574,15 @@ fraction.js@^4.3.7: resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== +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== fs-extra@^10.1.0: version "10.1.0" @@ -5598,26 +5602,6 @@ 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" @@ -5659,12 +5643,36 @@ 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-stream@^6.0.1: +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: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== @@ -5693,29 +5701,14 @@ 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.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== +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== dependencies: - foreground-child "^3.1.0" - jackspeak "^3.1.2" - minimatch "^9.0.4" + minimatch "^10.1.1" minipass "^7.1.2" - 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" + path-scurry "^2.0.0" global-dirs@^3.0.0: version "3.0.1" @@ -5724,22 +5717,6 @@ 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" @@ -5750,7 +5727,7 @@ globals@^15.14.0: resolved "https://registry.yarnpkg.com/globals/-/globals-15.15.0.tgz#7c4761299d41c32b075715a4ce1ede7897ff72a8" integrity sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg== -globby@^11.0.1, globby@^11.0.4, globby@^11.1.0: +globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -5773,7 +5750,7 @@ globby@^13.1.1, globby@^13.1.4: merge2 "^1.4.1" slash "^4.0.0" -gopd@^1.0.1: +gopd@^1.0.1, gopd@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== @@ -5851,7 +5828,7 @@ has-proto@^1.0.1: dependencies: call-bind "^1.0.7" -has-symbols@^1.0.3: +has-symbols@^1.0.3, has-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== @@ -6221,16 +6198,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: - version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== +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== dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" + depd "~2.0.0" + inherits "~2.0.4" + setprototypeof "~1.2.0" + statuses "~2.0.2" + toidentifier "~1.0.1" http-errors@~1.6.2: version "1.6.3" @@ -6276,18 +6253,16 @@ 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" @@ -6295,6 +6270,13 @@ 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" @@ -6310,7 +6292,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@^1.0.2: +image-size@>=1.2.1, image-size@^2.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== @@ -6320,12 +6302,7 @@ immediate@^3.2.3: resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== -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: +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== @@ -6353,30 +6330,22 @@ 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.5, ini@~1.3.0: +ini@^1.3.4, 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== @@ -6401,11 +6370,6 @@ 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" @@ -6577,11 +6541,6 @@ 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" @@ -6609,6 +6568,11 @@ 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" @@ -6621,10 +6585,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-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-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-typed-array@^1.1.3: version "1.1.13" @@ -6682,7 +6646,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@^3.1.2: +jackspeak@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.1.1.tgz#2a42db4cfbb7e55433c28b6f75d8b796af9669cd" integrity sha512-juf9stUEwUaILepraGOWIJTLwg48bUnBmRqd2ln2Os1sW987zeoj/hzhbvRB95oMuS2ZTpjULmdwHNX4rzZIZw== @@ -6744,17 +6708,17 @@ joi@^17.9.2: integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + 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== dependencies: argparse "^1.0.7" esprima "^4.0.0" js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + version "4.1.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== dependencies: argparse "^2.0.1" @@ -6783,6 +6747,11 @@ 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" @@ -6901,11 +6870,6 @@ 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" @@ -6915,21 +6879,6 @@ 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" @@ -6991,10 +6940,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@^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@^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@^5.1.1: version "5.1.1" @@ -7040,14 +6989,15 @@ marked@^16.0.0: resolved "https://registry.yarnpkg.com/marked/-/marked-16.2.0.tgz#c407a4f7ed3acc1110812525cfd1b0ed8502792c" integrity sha512-LbbTuye+0dWRz2TS9KJ7wsnD4KAtpj0MVkWc90XvBa6AslXsT0hTBVH5k32pcSyHH1fst9XEFJunXHktVy0zlg== -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" +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-directive@^3.0.0: version "3.0.0" @@ -7374,24 +7324,10 @@ mdast-util-phrasing@^4.0.0: "@types/mdast" "^4.0.0" unist-util-is "^6.0.0" -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== +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== dependencies: "@types/hast" "^3.0.0" "@types/mdast" "^4.0.0" @@ -7456,17 +7392,10 @@ 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@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" +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== memfs@^4.6.0: version "4.17.2" @@ -7478,10 +7407,10 @@ memfs@^4.6.0: tree-dump "^1.0.1" tslib "^2.0.0" -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-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-stream@^2.0.0: version "2.0.0" @@ -7519,11 +7448,6 @@ 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" @@ -8179,7 +8103,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.1.0: +micromark-util-sanitize-uri@^1.0.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== @@ -8301,6 +8225,11 @@ 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" @@ -8313,17 +8242,24 @@ 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.24, mime-types@~2.1.34: +mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, 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@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +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== mimic-response@^3.1.0: version "3.1.0" @@ -8335,10 +8271,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.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== +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== dependencies: schema-utils "^4.0.0" tapable "^2.2.1" @@ -8348,26 +8284,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.0.5, minimatch@^3.1.1: +minimatch@3.1.2, minimatch@^3.0.4: 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@^9.0.4: - version "9.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== +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== dependencies: - brace-expansion "^2.0.1" + "@isaacs/brace-expansion" "^5.0.0" 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@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: +minipass@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== @@ -8402,7 +8338,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== @@ -8424,6 +8360,11 @@ 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" @@ -8434,6 +8375,11 @@ 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" @@ -8476,16 +8422,21 @@ node-fetch@2.6.7: dependencies: whatwg-url "^5.0.0" -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-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-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" @@ -8513,6 +8464,13 @@ 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" @@ -8538,10 +8496,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.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-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-is@^1.1.5: version "1.1.6" @@ -8571,7 +8529,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== @@ -8583,13 +8541,20 @@ 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.3.0: +once@^1.4.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" @@ -8619,19 +8584,10 @@ p-cancelable@^3.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== -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-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@^4.0.0: version "4.0.0" @@ -8640,20 +8596,6 @@ 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" @@ -8668,6 +8610,14 @@ 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" @@ -8677,15 +8627,12 @@ p-retry@^6.2.0: is-network-error "^1.0.0" retry "^0.13.1" -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== +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" package-json@^8.1.0: version "8.1.1" @@ -8731,7 +8678,7 @@ parse-entities@^4.0.0: is-decimal "^2.0.0" is-hexadecimal "^2.0.0" -parse-json@^5.0.0, parse-json@^5.2.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== @@ -8766,7 +8713,7 @@ parse5@^7.0.0: dependencies: entities "^4.5.0" -parseurl@~1.3.2, parseurl@~1.3.3: +parseurl@^1.3.3, parseurl@~1.3.2: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== @@ -8789,32 +8736,17 @@ 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.1.0: +path-key@^3.0.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== @@ -8836,18 +8768,13 @@ path-root@^0.1.1: dependencies: path-root-regex "^0.1.0" -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== +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== dependencies: - 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== + lru-cache "^11.0.0" + minipass "^7.1.2" path-to-regexp@3.3.0: version "3.3.0" @@ -8861,6 +8788,11 @@ 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" @@ -8920,13 +8852,6 @@ 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" @@ -8967,15 +8892,15 @@ postcss-clamp@^4.1.0: dependencies: postcss-value-parser "^4.2.0" -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== +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== dependencies: - "@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/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" postcss-color-hex-alpha@^10.0.0: @@ -9012,35 +8937,35 @@ postcss-convert-values@^6.1.0: browserslist "^4.23.0" postcss-value-parser "^4.2.0" -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== +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== dependencies: - "@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" + "@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" -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== +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== dependencies: - "@csstools/cascade-layer-name-parser" "^2.0.4" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" + "@csstools/cascade-layer-name-parser" "^2.0.5" + "@csstools/css-parser-algorithms" "^3.0.5" + "@csstools/css-tokenizer" "^3.0.4" "@csstools/utilities" "^2.0.0" postcss-value-parser "^4.2.0" -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== +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== dependencies: - "@csstools/cascade-layer-name-parser" "^2.0.4" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" + "@csstools/cascade-layer-name-parser" "^2.0.5" + "@csstools/css-parser-algorithms" "^3.0.5" + "@csstools/css-tokenizer" "^3.0.4" postcss-selector-parser "^7.0.0" postcss-dir-pseudo-class@^9.0.1: @@ -9077,12 +9002,12 @@ postcss-discard-unused@^6.0.5: dependencies: postcss-selector-parser "^6.0.16" -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== +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== dependencies: - "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/postcss-progressive-custom-properties" "^4.2.1" "@csstools/utilities" "^2.0.0" postcss-value-parser "^4.2.0" @@ -9118,18 +9043,18 @@ postcss-image-set-function@^7.0.0: "@csstools/utilities" "^2.0.0" postcss-value-parser "^4.2.0" -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== +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== dependencies: - "@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/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" -postcss-loader@^7.3.3: +postcss-loader@^7.3.4: version "7.3.4" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-7.3.4.tgz#aed9b79ce4ed7e9e89e56199d25ad1ec8f606209" integrity sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A== @@ -9138,10 +9063,10 @@ postcss-loader@^7.3.3: jiti "^1.20.0" semver "^7.5.4" -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== +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== dependencies: postcss-value-parser "^4.2.0" @@ -9231,12 +9156,12 @@ postcss-modules-values@^4.0.0: dependencies: icss-utils "^5.0.0" -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== +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== dependencies: - "@csstools/selector-resolve-nested" "^3.0.0" + "@csstools/selector-resolve-nested" "^3.1.0" "@csstools/selector-specificity" "^5.0.0" postcss-selector-parser "^7.0.0" @@ -9334,67 +9259,71 @@ postcss-place@^10.0.0: dependencies: postcss-value-parser "^4.2.0" -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== +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== dependencies: - "@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-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-font-format-keywords" "^4.0.0" - "@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-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-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.3" - "@csstools/postcss-media-minmax" "^2.0.5" - "@csstools/postcss-media-queries-aspect-ratio-number-values" "^3.0.4" + "@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-nested-calc" "^4.0.0" "@csstools/postcss-normalize-display-values" "^4.0.0" - "@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-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-scope-pseudo-class" "^4.0.1" - "@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-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-unset-value" "^4.0.0" - autoprefixer "^10.4.19" - browserslist "^4.23.1" + autoprefixer "^10.4.21" + browserslist "^4.26.0" css-blank-pseudo "^7.0.1" - css-has-pseudo "^7.0.1" + css-has-pseudo "^7.0.3" css-prefers-color-scheme "^10.0.0" - cssdb "^8.2.1" + cssdb "^8.4.2" postcss-attribute-case-insensitive "^7.0.1" postcss-clamp "^4.1.0" - postcss-color-functional-notation "^7.0.6" + postcss-color-functional-notation "^7.0.12" postcss-color-hex-alpha "^10.0.0" postcss-color-rebeccapurple "^10.0.0" - postcss-custom-media "^11.0.5" - postcss-custom-properties "^14.0.4" - postcss-custom-selectors "^8.0.4" + postcss-custom-media "^11.0.6" + postcss-custom-properties "^14.0.6" + postcss-custom-selectors "^8.0.5" postcss-dir-pseudo-class "^9.0.1" - postcss-double-position-gradients "^6.0.0" + postcss-double-position-gradients "^6.0.4" 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.6" - postcss-logical "^8.0.0" - postcss-nesting "^13.0.1" + postcss-lab-function "^7.0.12" + postcss-logical "^8.1.0" + postcss-nesting "^13.0.2" postcss-opacity-percentage "^3.0.0" postcss-overflow-shorthand "^6.0.0" postcss-page-break "^3.0.4" @@ -9492,7 +9421,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.26, postcss@^8.4.33, postcss@^8.4.38: +postcss@^8.4.21, postcss@^8.4.24, postcss@^8.4.33: version "8.4.49" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.49.tgz#4ea479048ab059ab3ae61d082190fabfd994fe19" integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA== @@ -9501,6 +9430,15 @@ postcss@^8.4.21, postcss@^8.4.24, postcss@^8.4.26, postcss@^8.4.33, postcss@^8.4 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" @@ -9566,7 +9504,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== @@ -9586,12 +9524,12 @@ pupa@^3.1.0: dependencies: escape-goat "^4.0.0" -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== +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== dependencies: - side-channel "^1.0.6" + side-channel "^1.1.0" quansync@^0.2.11: version "0.2.11" @@ -9620,20 +9558,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@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== +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== dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" + bytes "~3.1.2" + http-errors "~2.0.1" + iconv-lite "~0.7.0" + unpipe "~1.0.0" rc@1.2.8: version "1.2.8" @@ -9645,36 +9583,6 @@ 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" @@ -9683,29 +9591,15 @@ react-dom@^18.0.0: loose-envify "^1.1.0" scheduler "^0.23.2" -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: +react-fast-compare@^3.2.0: 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@*: - 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: +"react-helmet-async@npm:@slorber/react-helmet-async@1.3.0": version "1.3.0" - resolved "https://registry.yarnpkg.com/react-helmet-async/-/react-helmet-async-1.3.0.tgz#7bd5bf8c5c69ea9f02f6083f14ce33ef545c222e" - integrity sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg== + resolved "https://registry.yarnpkg.com/@slorber/react-helmet-async/-/react-helmet-async-1.3.0.tgz#11fbc6094605cf60aa04a28c17e0aab894b4ecff" + integrity sha512-e9/OK8VhwUSc67diWI8Rb3I0YgI9/SBQtnhe9aEuK6MhZm7ntZZimXgwXnd8W96YTmSOb9M4d8LwhRZyhWr/1A== dependencies: "@babel/runtime" "^7.12.5" invariant "^2.2.4" @@ -9718,10 +9612,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@^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-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-lifecycles-compat@^3.0.0: version "3.0.4" @@ -9832,18 +9726,6 @@ 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" @@ -9884,13 +9766,6 @@ 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" @@ -10081,20 +9956,10 @@ remark-parse@^11.0.0: micromark-util-types "^2.0.0" unified "^11.0.0" -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== +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== dependencies: "@types/hast" "^3.0.0" "@types/mdast" "^4.0.0" @@ -10164,7 +10029,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.1.6, resolve@^1.14.2: +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== @@ -10190,13 +10055,6 @@ 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" @@ -10212,10 +10070,16 @@ roughjs@^4.6.6: points-on-curve "^0.2.0" points-on-path "^0.2.1" -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== +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" rtlcss@^4.1.0: version "4.3.0" @@ -10261,7 +10125,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", "safer-buffer@>= 2.1.2 < 3.0.0": +"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== @@ -10278,14 +10142,10 @@ scheduler@^0.23.2: dependencies: loose-envify "^1.1.0" -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-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@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0: version "3.3.0" @@ -10349,29 +10209,27 @@ 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.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: +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@0.19.0: - version "0.19.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" - integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== +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== dependencies: - 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" + 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" serialize-javascript@^6.0.0, serialize-javascript@^6.0.1: version "6.0.2" @@ -10406,15 +10264,15 @@ serve-index@^1.9.1: mime-types "~2.1.17" parseurl "~1.3.2" -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== +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== dependencies: - encodeurl "~2.0.0" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.19.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + parseurl "^1.3.3" + send "^1.2.0" set-function-length@^1.2.2: version "1.2.2" @@ -10433,7 +10291,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== @@ -10462,40 +10320,56 @@ 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.7.3, shell-quote@^1.8.1: +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== -shelljs@^0.8.5: - version "0.8.5" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" - integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== +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== dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - -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-bind "^1.0.7" es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" + object-inspect "^1.13.3" -signal-exit@^3.0.0, signal-exit@^3.0.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== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +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: 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" @@ -10630,16 +10504,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" @@ -10713,6 +10587,11 @@ 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" @@ -10800,6 +10679,14 @@ 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" @@ -10815,11 +10702,6 @@ 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" @@ -10846,11 +10728,6 @@ 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" @@ -10870,6 +10747,11 @@ 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" @@ -10890,6 +10772,11 @@ 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" @@ -10905,7 +10792,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== @@ -10970,13 +10857,14 @@ 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@~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== +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== dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" + content-type "^1.0.5" + media-typer "^1.1.0" + mime-types "^3.0.0" typedarray-to-buffer@^3.1.5: version "3.1.5" @@ -11075,11 +10963,6 @@ 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" @@ -11221,7 +11104,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== @@ -11234,6 +11117,14 @@ 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" @@ -11275,6 +11166,11 @@ 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" @@ -11301,11 +11197,6 @@ 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" @@ -11339,7 +11230,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== @@ -11511,7 +11402,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@^4.15.2: +webpack-dev-server@>=5.2.1, webpack-dev-server@^5.2.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== @@ -11651,13 +11542,6 @@ 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" @@ -11749,11 +11633,6 @@ 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" @@ -11778,16 +11657,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"