Compare commits
1 Commits
0.14.11
...
micha/ty-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ad2e09430 |
67
.claude/settings.local.json
Normal file
67
.claude/settings.local.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(cargo build:*)",
|
||||
"Read(//home/micha/astral/discord.py/discord/**)",
|
||||
"Bash(source:*)",
|
||||
"Bash(./target/profiling/ty check:*)",
|
||||
"Bash(tee:*)",
|
||||
"Read(//home/micha/astral/discord.py/.venv/**)",
|
||||
"Read(//home/micha/astral/discord.py/**)",
|
||||
"Bash(perf record:*)",
|
||||
"Bash(perf report:*)",
|
||||
"Bash(time:*)",
|
||||
"Bash(../ruff/target/profiling/ty check discord/audit_logs.py -vv)",
|
||||
"Bash(sed:*)",
|
||||
"Read(//home/micha/git/TypeScript/**)",
|
||||
"Bash(cargo test:*)",
|
||||
"Bash(MDTEST_TEST_FILTER='union_types.md - Union types - Unions of tuples' cargo test -p ty_python_semantic --test mdtest -- mdtest__union_types)",
|
||||
"Bash(timeout 10 cargo test --package ty_python_semantic --lib types::tests::divergent_type)",
|
||||
"Bash(timeout 30 cargo test:*)",
|
||||
"Bash(git stash:*)",
|
||||
"Bash(timeout 60 time:*)",
|
||||
"Bash(for i in 1 2 3 4 5)",
|
||||
"Bash(do echo \"Run $i:\")",
|
||||
"Bash(done)",
|
||||
"Bash(for i in 1 2 3)",
|
||||
"Bash(cargo fuzz run:*)",
|
||||
"Bash(timeout 60 cargo fuzz run -s none ty_check_invalid_syntax -- -timeout=1)",
|
||||
"Bash(for:*)",
|
||||
"Bash(do echo \"=== Checking $crash ===\")",
|
||||
"Bash(uvx ty@latest check \"$crash\")",
|
||||
"Bash(do echo \"=== $crash ===\")",
|
||||
"Bash(while read crash)",
|
||||
"Bash(cargo fuzz cmin:*)",
|
||||
"Bash(cargo +nightly fuzz cmin:*)",
|
||||
"Bash(timeout 120 cargo fuzz run -s none ty_check_invalid_syntax -- -timeout=1)",
|
||||
"Bash(awk:*)",
|
||||
"Bash(while read file)",
|
||||
"Bash(cat:*)",
|
||||
"Bash(uvx ty@latest:*)",
|
||||
"Bash(do cp \"$crash\" /tmp/isolated_crash.py)",
|
||||
"Bash(echo \"=== $crash ===\")",
|
||||
"Bash(do echo \"=== test$i.py ===\")",
|
||||
"Bash(do echo \"=== Testing $crash ===\")",
|
||||
"Bash(tree:*)",
|
||||
"Bash(cut:*)",
|
||||
"Bash(grep:*)",
|
||||
"Bash(ls:*)",
|
||||
"Bash(xargs basename:*)",
|
||||
"Bash(wc:*)",
|
||||
"Bash(find:*)",
|
||||
"Bash({} ;)",
|
||||
"Bash(git checkout:*)",
|
||||
"Bash(do)",
|
||||
"Bash(if ! grep -q \"use crate::types\" \"$f\")",
|
||||
"Bash(! grep -q \"crate::types::\" \"$f\")",
|
||||
"Bash(then)",
|
||||
"Bash(else)",
|
||||
"Bash(fi)",
|
||||
"Bash(1)",
|
||||
"Bash(__NEW_LINE__ echo \"Done\")",
|
||||
"Bash(rm:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ exclude: |
|
||||
.github/workflows/release.yml|
|
||||
crates/ty_vendored/vendor/.*|
|
||||
crates/ty_project/resources/.*|
|
||||
crates/ty_python_semantic/resources/corpus/.*|
|
||||
crates/ty_python_types/resources/corpus/.*|
|
||||
crates/ty/docs/(configuration|rules|cli|environment).md|
|
||||
crates/ruff_benchmark/resources/.*|
|
||||
crates/ruff_linter/resources/.*|
|
||||
|
||||
63
Cargo.lock
generated
63
Cargo.lock
generated
@@ -3083,6 +3083,7 @@ dependencies = [
|
||||
"ty",
|
||||
"ty_project",
|
||||
"ty_python_semantic",
|
||||
"ty_python_types",
|
||||
"ty_static",
|
||||
"url",
|
||||
]
|
||||
@@ -3131,6 +3132,7 @@ dependencies = [
|
||||
"serde",
|
||||
"ty_module_resolver",
|
||||
"ty_python_semantic",
|
||||
"ty_python_types",
|
||||
"zip",
|
||||
]
|
||||
|
||||
@@ -4442,6 +4444,7 @@ dependencies = [
|
||||
"ty_module_resolver",
|
||||
"ty_project",
|
||||
"ty_python_semantic",
|
||||
"ty_python_types",
|
||||
"ty_vendored",
|
||||
]
|
||||
|
||||
@@ -4504,6 +4507,7 @@ dependencies = [
|
||||
"ty_combine",
|
||||
"ty_module_resolver",
|
||||
"ty_python_semantic",
|
||||
"ty_python_types",
|
||||
"ty_static",
|
||||
"ty_vendored",
|
||||
]
|
||||
@@ -4517,19 +4521,12 @@ dependencies = [
|
||||
"bitvec",
|
||||
"camino",
|
||||
"colored 3.0.0",
|
||||
"compact_str",
|
||||
"datatest-stable",
|
||||
"drop_bomb",
|
||||
"get-size2",
|
||||
"glob",
|
||||
"hashbrown 0.16.1",
|
||||
"indexmap",
|
||||
"indoc",
|
||||
"insta",
|
||||
"itertools 0.14.0",
|
||||
"memchr",
|
||||
"ordermap",
|
||||
"pretty_assertions",
|
||||
"quickcheck",
|
||||
"quickcheck_macros",
|
||||
"ruff_annotate_snippets",
|
||||
@@ -4539,9 +4536,7 @@ dependencies = [
|
||||
"ruff_macros",
|
||||
"ruff_memory_usage",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_literal",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_python_trivia",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
@@ -4555,12 +4550,59 @@ dependencies = [
|
||||
"strsim",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"test-case",
|
||||
"thiserror 2.0.17",
|
||||
"tracing",
|
||||
"ty_combine",
|
||||
"ty_module_resolver",
|
||||
"ty_static",
|
||||
"ty_vendored",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ty_python_types"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.10.0",
|
||||
"camino",
|
||||
"compact_str",
|
||||
"datatest-stable",
|
||||
"drop_bomb",
|
||||
"get-size2",
|
||||
"glob",
|
||||
"indexmap",
|
||||
"indoc",
|
||||
"insta",
|
||||
"itertools 0.14.0",
|
||||
"memchr",
|
||||
"ordermap",
|
||||
"pretty_assertions",
|
||||
"quickcheck",
|
||||
"quickcheck_macros",
|
||||
"ruff_db",
|
||||
"ruff_diagnostics",
|
||||
"ruff_macros",
|
||||
"ruff_memory_usage",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_literal",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
"rustc-hash",
|
||||
"salsa",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smallvec",
|
||||
"static_assertions",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"test-case",
|
||||
"tracing",
|
||||
"ty_module_resolver",
|
||||
"ty_python_semantic",
|
||||
"ty_static",
|
||||
"ty_test",
|
||||
"ty_vendored",
|
||||
]
|
||||
@@ -4641,6 +4683,7 @@ dependencies = [
|
||||
"tracing",
|
||||
"ty_module_resolver",
|
||||
"ty_python_semantic",
|
||||
"ty_python_types",
|
||||
"ty_static",
|
||||
"ty_vendored",
|
||||
]
|
||||
|
||||
@@ -48,6 +48,7 @@ ty_ide = { path = "crates/ty_ide" }
|
||||
ty_module_resolver = { path = "crates/ty_module_resolver" }
|
||||
ty_project = { path = "crates/ty_project", default-features = false }
|
||||
ty_python_semantic = { path = "crates/ty_python_semantic" }
|
||||
ty_python_types = { path = "crates/ty_python_types" }
|
||||
ty_server = { path = "crates/ty_server" }
|
||||
ty_static = { path = "crates/ty_static" }
|
||||
ty_test = { path = "crates/ty_test" }
|
||||
|
||||
@@ -14,6 +14,7 @@ license = { workspace = true }
|
||||
ty = { workspace = true }
|
||||
ty_project = { workspace = true, features = ["schemars"] }
|
||||
ty_python_semantic = { workspace = true }
|
||||
ty_python_types = { workspace = true }
|
||||
ty_static = { workspace = true }
|
||||
ruff = { workspace = true }
|
||||
ruff_formatter = { workspace = true }
|
||||
|
||||
@@ -52,7 +52,7 @@ pub(crate) fn main(args: &Args) -> Result<()> {
|
||||
}
|
||||
|
||||
fn generate_markdown() -> String {
|
||||
let registry = ty_python_semantic::default_lint_registry();
|
||||
let registry = ty_python_types::default_lint_registry();
|
||||
|
||||
let mut output = String::new();
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ ruff_python_ast = { workspace = true }
|
||||
ruff_python_parser = { workspace = true }
|
||||
ty_module_resolver = { workspace = true }
|
||||
ty_python_semantic = { workspace = true }
|
||||
ty_python_types = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true, optional = true }
|
||||
|
||||
@@ -11,8 +11,9 @@ use ty_module_resolver::{SearchPathSettings, SearchPaths};
|
||||
use ty_python_semantic::lint::{LintRegistry, RuleSelection};
|
||||
use ty_python_semantic::{
|
||||
AnalysisSettings, Db, Program, ProgramSettings, PythonEnvironment, PythonPlatform,
|
||||
PythonVersionSource, PythonVersionWithSource, SysPrefixPathOrigin, default_lint_registry,
|
||||
PythonVersionSource, PythonVersionWithSource, SysPrefixPathOrigin,
|
||||
};
|
||||
use ty_python_types::default_lint_registry;
|
||||
|
||||
static EMPTY_VENDORED: std::sync::LazyLock<VendoredFileSystem> = std::sync::LazyLock::new(|| {
|
||||
let mut builder = VendoredFileSystemBuilder::new(CompressionMethod::Stored);
|
||||
|
||||
170
crates/ty/docs/rules.md
generated
170
crates/ty/docs/rules.md
generated
@@ -8,7 +8,7 @@
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20ambiguous-protocol-member" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L538" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L538" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class SubProto(BaseProto, Protocol):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20byte-string-type-annotation" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L36" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fstring_annotation.rs#L36" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ def test(): -> "int":
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L137" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L137" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ Calling a non-callable object will raise a `TypeError` at runtime.
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.7">0.0.7</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-top-callable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L155" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L155" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ def f(x: object):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L206" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L206" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ f(int) # error
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L232" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L232" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ a = 1
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L257" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L257" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ class C(A, B): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L283" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L283" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -262,7 +262,7 @@ class B(A): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/1.0.0">1.0.0</a>) ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-type-alias-definition" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L309" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L309" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -290,7 +290,7 @@ type B = A
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.16">0.0.1-alpha.16</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20deprecated" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L353" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L353" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -317,7 +317,7 @@ old_func() # emits [deprecated] diagnostic
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a>) ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L331" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L331" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -346,7 +346,7 @@ false positives it can produce.
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L374" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L374" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -373,7 +373,7 @@ class B(A, A): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.12">0.0.1-alpha.12</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-kw-only" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L395" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L395" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -411,7 +411,7 @@ class A: # Crash at runtime
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20escape-character-in-forward-annotation" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L154" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fstring_annotation.rs#L154" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -436,7 +436,7 @@ def foo() -> "intt\b": ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20fstring-type-annotation" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L11" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fstring_annotation.rs#L11" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -467,7 +467,7 @@ def test(): -> "int":
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20ignore-comment-unknown-rule" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L50" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L49" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -498,7 +498,7 @@ a = 20 / 0 # ty: ignore[division-by-zero]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20implicit-concatenated-string-type-annotation" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L86" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fstring_annotation.rs#L86" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -529,7 +529,7 @@ def test(): -> "Literal[5]":
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L621" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L621" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -559,7 +559,7 @@ class C(A, B): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L645" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L645" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -585,7 +585,7 @@ t[3] # IndexError: tuple index out of range
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.12">0.0.1-alpha.12</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20instance-layout-conflict" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L427" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L427" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -674,7 +674,7 @@ an atypical memory layout.
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L699" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L699" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -701,7 +701,7 @@ func("foo") # error: [invalid-argument-type]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L739" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L739" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -729,7 +729,7 @@ a: int = ''
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2042" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2042" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -763,7 +763,7 @@ C.instance_var = 3 # error: Cannot assign to instance variable
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.19">0.0.1-alpha.19</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-await" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L761" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L761" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -799,7 +799,7 @@ asyncio.run(main())
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L791" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L791" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -823,7 +823,7 @@ class A(42): ... # error: [invalid-base]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L842" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L842" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -850,7 +850,7 @@ with 1:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L863" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L863" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -879,7 +879,7 @@ a: str
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L886" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L886" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -923,7 +923,7 @@ except ZeroDivisionError:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.28">0.0.1-alpha.28</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-explicit-override" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1712" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1712" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -965,7 +965,7 @@ class D(A):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.35">0.0.1-alpha.35</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-frozen-dataclass-subclass" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2268" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2268" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1009,7 +1009,7 @@ class NonFrozenChild(FrozenBase): # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L922" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L922" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1047,7 +1047,7 @@ class D(Generic[U, T]): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-ignore-comment" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L75" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L74" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1077,7 +1077,7 @@ a = 20 / 0 # type: ignore
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.17">0.0.1-alpha.17</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-key" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L666" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L666" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1116,7 +1116,7 @@ carol = Person(name="Carol", age=25) # typo!
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L953" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L953" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1151,7 +1151,7 @@ def f(t: TypeVar("U")): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1050" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1050" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1185,7 +1185,7 @@ class B(metaclass=f): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-method-override" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2170" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2170" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1292,7 +1292,7 @@ Correct use of `@override` is enforced by ty's `invalid-explicit-override` rule.
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.19">0.0.1-alpha.19</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-named-tuple" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L573" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L573" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1346,7 +1346,7 @@ AttributeError: Cannot overwrite NamedTuple attribute _asdict
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/1.0.0">1.0.0</a>) ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-newtype" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1026" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1026" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1376,7 +1376,7 @@ Baz = NewType("Baz", int | str) # error: invalid base for `typing.NewType`
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1077" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1077" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1426,7 +1426,7 @@ def foo(x: int) -> int: ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1176" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1176" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1452,7 +1452,7 @@ def f(a: int = ''): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-paramspec" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L981" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L981" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1483,7 +1483,7 @@ P2 = ParamSpec("S2") # error: ParamSpec name must match the variable it's assig
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L509" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L509" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1517,7 +1517,7 @@ TypeError: Protocols can only inherit from other protocols, got <class 'int'>
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1196" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1196" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1566,7 +1566,7 @@ def g():
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L720" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L720" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1591,7 +1591,7 @@ def func() -> int:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1239" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1239" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1637,7 +1637,7 @@ super(B, A) # error: `A` does not satisfy `issubclass(A, B)`
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-syntax-in-forward-annotation" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L111" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fstring_annotation.rs#L111" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1687,7 +1687,7 @@ class C: ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.6">0.0.1-alpha.6</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-alias-type" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1005" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1005" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1714,7 +1714,7 @@ NewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name mus
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.29">0.0.1-alpha.29</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-arguments" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1471" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1471" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1761,7 +1761,7 @@ Bar[int] # error: too few arguments
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1278" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1278" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1791,7 +1791,7 @@ TYPE_CHECKING = ''
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1302" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1302" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1821,7 +1821,7 @@ b: Annotated[int] # `Annotated` expects at least two arguments
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.11">0.0.1-alpha.11</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-call" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1354" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1354" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1855,7 +1855,7 @@ f(10) # Error
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.11">0.0.1-alpha.11</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-definition" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1326" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1326" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1889,7 +1889,7 @@ class C:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1382" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1382" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1924,7 +1924,7 @@ T = TypeVar('T', bound=str) # valid bound TypeVar
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1411" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1411" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1949,7 +1949,7 @@ func() # TypeError: func() missing 1 required positional argument: 'x'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-typed-dict-key" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2143" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2143" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1982,7 +1982,7 @@ alice["age"] # KeyError
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1430" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1430" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2011,7 +2011,7 @@ func("string") # error: [no-matching-overload]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1453" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1453" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2035,7 +2035,7 @@ Subscripting an object that does not support it will raise a `TypeError` at runt
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1512" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1512" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2061,7 +2061,7 @@ for i in 34: # TypeError: 'int' object is not iterable
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.29">0.0.1-alpha.29</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20override-of-final-method" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1685" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1685" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2094,7 +2094,7 @@ class B(A):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1563" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1563" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2121,7 +2121,7 @@ f(1, x=2) # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20positional-only-parameter-as-kwarg" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1896" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1896" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2148,7 +2148,7 @@ f(x=1) # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-attribute" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1584" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1584" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2176,7 +2176,7 @@ A.c # AttributeError: type object 'A' has no attribute 'c'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-implicit-call" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L180" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L180" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2208,7 +2208,7 @@ A()[0] # TypeError: 'A' object is not subscriptable
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-import" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1606" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1606" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2245,7 +2245,7 @@ from module import a # ImportError: cannot import name 'a' from 'module'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1636" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1636" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2278,7 +2278,7 @@ print(x) # NameError: name 'x' is not defined
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20raw-string-type-annotation" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L61" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fstring_annotation.rs#L61" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2309,7 +2309,7 @@ def test(): -> "int":
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2070" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2070" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2336,7 +2336,7 @@ cast(int, f()) # Redundant
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2018" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2018" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2366,7 +2366,7 @@ static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known tr
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1662" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1662" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2395,7 +2395,7 @@ class B(A): ... # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.30">0.0.1-alpha.30</a>) ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20super-call-in-named-tuple-method" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1830" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1830" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2429,7 +2429,7 @@ class F(NamedTuple):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1770" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1770" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2456,7 +2456,7 @@ f("foo") # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1748" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1748" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2484,7 +2484,7 @@ def _(x: int):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1791" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1791" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2530,7 +2530,7 @@ class A:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1857" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1857" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2554,7 +2554,7 @@ reveal_type(1) # NameError: name 'reveal_type' is not defined
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1875" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1875" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2581,7 +2581,7 @@ f(x=1, y=2) # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1917" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1917" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2609,7 +2609,7 @@ A().foo # AttributeError: 'A' object has no attribute 'foo'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.15">0.0.1-alpha.15</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-global" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2091" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2091" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2667,7 +2667,7 @@ def g():
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1939" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1939" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2692,7 +2692,7 @@ import foo # ModuleNotFoundError: No module named 'foo'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1958" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1958" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2717,7 +2717,7 @@ print(x) # NameError: name 'x' is not defined
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.7">0.0.1-alpha.7</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-base" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L809" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L809" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2756,7 +2756,7 @@ class D(C): ... # error: [unsupported-base]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1532" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1532" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2793,7 +2793,7 @@ b1 < b2 < b1 # exception raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1977" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1977" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2821,7 +2821,7 @@ A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unused-ignore-comment" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L25" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L24" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2852,7 +2852,7 @@ a = 20 / 2
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20useless-overload-body" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1120" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1120" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2915,7 +2915,7 @@ def foo(x: int | str) -> int | str:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1999" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1999" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ ruff_source_file = { workspace = true }
|
||||
ruff_text_size = { workspace = true }
|
||||
ty_module_resolver = { workspace = true }
|
||||
ty_python_semantic = { workspace = true }
|
||||
ty_python_types = { workspace = true }
|
||||
ty_project = { workspace = true, features = ["testing"] }
|
||||
ty_vendored = { workspace = true }
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ use ruff_text_size::TextRange;
|
||||
use ty_project::Db;
|
||||
use ty_python_semantic::create_suppression_fix;
|
||||
use ty_python_semantic::lint::LintId;
|
||||
use ty_python_semantic::types::{UNDEFINED_REVEAL, UNRESOLVED_REFERENCE};
|
||||
use ty_python_types::types::{UNDEFINED_REVEAL, UNRESOLVED_REFERENCE};
|
||||
|
||||
/// A `QuickFix` Code Action
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -87,10 +87,8 @@ mod tests {
|
||||
use ruff_python_trivia::textwrap::dedent;
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use ty_project::ProjectMetadata;
|
||||
use ty_python_semantic::{
|
||||
lint::LintMetadata,
|
||||
types::{UNDEFINED_REVEAL, UNRESOLVED_REFERENCE},
|
||||
};
|
||||
use ty_python_semantic::lint::LintMetadata;
|
||||
use ty_python_types::types::{UNDEFINED_REVEAL, UNRESOLVED_REFERENCE};
|
||||
|
||||
#[test]
|
||||
fn add_ignore() {
|
||||
|
||||
@@ -12,11 +12,8 @@ use ruff_python_codegen::Stylist;
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
use rustc_hash::FxHashSet;
|
||||
use ty_module_resolver::{KnownModule, ModuleName};
|
||||
use ty_python_semantic::types::UnionType;
|
||||
use ty_python_semantic::{
|
||||
Completion as SemanticCompletion, NameKind, SemanticModel,
|
||||
types::{CycleDetector, KnownClass, Type},
|
||||
};
|
||||
use ty_python_types::types::{CycleDetector, KnownClass, Type, UnionType};
|
||||
use ty_python_types::{Completion as SemanticCompletion, NameKind, SemanticModel};
|
||||
|
||||
use crate::docstring::Docstring;
|
||||
use crate::goto::Definitions;
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::references::{ReferencesMode, references};
|
||||
use crate::{Db, ReferenceTarget};
|
||||
use ruff_db::files::File;
|
||||
use ruff_text_size::TextSize;
|
||||
use ty_python_semantic::SemanticModel;
|
||||
use ty_python_types::SemanticModel;
|
||||
|
||||
/// Find all document highlights for a symbol at the given position.
|
||||
/// Document highlights are limited to the current file only.
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::references::{ReferencesMode, references};
|
||||
use crate::{Db, ReferenceTarget};
|
||||
use ruff_db::files::File;
|
||||
use ruff_text_size::TextSize;
|
||||
use ty_python_semantic::SemanticModel;
|
||||
use ty_python_types::SemanticModel;
|
||||
|
||||
/// Find all references to a symbol at the given position.
|
||||
/// Search for references across all files in the project.
|
||||
|
||||
@@ -12,12 +12,12 @@ use ruff_python_ast::token::{TokenKind, Tokens};
|
||||
use ruff_python_ast::{self as ast, AnyNodeRef};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
|
||||
use ty_python_semantic::ResolvedDefinition;
|
||||
use ty_python_semantic::types::Type;
|
||||
use ty_python_semantic::types::ide_support::{
|
||||
use ty_python_types::ResolvedDefinition;
|
||||
use ty_python_types::types::Type;
|
||||
use ty_python_types::types::ide_support::{
|
||||
call_signature_details, call_type_simplified_by_overloads, definitions_for_keyword_argument,
|
||||
};
|
||||
use ty_python_semantic::{
|
||||
use ty_python_types::{
|
||||
HasDefinition, HasType, ImportAliasResolution, SemanticModel, definitions_for_imported_symbol,
|
||||
definitions_for_name,
|
||||
};
|
||||
@@ -228,15 +228,15 @@ impl<'db> Definitions<'db> {
|
||||
pub(crate) fn from_ty(db: &'db dyn crate::Db, ty: Type<'db>) -> Option<Self> {
|
||||
let ty_def = ty.definition(db)?;
|
||||
let resolved = match ty_def {
|
||||
ty_python_semantic::types::TypeDefinition::Module(module) => {
|
||||
ty_python_types::types::TypeDefinition::Module(module) => {
|
||||
ResolvedDefinition::Module(module.file(db)?)
|
||||
}
|
||||
ty_python_semantic::types::TypeDefinition::Class(definition)
|
||||
| ty_python_semantic::types::TypeDefinition::Function(definition)
|
||||
| ty_python_semantic::types::TypeDefinition::TypeVar(definition)
|
||||
| ty_python_semantic::types::TypeDefinition::TypeAlias(definition)
|
||||
| ty_python_semantic::types::TypeDefinition::SpecialForm(definition)
|
||||
| ty_python_semantic::types::TypeDefinition::NewType(definition) => {
|
||||
ty_python_types::types::TypeDefinition::Class(definition)
|
||||
| ty_python_types::types::TypeDefinition::Function(definition)
|
||||
| ty_python_types::types::TypeDefinition::TypeVar(definition)
|
||||
| ty_python_types::types::TypeDefinition::TypeAlias(definition)
|
||||
| ty_python_types::types::TypeDefinition::SpecialForm(definition)
|
||||
| ty_python_types::types::TypeDefinition::NewType(definition) => {
|
||||
ResolvedDefinition::Definition(definition)
|
||||
}
|
||||
};
|
||||
@@ -338,11 +338,11 @@ impl GotoTarget<'_> {
|
||||
}
|
||||
}
|
||||
GotoTarget::BinOp { expression, .. } => {
|
||||
let (_, ty) = ty_python_semantic::definitions_for_bin_op(model, expression)?;
|
||||
let (_, ty) = ty_python_types::definitions_for_bin_op(model, expression)?;
|
||||
Some(ty)
|
||||
}
|
||||
GotoTarget::UnaryOp { expression, .. } => {
|
||||
let (_, ty) = ty_python_semantic::definitions_for_unary_op(model, expression)?;
|
||||
let (_, ty) = ty_python_types::definitions_for_unary_op(model, expression)?;
|
||||
Some(ty)
|
||||
}
|
||||
// TODO: Support identifier targets
|
||||
@@ -526,15 +526,14 @@ impl GotoTarget<'_> {
|
||||
}
|
||||
|
||||
GotoTarget::BinOp { expression, .. } => {
|
||||
let (definitions, _) =
|
||||
ty_python_semantic::definitions_for_bin_op(model, expression)?;
|
||||
let (definitions, _) = ty_python_types::definitions_for_bin_op(model, expression)?;
|
||||
|
||||
Some(definitions)
|
||||
}
|
||||
|
||||
GotoTarget::UnaryOp { expression, .. } => {
|
||||
let (definitions, _) =
|
||||
ty_python_semantic::definitions_for_unary_op(model, expression)?;
|
||||
ty_python_types::definitions_for_unary_op(model, expression)?;
|
||||
|
||||
Some(definitions)
|
||||
}
|
||||
@@ -939,12 +938,12 @@ impl Ranged for GotoTarget<'_> {
|
||||
/// Converts a collection of `ResolvedDefinition` items into `NavigationTarget` items.
|
||||
fn convert_resolved_definitions_to_targets<'db>(
|
||||
db: &'db dyn ty_python_semantic::Db,
|
||||
definitions: Vec<ty_python_semantic::ResolvedDefinition<'db>>,
|
||||
definitions: Vec<ty_python_types::ResolvedDefinition<'db>>,
|
||||
) -> Vec<crate::NavigationTarget> {
|
||||
definitions
|
||||
.into_iter()
|
||||
.map(|resolved_definition| match resolved_definition {
|
||||
ty_python_semantic::ResolvedDefinition::Definition(definition) => {
|
||||
ty_python_types::ResolvedDefinition::Definition(definition) => {
|
||||
// Get the parsed module for range calculation
|
||||
let definition_file = definition.file(db);
|
||||
let module = ruff_db::parsed::parsed_module(db, definition_file).load(db);
|
||||
@@ -959,11 +958,11 @@ fn convert_resolved_definitions_to_targets<'db>(
|
||||
full_range: full_range.range(),
|
||||
}
|
||||
}
|
||||
ty_python_semantic::ResolvedDefinition::Module(file) => {
|
||||
ty_python_types::ResolvedDefinition::Module(file) => {
|
||||
// For modules, navigate to the start of the file
|
||||
crate::NavigationTarget::new(file, TextRange::default())
|
||||
}
|
||||
ty_python_semantic::ResolvedDefinition::FileWithRange(file_range) => {
|
||||
ty_python_types::ResolvedDefinition::FileWithRange(file_range) => {
|
||||
// For file ranges, navigate to the specific range within the file
|
||||
crate::NavigationTarget::from(file_range)
|
||||
}
|
||||
@@ -984,9 +983,9 @@ fn definitions_for_expression<'db>(
|
||||
expression.into(),
|
||||
alias_resolution,
|
||||
)),
|
||||
ast::ExprRef::Attribute(attribute) => Some(ty_python_semantic::definitions_for_attribute(
|
||||
model, attribute,
|
||||
)),
|
||||
ast::ExprRef::Attribute(attribute) => {
|
||||
Some(ty_python_types::definitions_for_attribute(model, attribute))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -1007,7 +1006,7 @@ fn definitions_for_callable<'db>(
|
||||
fn definitions_to_navigation_targets<'db>(
|
||||
db: &dyn ty_python_semantic::Db,
|
||||
stub_mapper: Option<&StubMapper<'db>>,
|
||||
mut definitions: Vec<ty_python_semantic::ResolvedDefinition<'db>>,
|
||||
mut definitions: Vec<ty_python_types::ResolvedDefinition<'db>>,
|
||||
) -> Option<crate::NavigationTargets> {
|
||||
if let Some(mapper) = stub_mapper {
|
||||
definitions = mapper.map_definitions(definitions);
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{Db, NavigationTargets, RangedValue};
|
||||
use ruff_db::files::{File, FileRange};
|
||||
use ruff_db::parsed::parsed_module;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
use ty_python_semantic::{ImportAliasResolution, SemanticModel};
|
||||
use ty_python_types::{ImportAliasResolution, SemanticModel};
|
||||
|
||||
/// Navigate to the declaration of a symbol.
|
||||
///
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{Db, NavigationTargets, RangedValue};
|
||||
use ruff_db::files::{File, FileRange};
|
||||
use ruff_db::parsed::parsed_module;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
use ty_python_semantic::{ImportAliasResolution, SemanticModel};
|
||||
use ty_python_types::{ImportAliasResolution, SemanticModel};
|
||||
|
||||
/// Navigate to the definition of a symbol.
|
||||
///
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{Db, HasNavigationTargets, NavigationTargets, RangedValue};
|
||||
use ruff_db::files::{File, FileRange};
|
||||
use ruff_db::parsed::parsed_module;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
use ty_python_semantic::SemanticModel;
|
||||
use ty_python_types::SemanticModel;
|
||||
|
||||
pub fn goto_type_definition(
|
||||
db: &dyn Db,
|
||||
|
||||
@@ -6,8 +6,8 @@ use ruff_db::parsed::parsed_module;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
use std::fmt;
|
||||
use std::fmt::Formatter;
|
||||
use ty_python_semantic::types::{KnownInstanceType, Type, TypeVarVariance};
|
||||
use ty_python_semantic::{DisplaySettings, SemanticModel};
|
||||
use ty_python_types::types::{KnownInstanceType, Type, TypeVarVariance};
|
||||
use ty_python_types::{DisplaySettings, SemanticModel};
|
||||
|
||||
pub fn hover(db: &dyn Db, file: File, offset: TextSize) -> Option<RangedValue<Hover<'_>>> {
|
||||
let parsed = parsed_module(db, file).load(db);
|
||||
@@ -23,7 +23,7 @@ pub fn hover(db: &dyn Db, file: File, offset: TextSize) -> Option<RangedValue<Ho
|
||||
let docs = goto_target
|
||||
.get_definition_targets(
|
||||
&model,
|
||||
ty_python_semantic::ImportAliasResolution::ResolveAliases,
|
||||
ty_python_types::ImportAliasResolution::ResolveAliases,
|
||||
)
|
||||
.and_then(|definitions| definitions.docstring(db))
|
||||
.map(HoverContent::Docstring);
|
||||
|
||||
@@ -32,8 +32,8 @@ use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
use ty_module_resolver::ModuleName;
|
||||
use ty_project::Db;
|
||||
use ty_python_semantic::semantic_index::definition::DefinitionKind;
|
||||
use ty_python_semantic::types::Type;
|
||||
use ty_python_semantic::{MemberDefinition, SemanticModel};
|
||||
use ty_python_types::types::Type;
|
||||
use ty_python_types::{MemberDefinition, SemanticModel};
|
||||
|
||||
pub(crate) struct Importer<'a> {
|
||||
/// The ty Salsa database.
|
||||
@@ -883,9 +883,8 @@ mod tests {
|
||||
use ruff_text_size::TextSize;
|
||||
use ty_module_resolver::SearchPathSettings;
|
||||
use ty_project::ProjectMetadata;
|
||||
use ty_python_semantic::{
|
||||
Program, ProgramSettings, PythonPlatform, PythonVersionWithSource, SemanticModel,
|
||||
};
|
||||
use ty_python_semantic::{Program, ProgramSettings, PythonPlatform, PythonVersionWithSource};
|
||||
use ty_python_types::SemanticModel;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ use ruff_db::parsed::parsed_module;
|
||||
use ruff_python_ast::visitor::source_order::{self, SourceOrderVisitor, TraversalSignal};
|
||||
use ruff_python_ast::{AnyNodeRef, ArgOrKeyword, Expr, ExprUnaryOp, Stmt, UnaryOp};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
use ty_python_semantic::types::ide_support::inlay_hint_call_argument_details;
|
||||
use ty_python_semantic::types::{Type, TypeDetail};
|
||||
use ty_python_semantic::{HasType, SemanticModel};
|
||||
use ty_python_types::types::ide_support::inlay_hint_call_argument_details;
|
||||
use ty_python_types::types::{Type, TypeDetail};
|
||||
use ty_python_types::{HasType, SemanticModel};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InlayHint {
|
||||
|
||||
@@ -57,7 +57,7 @@ use ruff_text_size::{Ranged, TextRange};
|
||||
use rustc_hash::FxHashSet;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use ty_project::Db;
|
||||
use ty_python_semantic::types::{Type, TypeDefinition};
|
||||
use ty_python_types::types::{Type, TypeDefinition};
|
||||
|
||||
/// Information associated with a text range.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
|
||||
@@ -20,7 +20,7 @@ use ruff_python_ast::{
|
||||
visitor::source_order::{SourceOrderVisitor, TraversalSignal},
|
||||
};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
use ty_python_semantic::{ImportAliasResolution, SemanticModel};
|
||||
use ty_python_types::{ImportAliasResolution, SemanticModel};
|
||||
|
||||
/// Mode for references search behavior
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::references::{ReferencesMode, references};
|
||||
use crate::{Db, ReferenceTarget};
|
||||
use ruff_db::files::File;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
use ty_python_semantic::SemanticModel;
|
||||
use ty_python_types::SemanticModel;
|
||||
|
||||
/// Returns the range of the symbol if it can be renamed, None if not.
|
||||
pub fn can_rename(db: &dyn Db, file: File, offset: TextSize) -> Option<ruff_text_size::TextRange> {
|
||||
|
||||
@@ -44,10 +44,10 @@ use ruff_python_ast::{
|
||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||
use std::ops::Deref;
|
||||
use ty_python_semantic::semantic_index::definition::Definition;
|
||||
use ty_python_semantic::types::TypeVarKind;
|
||||
use ty_python_semantic::{
|
||||
HasType, SemanticModel, semantic_index::definition::DefinitionKind, types::Type,
|
||||
types::ide_support::definition_for_name,
|
||||
use ty_python_semantic::semantic_index::definition::DefinitionKind;
|
||||
use ty_python_types::types::TypeVarKind;
|
||||
use ty_python_types::{
|
||||
HasType, SemanticModel, types::Type, types::ide_support::definition_for_name,
|
||||
};
|
||||
|
||||
/// Semantic token types supported by the language server.
|
||||
@@ -272,7 +272,7 @@ impl<'db> SemanticTokenVisitor<'db> {
|
||||
let definition = definition_for_name(
|
||||
self.model,
|
||||
name,
|
||||
ty_python_semantic::ImportAliasResolution::ResolveAliases,
|
||||
ty_python_types::ImportAliasResolution::ResolveAliases,
|
||||
);
|
||||
|
||||
if let Some(definition) = definition {
|
||||
|
||||
@@ -15,13 +15,13 @@ use ruff_python_ast::find_node::covering_node;
|
||||
use ruff_python_ast::token::TokenKind;
|
||||
use ruff_python_ast::{self as ast, AnyNodeRef};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
use ty_python_semantic::ResolvedDefinition;
|
||||
use ty_python_semantic::SemanticModel;
|
||||
use ty_python_semantic::semantic_index::definition::Definition;
|
||||
use ty_python_semantic::types::ide_support::{
|
||||
use ty_python_types::ResolvedDefinition;
|
||||
use ty_python_types::SemanticModel;
|
||||
use ty_python_types::types::ide_support::{
|
||||
CallSignatureDetails, call_signature_details, find_active_signature_from_details,
|
||||
};
|
||||
use ty_python_semantic::types::{ParameterKind, Type};
|
||||
use ty_python_types::types::{ParameterKind, Type};
|
||||
|
||||
// TODO: We may want to add special-case handling for calls to constructors
|
||||
// so the class docstring is used in place of (or inaddition to) any docstring
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use itertools::Either;
|
||||
use ruff_db::system::SystemPathBuf;
|
||||
use ty_python_semantic::{ResolvedDefinition, map_stub_definition};
|
||||
use ty_python_types::{ResolvedDefinition, map_stub_definition};
|
||||
|
||||
use crate::cached_vendored_root;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ ruff_text_size = { workspace = true }
|
||||
ty_combine = { workspace = true }
|
||||
ty_module_resolver = { workspace = true }
|
||||
ty_python_semantic = { workspace = true, features = ["serde"] }
|
||||
ty_python_types = { workspace = true }
|
||||
ty_static = { workspace = true }
|
||||
ty_vendored = { workspace = true }
|
||||
|
||||
|
||||
@@ -467,7 +467,7 @@ impl SemanticDb for ProjectDatabase {
|
||||
}
|
||||
|
||||
fn lint_registry(&self) -> &LintRegistry {
|
||||
ty_python_semantic::default_lint_registry()
|
||||
ty_python_types::default_lint_registry()
|
||||
}
|
||||
|
||||
fn analysis_settings(&self) -> &AnalysisSettings {
|
||||
@@ -658,7 +658,7 @@ pub(crate) mod tests {
|
||||
}
|
||||
|
||||
fn lint_registry(&self) -> &LintRegistry {
|
||||
ty_python_semantic::default_lint_registry()
|
||||
ty_python_types::default_lint_registry()
|
||||
}
|
||||
|
||||
fn analysis_settings(&self) -> &AnalysisSettings {
|
||||
|
||||
@@ -29,7 +29,7 @@ use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
use ty_python_semantic::add_inferred_python_version_hint_to_diagnostic;
|
||||
use ty_python_semantic::lint::RuleSelection;
|
||||
use ty_python_semantic::types::check_types;
|
||||
use ty_python_types::types::check_types;
|
||||
|
||||
mod db;
|
||||
mod files;
|
||||
@@ -769,7 +769,7 @@ mod tests {
|
||||
use ruff_db::system::{DbWithTestSystem, DbWithWritableSystem as _, SystemPath, SystemPathBuf};
|
||||
use ruff_db::testing::assert_function_query_was_not_run;
|
||||
use ruff_python_ast::name::Name;
|
||||
use ty_python_semantic::types::check_types;
|
||||
use ty_python_types::types::check_types;
|
||||
|
||||
#[test]
|
||||
fn check_file_skips_type_checking_when_file_cant_be_read() -> ruff_db::system::Result<()> {
|
||||
|
||||
@@ -1666,7 +1666,7 @@ mod schema {
|
||||
fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
let registry = ty_python_semantic::default_lint_registry();
|
||||
let registry = ty_python_types::default_lint_registry();
|
||||
let level_schema = generator.subschema_for::<super::Level>();
|
||||
|
||||
let properties: Map<String, Value> = registry
|
||||
|
||||
@@ -19,10 +19,8 @@ ruff_macros = { workspace = true }
|
||||
ruff_memory_usage = { workspace = true }
|
||||
ruff_python_ast = { workspace = true, features = ["salsa"] }
|
||||
ruff_python_parser = { workspace = true }
|
||||
ruff_python_stdlib = { workspace = true }
|
||||
ruff_source_file = { workspace = true }
|
||||
ruff_text_size = { workspace = true }
|
||||
ruff_python_literal = { workspace = true }
|
||||
ruff_python_trivia = { workspace = true }
|
||||
ty_module_resolver = { workspace = true }
|
||||
ty_combine = { workspace = true }
|
||||
@@ -33,8 +31,6 @@ bitflags = { workspace = true }
|
||||
bitvec = { workspace = true }
|
||||
camino = { workspace = true }
|
||||
colored = { workspace = true }
|
||||
compact_str = { workspace = true }
|
||||
drop_bomb = { workspace = true }
|
||||
get-size2 = { workspace = true, features = ["indexmap", "ordermap"] }
|
||||
indexmap = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
@@ -48,9 +44,8 @@ schemars = { workspace = true, optional = true }
|
||||
serde = { workspace = true, optional = true }
|
||||
serde_json = { workspace = true, optional = true }
|
||||
smallvec = { workspace = true }
|
||||
ty_vendored = { workspace = true, optional = true }
|
||||
static_assertions = { workspace = true }
|
||||
test-case = { workspace = true }
|
||||
memchr = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
strsim = "0.11.1"
|
||||
@@ -58,27 +53,19 @@ strsim = "0.11.1"
|
||||
[dev-dependencies]
|
||||
ruff_db = { workspace = true, features = ["testing", "os"] }
|
||||
ruff_python_parser = { workspace = true }
|
||||
ty_static = { workspace = true }
|
||||
ty_test = { workspace = true }
|
||||
ty_vendored = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
datatest-stable = { workspace = true }
|
||||
glob = { workspace = true }
|
||||
indoc = { workspace = true }
|
||||
insta = { workspace = true }
|
||||
pretty_assertions = { workspace = true }
|
||||
quickcheck = { version = "1.0.3", default-features = false }
|
||||
quickcheck_macros = { version = "1.0.0" }
|
||||
|
||||
[features]
|
||||
schemars = ["dep:schemars", "dep:serde_json"]
|
||||
serde = ["ruff_db/serde", "dep:serde", "ruff_python_ast/serde"]
|
||||
testing = []
|
||||
|
||||
[[test]]
|
||||
name = "mdtest"
|
||||
harness = false
|
||||
testing = ["dep:ty_vendored", "ruff_db/testing"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.cargo-shear]
|
||||
# Used via macro expansion.
|
||||
ignored = ["quickcheck"]
|
||||
|
||||
@@ -20,19 +20,19 @@ pub trait Db: ModuleResolverDb {
|
||||
fn verbose(&self) -> bool;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
#[cfg(any(test, feature = "testing"))]
|
||||
pub mod tests {
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::program::Program;
|
||||
use crate::{
|
||||
AnalysisSettings, ProgramSettings, PythonPlatform, PythonVersionSource,
|
||||
PythonVersionWithSource, default_lint_registry,
|
||||
PythonVersionWithSource,
|
||||
};
|
||||
use ty_module_resolver::SearchPathSettings;
|
||||
|
||||
use super::Db;
|
||||
use crate::lint::{LintRegistry, RuleSelection};
|
||||
use crate::lint::{LintRegistry, LintRegistryBuilder, RuleSelection};
|
||||
use anyhow::Context;
|
||||
use ruff_db::Db as SourceDb;
|
||||
use ruff_db::files::{File, Files};
|
||||
@@ -46,21 +46,44 @@ pub(crate) mod tests {
|
||||
|
||||
type Events = Arc<Mutex<Vec<salsa::Event>>>;
|
||||
|
||||
/// A default lint registry containing only the suppression lints.
|
||||
/// Full lint registry should be obtained from `ty_python_types`.
|
||||
fn test_lint_registry() -> &'static LintRegistry {
|
||||
static REGISTRY: std::sync::LazyLock<LintRegistry> = std::sync::LazyLock::new(|| {
|
||||
let mut builder = LintRegistryBuilder::default();
|
||||
crate::register_suppression_lints(&mut builder);
|
||||
builder.build()
|
||||
});
|
||||
®ISTRY
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct TestDb {
|
||||
pub struct TestDb {
|
||||
storage: salsa::Storage<Self>,
|
||||
files: Files,
|
||||
system: TestSystem,
|
||||
vendored: VendoredFileSystem,
|
||||
events: Events,
|
||||
rule_selection: Arc<RuleSelection>,
|
||||
lint_registry: Arc<LintRegistry>,
|
||||
analysis_settings: Arc<AnalysisSettings>,
|
||||
}
|
||||
|
||||
impl Default for TestDb {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl TestDb {
|
||||
pub(crate) fn new() -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self::with_vendored(ty_vendored::file_system().clone())
|
||||
}
|
||||
|
||||
pub fn with_vendored(vendored: VendoredFileSystem) -> Self {
|
||||
let events = Events::default();
|
||||
let lint_registry = test_lint_registry();
|
||||
Self {
|
||||
storage: salsa::Storage::new(Some(Box::new({
|
||||
let events = events.clone();
|
||||
@@ -71,16 +94,17 @@ pub(crate) mod tests {
|
||||
}
|
||||
}))),
|
||||
system: TestSystem::default(),
|
||||
vendored: ty_vendored::file_system().clone(),
|
||||
vendored,
|
||||
events,
|
||||
files: Files::default(),
|
||||
rule_selection: Arc::new(RuleSelection::from_registry(default_lint_registry())),
|
||||
rule_selection: Arc::new(RuleSelection::from_registry(lint_registry)),
|
||||
lint_registry: Arc::new(lint_registry.clone()),
|
||||
analysis_settings: AnalysisSettings::default().into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes the salsa events.
|
||||
pub(crate) fn take_salsa_events(&mut self) -> Vec<salsa::Event> {
|
||||
pub fn take_salsa_events(&mut self) -> Vec<salsa::Event> {
|
||||
let mut events = self.events.lock().unwrap();
|
||||
|
||||
std::mem::take(&mut *events)
|
||||
@@ -90,7 +114,7 @@ pub(crate) mod tests {
|
||||
///
|
||||
/// ## Panics
|
||||
/// If there are any pending salsa snapshots.
|
||||
pub(crate) fn clear_salsa_events(&mut self) {
|
||||
pub fn clear_salsa_events(&mut self) {
|
||||
self.take_salsa_events();
|
||||
}
|
||||
}
|
||||
@@ -135,7 +159,7 @@ pub(crate) mod tests {
|
||||
}
|
||||
|
||||
fn lint_registry(&self) -> &LintRegistry {
|
||||
default_lint_registry()
|
||||
&self.lint_registry
|
||||
}
|
||||
|
||||
fn analysis_settings(&self) -> &AnalysisSettings {
|
||||
@@ -157,7 +181,7 @@ pub(crate) mod tests {
|
||||
#[salsa::db]
|
||||
impl salsa::Database for TestDb {}
|
||||
|
||||
pub(crate) struct TestDbBuilder<'a> {
|
||||
pub struct TestDbBuilder<'a> {
|
||||
/// Target Python version
|
||||
python_version: PythonVersion,
|
||||
/// Target Python platform
|
||||
@@ -166,8 +190,14 @@ pub(crate) mod tests {
|
||||
files: Vec<(&'a str, &'a str)>,
|
||||
}
|
||||
|
||||
impl Default for TestDbBuilder<'_> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TestDbBuilder<'a> {
|
||||
pub(crate) fn new() -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
python_version: PythonVersion::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
@@ -175,12 +205,14 @@ pub(crate) mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_python_version(mut self, version: PythonVersion) -> Self {
|
||||
#[must_use]
|
||||
pub fn with_python_version(mut self, version: PythonVersion) -> Self {
|
||||
self.python_version = version;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn with_file(
|
||||
#[must_use]
|
||||
pub fn with_file(
|
||||
mut self,
|
||||
path: &'a (impl AsRef<SystemPath> + ?Sized),
|
||||
content: &'a str,
|
||||
@@ -189,7 +221,7 @@ pub(crate) mod tests {
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn build(self) -> anyhow::Result<TestDb> {
|
||||
pub fn build(self) -> anyhow::Result<TestDb> {
|
||||
let mut db = TestDb::new();
|
||||
|
||||
let src_root = SystemPathBuf::from("/src");
|
||||
@@ -216,7 +248,7 @@ pub(crate) mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn setup_db() -> TestDb {
|
||||
pub fn setup_db() -> TestDb {
|
||||
TestDbBuilder::new().build().expect("valid TestDb setup")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
Db, Program, PythonVersionWithSource, lint::lint_documentation_url, types::TypeCheckDiagnostics,
|
||||
Db, Program, PythonVersionWithSource, lint::lint_documentation_url,
|
||||
suppression::TypeCheckDiagnostics,
|
||||
};
|
||||
use ruff_db::{
|
||||
diagnostic::{Annotation, Diagnostic, DiagnosticId, SubDiagnostic, SubDiagnosticSeverity},
|
||||
@@ -9,7 +10,7 @@ use std::cell::RefCell;
|
||||
use std::fmt::Write;
|
||||
|
||||
/// Suggest a name from `existing_names` that is similar to `wrong_name`.
|
||||
pub(crate) fn did_you_mean<S: AsRef<str>, T: AsRef<str>>(
|
||||
pub fn did_you_mean<S: AsRef<str>, T: AsRef<str>>(
|
||||
existing_names: impl Iterator<Item = S>,
|
||||
wrong_name: T,
|
||||
) -> Option<String> {
|
||||
@@ -127,7 +128,7 @@ pub fn add_inferred_python_version_hint_to_diagnostic(
|
||||
/// Format a list of elements as a human-readable enumeration.
|
||||
///
|
||||
/// Encloses every element in backticks (`1`, `2` and `3`).
|
||||
pub(crate) fn format_enumeration<I, IT, D>(elements: I) -> String
|
||||
pub fn format_enumeration<I, IT, D>(elements: I) -> String
|
||||
where
|
||||
I: IntoIterator<IntoIter = IT>,
|
||||
IT: ExactSizeIterator<Item = D> + DoubleEndedIterator,
|
||||
@@ -160,7 +161,7 @@ where
|
||||
/// associated file is equivalent to the file being type checked. As a result,
|
||||
/// if either is violated, then the `Drop` impl on `DiagnosticGuard` will
|
||||
/// panic.
|
||||
pub(super) struct DiagnosticGuard<'sink> {
|
||||
pub struct DiagnosticGuard<'sink> {
|
||||
/// The file of the primary span (to which file does this diagnostic belong).
|
||||
file: File,
|
||||
|
||||
@@ -187,7 +188,7 @@ pub(super) struct DiagnosticGuard<'sink> {
|
||||
}
|
||||
|
||||
impl<'sink> DiagnosticGuard<'sink> {
|
||||
pub(crate) fn new(
|
||||
pub fn new(
|
||||
file: File,
|
||||
sink: &'sink std::cell::RefCell<TypeCheckDiagnostics>,
|
||||
diag: Diagnostic,
|
||||
|
||||
15
crates/ty_python_semantic/src/has_tracked_scope.rs
Normal file
15
crates/ty_python_semantic/src/has_tracked_scope.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use ruff_python_ast::{self as ast, HasNodeIndex};
|
||||
|
||||
/// Implemented by types for which the semantic index tracks their scope.
|
||||
pub trait HasTrackedScope: HasNodeIndex {}
|
||||
|
||||
impl HasTrackedScope for ast::Expr {}
|
||||
|
||||
impl HasTrackedScope for ast::ExprRef<'_> {}
|
||||
impl HasTrackedScope for &ast::ExprRef<'_> {}
|
||||
|
||||
// We never explicitly register the scope of an `Identifier`.
|
||||
// However, `ExpressionsScopeMap` stores the text ranges of each scope.
|
||||
// That allows us to look up the identifier's scope for as long as it's
|
||||
// inside an expression (because the ranges overlap).
|
||||
impl HasTrackedScope for ast::Identifier {}
|
||||
@@ -4,7 +4,7 @@
|
||||
)]
|
||||
use std::hash::BuildHasherDefault;
|
||||
|
||||
use crate::lint::{LintRegistry, LintRegistryBuilder};
|
||||
use crate::lint::LintRegistryBuilder;
|
||||
use crate::suppression::{
|
||||
IGNORE_COMMENT_UNKNOWN_RULE, INVALID_IGNORE_COMMENT, UNUSED_IGNORE_COMMENT,
|
||||
};
|
||||
@@ -15,60 +15,38 @@ pub use program::{
|
||||
};
|
||||
pub use python_platform::PythonPlatform;
|
||||
use rustc_hash::FxHasher;
|
||||
pub use semantic_model::{
|
||||
Completion, HasDefinition, HasType, MemberDefinition, NameKind, SemanticModel,
|
||||
};
|
||||
pub use site_packages::{PythonEnvironment, SitePackagesPaths, SysPrefixPathOrigin};
|
||||
pub use suppression::create_suppression_fix;
|
||||
pub use suppression::{FileSuppressionId, TypeCheckDiagnostics, create_suppression_fix};
|
||||
pub use ty_module_resolver::MisconfigurationMode;
|
||||
pub use types::DisplaySettings;
|
||||
pub use types::ide_support::{
|
||||
ImportAliasResolution, ResolvedDefinition, definitions_for_attribute, definitions_for_bin_op,
|
||||
definitions_for_imported_symbol, definitions_for_name, definitions_for_unary_op,
|
||||
map_stub_definition,
|
||||
};
|
||||
|
||||
pub mod ast_node_ref;
|
||||
mod db;
|
||||
mod dunder_all;
|
||||
pub mod db;
|
||||
pub(crate) mod has_tracked_scope;
|
||||
pub mod lint;
|
||||
pub(crate) mod list;
|
||||
mod node_key;
|
||||
pub(crate) mod place;
|
||||
pub mod list;
|
||||
pub mod node_key;
|
||||
pub mod place_qualifiers;
|
||||
mod program;
|
||||
mod python_platform;
|
||||
mod rank;
|
||||
pub mod rank;
|
||||
pub mod semantic_index;
|
||||
mod semantic_model;
|
||||
pub(crate) mod site_packages;
|
||||
mod subscript;
|
||||
mod suppression;
|
||||
pub mod types;
|
||||
mod unpack;
|
||||
pub mod subscript;
|
||||
pub mod suppression;
|
||||
mod truthiness;
|
||||
pub mod unpack;
|
||||
|
||||
mod diagnostic;
|
||||
#[cfg(feature = "testing")]
|
||||
pub mod pull_types;
|
||||
pub use truthiness::Truthiness;
|
||||
|
||||
type FxOrderMap<K, V> = ordermap::map::OrderMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||
type FxOrderSet<V> = ordermap::set::OrderSet<V, BuildHasherDefault<FxHasher>>;
|
||||
type FxIndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||
type FxIndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
|
||||
pub mod diagnostic;
|
||||
|
||||
/// Returns the default registry with all known semantic lints.
|
||||
pub fn default_lint_registry() -> &'static LintRegistry {
|
||||
static REGISTRY: std::sync::LazyLock<LintRegistry> = std::sync::LazyLock::new(|| {
|
||||
let mut registry = LintRegistryBuilder::default();
|
||||
register_lints(&mut registry);
|
||||
registry.build()
|
||||
});
|
||||
pub type FxOrderMap<K, V> = ordermap::map::OrderMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||
pub type FxOrderSet<V> = ordermap::set::OrderSet<V, BuildHasherDefault<FxHasher>>;
|
||||
pub type FxIndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||
pub type FxIndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
|
||||
|
||||
®ISTRY
|
||||
}
|
||||
|
||||
/// Register all known semantic lints.
|
||||
pub fn register_lints(registry: &mut LintRegistryBuilder) {
|
||||
types::register_lints(registry);
|
||||
/// Register suppression-related lints (used by `ty_python_types` to build the full registry).
|
||||
pub fn register_suppression_lints(registry: &mut LintRegistryBuilder) {
|
||||
registry.register_lint(&UNUSED_IGNORE_COMMENT);
|
||||
registry.register_lint(&IGNORE_COMMENT_UNKNOWN_RULE);
|
||||
registry.register_lint(&INVALID_IGNORE_COMMENT);
|
||||
|
||||
@@ -70,7 +70,7 @@ use ruff_index::{IndexVec, newtype_index};
|
||||
/// A handle to an association list. Use [`ListStorage`] to access its elements, and
|
||||
/// [`ListBuilder`] to construct other lists based on this one.
|
||||
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, get_size2::GetSize)]
|
||||
pub(crate) struct List<K, V = ()> {
|
||||
pub struct List<K, V = ()> {
|
||||
last: Option<ListCellId>,
|
||||
_phantom: PhantomData<(K, V)>,
|
||||
}
|
||||
|
||||
@@ -4,17 +4,17 @@ use crate::ast_node_ref::AstNodeRef;
|
||||
|
||||
/// Compact key for a node for use in a hash map.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
|
||||
pub(super) struct NodeKey(NodeIndex);
|
||||
pub struct NodeKey(NodeIndex);
|
||||
|
||||
impl NodeKey {
|
||||
pub(super) fn from_node<N>(node: N) -> Self
|
||||
pub fn from_node<N>(node: N) -> Self
|
||||
where
|
||||
N: HasNodeIndex,
|
||||
{
|
||||
NodeKey(node.node_index().load())
|
||||
}
|
||||
|
||||
pub(super) fn from_node_ref<T>(node_ref: &AstNodeRef<T>) -> Self {
|
||||
pub fn from_node_ref<T>(node_ref: &AstNodeRef<T>) -> Self {
|
||||
NodeKey(node_ref.index())
|
||||
}
|
||||
}
|
||||
|
||||
70
crates/ty_python_semantic/src/place_qualifiers.rs
Normal file
70
crates/ty_python_semantic/src/place_qualifiers.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
//! Place qualifier enums that are used by both semantic and type analysis.
|
||||
//!
|
||||
//! These simple enums don't depend on type information and are used by
|
||||
//! `use_def.rs` and other semantic index components.
|
||||
|
||||
/// Specifies how the boundness of a place should be determined.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, salsa::Update)]
|
||||
pub enum BoundnessAnalysis {
|
||||
/// The place is always considered bound.
|
||||
AssumeBound,
|
||||
/// The boundness of the place is determined based on the visibility of the implicit
|
||||
/// `unbound` binding. In the example below, when analyzing the visibility of the
|
||||
/// `x = <unbound>` binding from the position of the end of the scope, it would be
|
||||
/// `Truthiness::Ambiguous`, because it could either be visible or not, depending on the
|
||||
/// `flag()` return value. This would result in a `Definedness::PossiblyUndefined` for `x`.
|
||||
///
|
||||
/// ```py
|
||||
/// x = <unbound>
|
||||
///
|
||||
/// if flag():
|
||||
/// x = 1
|
||||
/// ```
|
||||
BasedOnUnboundVisibility,
|
||||
}
|
||||
|
||||
/// Specifies whether a place is always defined or might be undefined.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
|
||||
pub enum Definedness {
|
||||
/// The place is always defined at this point.
|
||||
AlwaysDefined,
|
||||
/// The place might or might not be defined at this point.
|
||||
PossiblyUndefined,
|
||||
}
|
||||
|
||||
/// Specifies how a type was determined.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Default, get_size2::GetSize)]
|
||||
pub enum TypeOrigin {
|
||||
/// The type was explicitly declared.
|
||||
Declared,
|
||||
/// The type was inferred from bindings.
|
||||
#[default]
|
||||
Inferred,
|
||||
}
|
||||
|
||||
/// Specifies whether to widen the type with `Unknown`.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Default, get_size2::GetSize)]
|
||||
pub enum Widening {
|
||||
/// Don't widen the type.
|
||||
#[default]
|
||||
None,
|
||||
/// Widen the type with `Unknown` to handle undefined bindings.
|
||||
WithUnknown,
|
||||
}
|
||||
|
||||
/// Specifies whether a re-export requires explicit `__all__` inclusion.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum RequiresExplicitReExport {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
/// Specifies which definitions to consider when looking up a place.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Default)]
|
||||
pub enum ConsideredDefinitions {
|
||||
/// Consider all reachable definitions at a specific use.
|
||||
AllReachable,
|
||||
/// Consider definitions visible at the end of the scope.
|
||||
#[default]
|
||||
EndOfScope,
|
||||
}
|
||||
@@ -24,7 +24,7 @@ use get_size2::GetSize;
|
||||
/// This trick adds O(1.5) bits of overhead per large vector element on 64-bit platforms, and O(2)
|
||||
/// bits of overhead on 32-bit platforms.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, GetSize)]
|
||||
pub(crate) struct RankBitBox {
|
||||
pub struct RankBitBox {
|
||||
#[get_size(size_fn = bit_box_size)]
|
||||
bits: BitBox<Chunk, Msb0>,
|
||||
chunk_ranks: Box<[u32]>,
|
||||
@@ -58,13 +58,13 @@ impl RankBitBox {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn get_bit(&self, index: usize) -> Option<bool> {
|
||||
pub fn get_bit(&self, index: usize) -> Option<bool> {
|
||||
self.bits.get(index).map(|bit| *bit)
|
||||
}
|
||||
|
||||
/// Returns the number of bits _before_ (and not including) the given index that are set.
|
||||
#[inline]
|
||||
pub(crate) fn rank(&self, index: usize) -> u32 {
|
||||
pub fn rank(&self, index: usize) -> u32 {
|
||||
let chunk_index = index / CHUNK_SIZE;
|
||||
let index_within_chunk = index % CHUNK_SIZE;
|
||||
let chunk_rank = self.chunk_ranks[chunk_index];
|
||||
|
||||
@@ -12,7 +12,7 @@ use salsa::plumbing::AsId;
|
||||
use ty_module_resolver::ModuleName;
|
||||
|
||||
use crate::Db;
|
||||
use crate::node_key::NodeKey;
|
||||
use crate::has_tracked_scope::HasTrackedScope;
|
||||
use crate::semantic_index::ast_ids::AstIds;
|
||||
use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey;
|
||||
use crate::semantic_index::builder::SemanticIndexBuilder;
|
||||
@@ -26,23 +26,22 @@ use crate::semantic_index::scope::{
|
||||
};
|
||||
use crate::semantic_index::symbol::ScopedSymbolId;
|
||||
use crate::semantic_index::use_def::{EnclosingSnapshotKey, ScopedEnclosingSnapshotId, UseDefMap};
|
||||
use crate::semantic_model::HasTrackedScope;
|
||||
|
||||
pub mod ast_ids;
|
||||
mod builder;
|
||||
pub mod definition;
|
||||
pub mod expression;
|
||||
pub(crate) mod member;
|
||||
pub(crate) mod narrowing_constraints;
|
||||
pub mod member;
|
||||
pub mod narrowing_constraints;
|
||||
pub mod place;
|
||||
pub(crate) mod predicate;
|
||||
pub mod predicate;
|
||||
mod re_exports;
|
||||
mod reachability_constraints;
|
||||
pub(crate) mod scope;
|
||||
pub(crate) mod symbol;
|
||||
mod use_def;
|
||||
pub mod reachability_constraints;
|
||||
pub mod scope;
|
||||
pub mod symbol;
|
||||
pub mod use_def;
|
||||
|
||||
pub(crate) use self::use_def::{
|
||||
pub use self::use_def::{
|
||||
ApplicableConstraints, BindingWithConstraints, BindingWithConstraintsIterator,
|
||||
DeclarationWithConstraint, DeclarationsIterator,
|
||||
};
|
||||
@@ -51,7 +50,7 @@ pub(crate) use self::use_def::{
|
||||
///
|
||||
/// Prefer using [`symbol_table`] when working with symbols from a single scope.
|
||||
#[salsa::tracked(returns(ref), no_eq, heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) fn semantic_index(db: &dyn Db, file: File) -> SemanticIndex<'_> {
|
||||
pub fn semantic_index(db: &dyn Db, file: File) -> SemanticIndex<'_> {
|
||||
let _span = tracing::trace_span!("semantic_index", ?file).entered();
|
||||
|
||||
let module = parsed_module(db, file).load(db);
|
||||
@@ -65,7 +64,7 @@ pub(crate) fn semantic_index(db: &dyn Db, file: File) -> SemanticIndex<'_> {
|
||||
/// Salsa can avoid invalidating dependent queries if this scope's place table
|
||||
/// is unchanged.
|
||||
#[salsa::tracked(returns(deref), heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) fn place_table<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc<PlaceTable> {
|
||||
pub fn place_table<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc<PlaceTable> {
|
||||
let file = scope.file(db);
|
||||
let _span = tracing::trace_span!("place_table", scope=?scope.as_id(), ?file).entered();
|
||||
let index = semantic_index(db, file);
|
||||
@@ -78,7 +77,7 @@ pub(crate) fn place_table<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc<Plac
|
||||
/// See [`ModuleLiteralType::available_submodule_attributes`] for discussion
|
||||
/// of why this analysis is intentionally limited.
|
||||
#[salsa::tracked(returns(deref), heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) fn imported_modules<'db>(db: &'db dyn Db, file: File) -> Arc<FxHashSet<ModuleName>> {
|
||||
pub fn imported_modules<'db>(db: &'db dyn Db, file: File) -> Arc<FxHashSet<ModuleName>> {
|
||||
semantic_index(db, file).imported_modules.clone()
|
||||
}
|
||||
|
||||
@@ -88,7 +87,7 @@ pub(crate) fn imported_modules<'db>(db: &'db dyn Db, file: File) -> Arc<FxHashSe
|
||||
/// Salsa can avoid invalidating dependent queries if this scope's use-def map
|
||||
/// is unchanged.
|
||||
#[salsa::tracked(returns(deref), heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) fn use_def_map<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc<UseDefMap<'db>> {
|
||||
pub fn use_def_map<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc<UseDefMap<'db>> {
|
||||
let file = scope.file(db);
|
||||
let _span = tracing::trace_span!("use_def_map", scope=?scope.as_id(), ?file).entered();
|
||||
let index = semantic_index(db, file);
|
||||
@@ -100,7 +99,7 @@ pub(crate) fn use_def_map<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc<UseD
|
||||
///
|
||||
/// Only call this when doing type inference on the same file as `class_body_scope`, otherwise it
|
||||
/// introduces a direct dependency on that file's AST.
|
||||
pub(crate) fn attribute_assignments<'db, 's>(
|
||||
pub fn attribute_assignments<'db, 's>(
|
||||
db: &'db dyn Db,
|
||||
class_body_scope: ScopeId<'db>,
|
||||
name: &'s str,
|
||||
@@ -121,7 +120,7 @@ pub(crate) fn attribute_assignments<'db, 's>(
|
||||
///
|
||||
/// Only call this when doing type inference on the same file as `class_body_scope`, otherwise it
|
||||
/// introduces a direct dependency on that file's AST.
|
||||
pub(crate) fn attribute_declarations<'db, 's>(
|
||||
pub fn attribute_declarations<'db, 's>(
|
||||
db: &'db dyn Db,
|
||||
class_body_scope: ScopeId<'db>,
|
||||
name: &'s str,
|
||||
@@ -144,7 +143,7 @@ pub(crate) fn attribute_declarations<'db, 's>(
|
||||
///
|
||||
/// Only call this when doing type inference on the same file as `class_body_scope`, otherwise it
|
||||
/// introduces a direct dependency on that file's AST.
|
||||
pub(crate) fn attribute_scopes<'db>(
|
||||
pub fn attribute_scopes<'db>(
|
||||
db: &'db dyn Db,
|
||||
class_body_scope: ScopeId<'db>,
|
||||
) -> impl Iterator<Item = FileScopeId> + 'db {
|
||||
@@ -198,13 +197,13 @@ pub(crate) fn attribute_scopes<'db>(
|
||||
|
||||
/// Returns the module global scope of `file`.
|
||||
#[salsa::tracked(heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) fn global_scope(db: &dyn Db, file: File) -> ScopeId<'_> {
|
||||
pub fn global_scope(db: &dyn Db, file: File) -> ScopeId<'_> {
|
||||
let _span = tracing::trace_span!("global_scope", ?file).entered();
|
||||
|
||||
FileScopeId::global().to_scope_id(db, file)
|
||||
}
|
||||
|
||||
pub(crate) enum EnclosingSnapshotResult<'map, 'db> {
|
||||
pub enum EnclosingSnapshotResult<'map, 'db> {
|
||||
FoundConstraint(ScopedNarrowingConstraint),
|
||||
FoundBindings(BindingWithConstraintsIterator<'map, 'db>),
|
||||
NotFound,
|
||||
@@ -213,7 +212,7 @@ pub(crate) enum EnclosingSnapshotResult<'map, 'db> {
|
||||
|
||||
/// The place tables and use-def maps for all scopes in a file.
|
||||
#[derive(Debug, Update, get_size2::GetSize)]
|
||||
pub(crate) struct SemanticIndex<'db> {
|
||||
pub struct SemanticIndex<'db> {
|
||||
/// List of all place tables in this file, indexed by scope.
|
||||
place_tables: IndexVec<FileScopeId, Arc<PlaceTable>>,
|
||||
|
||||
@@ -266,7 +265,7 @@ impl<'db> SemanticIndex<'db> {
|
||||
/// Use the Salsa cached [`place_table()`] query if you only need the
|
||||
/// place table for a single scope.
|
||||
#[track_caller]
|
||||
pub(super) fn place_table(&self, scope_id: FileScopeId) -> &PlaceTable {
|
||||
pub fn place_table(&self, scope_id: FileScopeId) -> &PlaceTable {
|
||||
&self.place_tables[scope_id]
|
||||
}
|
||||
|
||||
@@ -275,7 +274,7 @@ impl<'db> SemanticIndex<'db> {
|
||||
/// Use the Salsa cached [`use_def_map()`] query if you only need the
|
||||
/// use-def map for a single scope.
|
||||
#[track_caller]
|
||||
pub(super) fn use_def_map(&self, scope_id: FileScopeId) -> &UseDefMap<'db> {
|
||||
pub fn use_def_map(&self, scope_id: FileScopeId) -> &UseDefMap<'db> {
|
||||
&self.use_def_maps[scope_id]
|
||||
}
|
||||
|
||||
@@ -286,7 +285,7 @@ impl<'db> SemanticIndex<'db> {
|
||||
|
||||
/// Returns the ID of the `expression`'s enclosing scope.
|
||||
#[track_caller]
|
||||
pub(crate) fn expression_scope_id<E>(&self, expression: &E) -> FileScopeId
|
||||
pub fn expression_scope_id<E>(&self, expression: &E) -> FileScopeId
|
||||
where
|
||||
E: HasTrackedScope,
|
||||
{
|
||||
@@ -295,7 +294,7 @@ impl<'db> SemanticIndex<'db> {
|
||||
}
|
||||
|
||||
/// Returns the ID of the `expression`'s enclosing scope.
|
||||
pub(crate) fn try_expression_scope_id<E>(&self, expression: &E) -> Option<FileScopeId>
|
||||
pub fn try_expression_scope_id<E>(&self, expression: &E) -> Option<FileScopeId>
|
||||
where
|
||||
E: HasTrackedScope,
|
||||
{
|
||||
@@ -305,52 +304,44 @@ impl<'db> SemanticIndex<'db> {
|
||||
/// Returns the [`Scope`] of the `expression`'s enclosing scope.
|
||||
#[allow(unused)]
|
||||
#[track_caller]
|
||||
pub(crate) fn expression_scope(&self, expression: &impl HasTrackedScope) -> &Scope {
|
||||
pub fn expression_scope(&self, expression: &impl HasTrackedScope) -> &Scope {
|
||||
&self.scopes[self.expression_scope_id(expression)]
|
||||
}
|
||||
|
||||
/// Returns the [`Scope`] with the given id.
|
||||
#[track_caller]
|
||||
pub(crate) fn scope(&self, id: FileScopeId) -> &Scope {
|
||||
pub fn scope(&self, id: FileScopeId) -> &Scope {
|
||||
&self.scopes[id]
|
||||
}
|
||||
|
||||
pub(crate) fn scope_ids(&self) -> impl Iterator<Item = ScopeId<'db>> + '_ {
|
||||
pub fn scope_ids(&self) -> impl Iterator<Item = ScopeId<'db>> + '_ {
|
||||
self.scope_ids_by_scope.iter().copied()
|
||||
}
|
||||
|
||||
pub(crate) fn symbol_is_global_in_scope(
|
||||
&self,
|
||||
symbol: ScopedSymbolId,
|
||||
scope: FileScopeId,
|
||||
) -> bool {
|
||||
pub fn symbol_is_global_in_scope(&self, symbol: ScopedSymbolId, scope: FileScopeId) -> bool {
|
||||
self.place_table(scope).symbol(symbol).is_global()
|
||||
}
|
||||
|
||||
pub(crate) fn symbol_is_nonlocal_in_scope(
|
||||
&self,
|
||||
symbol: ScopedSymbolId,
|
||||
scope: FileScopeId,
|
||||
) -> bool {
|
||||
pub fn symbol_is_nonlocal_in_scope(&self, symbol: ScopedSymbolId, scope: FileScopeId) -> bool {
|
||||
self.place_table(scope).symbol(symbol).is_nonlocal()
|
||||
}
|
||||
|
||||
/// Returns the id of the parent scope.
|
||||
pub(crate) fn parent_scope_id(&self, scope_id: FileScopeId) -> Option<FileScopeId> {
|
||||
pub fn parent_scope_id(&self, scope_id: FileScopeId) -> Option<FileScopeId> {
|
||||
let scope = self.scope(scope_id);
|
||||
scope.parent()
|
||||
}
|
||||
|
||||
/// Returns the parent scope of `scope_id`.
|
||||
#[expect(unused)]
|
||||
#[track_caller]
|
||||
#[expect(unused)]
|
||||
pub(crate) fn parent_scope(&self, scope_id: FileScopeId) -> Option<&Scope> {
|
||||
Some(&self.scopes[self.parent_scope_id(scope_id)?])
|
||||
}
|
||||
|
||||
/// Return the [`Definition`] of the class enclosing this method, given the
|
||||
/// method's body scope, or `None` if it is not a method.
|
||||
pub(crate) fn class_definition_of_method(
|
||||
pub fn class_definition_of_method(
|
||||
&self,
|
||||
function_body_scope: FileScopeId,
|
||||
) -> Option<Definition<'db>> {
|
||||
@@ -381,55 +372,20 @@ impl<'db> SemanticIndex<'db> {
|
||||
.map(|node_ref| self.expect_single_definition(node_ref))
|
||||
}
|
||||
|
||||
fn is_scope_reachable(&self, db: &'db dyn Db, scope_id: FileScopeId) -> bool {
|
||||
self.parent_scope_id(scope_id)
|
||||
.is_none_or(|parent_scope_id| {
|
||||
if !self.is_scope_reachable(db, parent_scope_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let parent_use_def = self.use_def_map(parent_scope_id);
|
||||
let reachability = self.scope(scope_id).reachability();
|
||||
|
||||
parent_use_def.is_reachable(db, reachability)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns true if a given AST node is reachable from the start of the scope. For example,
|
||||
/// in the following code, expression `2` is reachable, but expressions `1` and `3` are not:
|
||||
/// ```py
|
||||
/// def f():
|
||||
/// x = 1
|
||||
/// if False:
|
||||
/// x # 1
|
||||
/// x # 2
|
||||
/// return
|
||||
/// x # 3
|
||||
/// ```
|
||||
pub(crate) fn is_node_reachable(
|
||||
&self,
|
||||
db: &'db dyn crate::Db,
|
||||
scope_id: FileScopeId,
|
||||
node_key: NodeKey,
|
||||
) -> bool {
|
||||
self.is_scope_reachable(db, scope_id)
|
||||
&& self.use_def_map(scope_id).is_node_reachable(db, node_key)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the descendent scopes of `scope`.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn descendent_scopes(&self, scope: FileScopeId) -> DescendantsIter<'_> {
|
||||
pub fn descendent_scopes(&self, scope: FileScopeId) -> DescendantsIter<'_> {
|
||||
DescendantsIter::new(&self.scopes, scope)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the direct child scopes of `scope`.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn child_scopes(&self, scope: FileScopeId) -> ChildrenIter<'_> {
|
||||
pub fn child_scopes(&self, scope: FileScopeId) -> ChildrenIter<'_> {
|
||||
ChildrenIter::new(&self.scopes, scope)
|
||||
}
|
||||
|
||||
/// Returns an iterator over all ancestors of `scope`, starting with `scope` itself.
|
||||
pub(crate) fn ancestor_scopes(&self, scope: FileScopeId) -> AncestorsIter<'_> {
|
||||
pub fn ancestor_scopes(&self, scope: FileScopeId) -> AncestorsIter<'_> {
|
||||
AncestorsIter::new(&self.scopes, scope)
|
||||
}
|
||||
|
||||
@@ -447,7 +403,7 @@ impl<'db> SemanticIndex<'db> {
|
||||
/// print(x) # Refers to global x=1, not class x=2
|
||||
/// ```
|
||||
/// The `method` function can see the global scope but not the class scope.
|
||||
pub(crate) fn visible_ancestor_scopes(&self, scope: FileScopeId) -> VisibleAncestorsIter<'_> {
|
||||
pub fn visible_ancestor_scopes(&self, scope: FileScopeId) -> VisibleAncestorsIter<'_> {
|
||||
VisibleAncestorsIter::new(&self.scopes, scope)
|
||||
}
|
||||
|
||||
@@ -456,10 +412,7 @@ impl<'db> SemanticIndex<'db> {
|
||||
/// There will only ever be >1 `Definition` associated with a `definition_key`
|
||||
/// if the definition is created by a wildcard (`*`) import.
|
||||
#[track_caller]
|
||||
pub(crate) fn definitions(
|
||||
&self,
|
||||
definition_key: impl Into<DefinitionNodeKey>,
|
||||
) -> &Definitions<'db> {
|
||||
pub fn definitions(&self, definition_key: impl Into<DefinitionNodeKey>) -> &Definitions<'db> {
|
||||
&self.definitions_by_node[&definition_key.into()]
|
||||
}
|
||||
|
||||
@@ -470,7 +423,7 @@ impl<'db> SemanticIndex<'db> {
|
||||
/// If the number of definitions associated with the key is not exactly 1 and
|
||||
/// the `debug_assertions` feature is enabled, this method will panic.
|
||||
#[track_caller]
|
||||
pub(crate) fn expect_single_definition(
|
||||
pub fn expect_single_definition(
|
||||
&self,
|
||||
definition_key: impl Into<DefinitionNodeKey> + std::fmt::Debug + Copy,
|
||||
) -> Definition<'db> {
|
||||
@@ -489,14 +442,11 @@ impl<'db> SemanticIndex<'db> {
|
||||
/// standalone-inferable expressions, which we call `add_standalone_expression` for in
|
||||
/// [`SemanticIndexBuilder`].
|
||||
#[track_caller]
|
||||
pub(crate) fn expression(
|
||||
&self,
|
||||
expression_key: impl Into<ExpressionNodeKey>,
|
||||
) -> Expression<'db> {
|
||||
pub fn expression(&self, expression_key: impl Into<ExpressionNodeKey>) -> Expression<'db> {
|
||||
self.expressions_by_node[&expression_key.into()]
|
||||
}
|
||||
|
||||
pub(crate) fn try_expression(
|
||||
pub fn try_expression(
|
||||
&self,
|
||||
expression_key: impl Into<ExpressionNodeKey>,
|
||||
) -> Option<Expression<'db>> {
|
||||
@@ -505,10 +455,7 @@ impl<'db> SemanticIndex<'db> {
|
||||
.copied()
|
||||
}
|
||||
|
||||
pub(crate) fn is_standalone_expression(
|
||||
&self,
|
||||
expression_key: impl Into<ExpressionNodeKey>,
|
||||
) -> bool {
|
||||
pub fn is_standalone_expression(&self, expression_key: impl Into<ExpressionNodeKey>) -> bool {
|
||||
self.expressions_by_node
|
||||
.contains_key(&expression_key.into())
|
||||
}
|
||||
@@ -517,18 +464,18 @@ impl<'db> SemanticIndex<'db> {
|
||||
/// This is different from [`definition::Definition::scope`] which
|
||||
/// returns the scope in which that definition is defined in.
|
||||
#[track_caller]
|
||||
pub(crate) fn node_scope(&self, node: NodeWithScopeRef) -> FileScopeId {
|
||||
pub fn node_scope(&self, node: NodeWithScopeRef) -> FileScopeId {
|
||||
self.scopes_by_node[&node.node_key()]
|
||||
}
|
||||
|
||||
/// Returns the id of the scope that `node` creates, if it exists.
|
||||
pub(crate) fn try_node_scope(&self, node: NodeWithScopeRef) -> Option<FileScopeId> {
|
||||
pub fn try_node_scope(&self, node: NodeWithScopeRef) -> Option<FileScopeId> {
|
||||
self.scopes_by_node.get(&node.node_key()).copied()
|
||||
}
|
||||
|
||||
/// Checks if there is an import of `__future__.annotations` in the global scope, which affects
|
||||
/// the logic for type inference.
|
||||
pub(super) fn has_future_annotations(&self) -> bool {
|
||||
pub fn has_future_annotations(&self) -> bool {
|
||||
self.has_future_annotations
|
||||
}
|
||||
|
||||
@@ -538,7 +485,7 @@ impl<'db> SemanticIndex<'db> {
|
||||
/// * an iterator of bindings for a particular nested scope reference if the bindings exist.
|
||||
/// * a narrowing constraint if there are no bindings, but there is a narrowing constraint for an enclosing scope place.
|
||||
/// * `NotFound` if the narrowing constraint / bindings do not exist in the nested scope.
|
||||
pub(crate) fn enclosing_snapshot(
|
||||
pub fn enclosing_snapshot(
|
||||
&self,
|
||||
enclosing_scope: FileScopeId,
|
||||
expr: PlaceExprRef,
|
||||
@@ -582,12 +529,12 @@ impl<'db> SemanticIndex<'db> {
|
||||
self.use_def_maps[enclosing_scope].enclosing_snapshot(*id, key.nested_laziness)
|
||||
}
|
||||
|
||||
pub(crate) fn semantic_syntax_errors(&self) -> &[SemanticSyntaxError] {
|
||||
pub fn semantic_syntax_errors(&self) -> &[SemanticSyntaxError] {
|
||||
&self.semantic_syntax_errors
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct AncestorsIter<'a> {
|
||||
pub struct AncestorsIter<'a> {
|
||||
scopes: &'a IndexSlice<FileScopeId, Scope>,
|
||||
next_id: Option<FileScopeId>,
|
||||
}
|
||||
@@ -615,7 +562,7 @@ impl<'a> Iterator for AncestorsIter<'a> {
|
||||
|
||||
impl FusedIterator for AncestorsIter<'_> {}
|
||||
|
||||
pub(crate) struct VisibleAncestorsIter<'a> {
|
||||
pub struct VisibleAncestorsIter<'a> {
|
||||
inner: AncestorsIter<'a>,
|
||||
starting_scope_kind: ScopeKind,
|
||||
yielded_count: usize,
|
||||
@@ -662,7 +609,7 @@ impl<'a> Iterator for VisibleAncestorsIter<'a> {
|
||||
|
||||
impl FusedIterator for VisibleAncestorsIter<'_> {}
|
||||
|
||||
pub(crate) struct DescendantsIter<'a> {
|
||||
pub struct DescendantsIter<'a> {
|
||||
next_id: FileScopeId,
|
||||
descendants: std::slice::Iter<'a, Scope>,
|
||||
}
|
||||
@@ -699,7 +646,7 @@ impl FusedIterator for DescendantsIter<'_> {}
|
||||
|
||||
impl ExactSizeIterator for DescendantsIter<'_> {}
|
||||
|
||||
pub(crate) struct ChildrenIter<'a> {
|
||||
pub struct ChildrenIter<'a> {
|
||||
parent: FileScopeId,
|
||||
descendants: DescendantsIter<'a>,
|
||||
}
|
||||
|
||||
@@ -110,13 +110,13 @@ impl AstIdsBuilder {
|
||||
}
|
||||
|
||||
/// Node key that can only be constructed for expressions.
|
||||
pub(crate) mod node_key {
|
||||
pub mod node_key {
|
||||
use ruff_python_ast as ast;
|
||||
|
||||
use crate::node_key::NodeKey;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) struct ExpressionNodeKey(NodeKey);
|
||||
pub struct ExpressionNodeKey(NodeKey);
|
||||
|
||||
impl From<ast::ExprRef<'_>> for ExpressionNodeKey {
|
||||
fn from(value: ast::ExprRef<'_>) -> Self {
|
||||
|
||||
@@ -18,6 +18,7 @@ use ruff_text_size::TextRange;
|
||||
use ty_module_resolver::{ModuleName, resolve_module};
|
||||
|
||||
use crate::ast_node_ref::AstNodeRef;
|
||||
use crate::has_tracked_scope::HasTrackedScope;
|
||||
use crate::node_key::NodeKey;
|
||||
use crate::semantic_index::ast_ids::AstIdsBuilder;
|
||||
use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey;
|
||||
@@ -47,7 +48,6 @@ use crate::semantic_index::use_def::{
|
||||
EnclosingSnapshotKey, FlowSnapshot, ScopedEnclosingSnapshotId, UseDefMapBuilder,
|
||||
};
|
||||
use crate::semantic_index::{ExpressionsScopeMap, SemanticIndex, VisibleAncestorsIter};
|
||||
use crate::semantic_model::HasTrackedScope;
|
||||
use crate::unpack::{EvaluationMode, Unpack, UnpackKind, UnpackPosition, UnpackValue};
|
||||
use crate::{Db, Program};
|
||||
|
||||
|
||||
@@ -35,10 +35,10 @@ pub struct Definition<'db> {
|
||||
pub file: File,
|
||||
|
||||
/// The scope in which the definition occurs.
|
||||
pub(crate) file_scope: FileScopeId,
|
||||
pub file_scope: FileScopeId,
|
||||
|
||||
/// The place ID of the definition.
|
||||
pub(crate) place: ScopedPlaceId,
|
||||
pub place: ScopedPlaceId,
|
||||
|
||||
/// WARNING: Only access this field when doing type inference for the same
|
||||
/// file as where `Definition` is defined to avoid cross-file query dependencies.
|
||||
@@ -48,14 +48,14 @@ pub struct Definition<'db> {
|
||||
pub kind: DefinitionKind<'db>,
|
||||
|
||||
/// This is a dedicated field to avoid accessing `kind` to compute this value.
|
||||
pub(crate) is_reexported: bool,
|
||||
pub is_reexported: bool,
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for Definition<'_> {}
|
||||
|
||||
impl<'db> Definition<'db> {
|
||||
pub(crate) fn scope(self, db: &'db dyn Db) -> ScopeId<'db> {
|
||||
pub fn scope(self, db: &'db dyn Db) -> ScopeId<'db> {
|
||||
self.file_scope(db).to_scope_id(db, self.file(db))
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ impl<'db> Definition<'db> {
|
||||
}
|
||||
|
||||
/// Get the module-level docstring for the given file.
|
||||
pub(crate) fn module_docstring(db: &dyn Db, file: File) -> Option<String> {
|
||||
pub fn module_docstring(db: &dyn Db, file: File) -> Option<String> {
|
||||
let module = parsed_module(db, file).load(db);
|
||||
docstring_from_body(module.suite())
|
||||
.map(|docstring_expr| docstring_expr.value.to_str().to_owned())
|
||||
@@ -204,13 +204,13 @@ pub struct Definitions<'db> {
|
||||
}
|
||||
|
||||
impl<'db> Definitions<'db> {
|
||||
pub(crate) fn single(definition: Definition<'db>) -> Self {
|
||||
pub fn single(definition: Definition<'db>) -> Self {
|
||||
Self {
|
||||
definitions: smallvec::smallvec_inline![definition],
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn push(&mut self, definition: Definition<'db>) {
|
||||
pub fn push(&mut self, definition: Definition<'db>) {
|
||||
self.definitions.push(definition);
|
||||
}
|
||||
}
|
||||
@@ -233,7 +233,7 @@ impl<'a, 'db> IntoIterator for &'a Definitions<'db> {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) enum DefinitionState<'db> {
|
||||
pub enum DefinitionState<'db> {
|
||||
Defined(Definition<'db>),
|
||||
/// Represents the implicit "unbound"/"undeclared" definition of every place.
|
||||
Undefined,
|
||||
@@ -243,17 +243,17 @@ pub(crate) enum DefinitionState<'db> {
|
||||
}
|
||||
|
||||
impl<'db> DefinitionState<'db> {
|
||||
pub(crate) fn is_defined_and(self, f: impl Fn(Definition<'db>) -> bool) -> bool {
|
||||
pub fn is_defined_and(self, f: impl Fn(Definition<'db>) -> bool) -> bool {
|
||||
matches!(self, DefinitionState::Defined(def) if f(def))
|
||||
}
|
||||
|
||||
pub(crate) fn is_undefined_or(self, f: impl Fn(Definition<'db>) -> bool) -> bool {
|
||||
pub fn is_undefined_or(self, f: impl Fn(Definition<'db>) -> bool) -> bool {
|
||||
matches!(self, DefinitionState::Undefined)
|
||||
|| matches!(self, DefinitionState::Defined(def) if f(def))
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn definition(self) -> Option<Definition<'db>> {
|
||||
pub fn definition(self) -> Option<Definition<'db>> {
|
||||
match self {
|
||||
DefinitionState::Defined(def) => Some(def),
|
||||
DefinitionState::Deleted | DefinitionState::Undefined => None,
|
||||
@@ -262,7 +262,7 @@ impl<'db> DefinitionState<'db> {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) enum DefinitionNodeRef<'ast, 'db> {
|
||||
pub enum DefinitionNodeRef<'ast, 'db> {
|
||||
Import(ImportDefinitionNodeRef<'ast>),
|
||||
ImportFrom(ImportFromDefinitionNodeRef<'ast>),
|
||||
ImportFromSubmodule(ImportFromSubmoduleDefinitionNodeRef<'ast>),
|
||||
@@ -402,85 +402,85 @@ impl<'ast> From<StarImportDefinitionNodeRef<'ast>> for DefinitionNodeRef<'ast, '
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct ImportDefinitionNodeRef<'ast> {
|
||||
pub(crate) node: &'ast ast::StmtImport,
|
||||
pub(crate) alias_index: usize,
|
||||
pub(crate) is_reexported: bool,
|
||||
pub struct ImportDefinitionNodeRef<'ast> {
|
||||
pub node: &'ast ast::StmtImport,
|
||||
pub alias_index: usize,
|
||||
pub is_reexported: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct StarImportDefinitionNodeRef<'ast> {
|
||||
pub(crate) node: &'ast ast::StmtImportFrom,
|
||||
pub(crate) symbol_id: ScopedSymbolId,
|
||||
pub struct StarImportDefinitionNodeRef<'ast> {
|
||||
pub node: &'ast ast::StmtImportFrom,
|
||||
pub symbol_id: ScopedSymbolId,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct ImportFromDefinitionNodeRef<'ast> {
|
||||
pub(crate) node: &'ast ast::StmtImportFrom,
|
||||
pub(crate) alias_index: usize,
|
||||
pub(crate) is_reexported: bool,
|
||||
pub struct ImportFromDefinitionNodeRef<'ast> {
|
||||
pub node: &'ast ast::StmtImportFrom,
|
||||
pub alias_index: usize,
|
||||
pub is_reexported: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct ImportFromSubmoduleDefinitionNodeRef<'ast> {
|
||||
pub(crate) node: &'ast ast::StmtImportFrom,
|
||||
pub struct ImportFromSubmoduleDefinitionNodeRef<'ast> {
|
||||
pub node: &'ast ast::StmtImportFrom,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct AssignmentDefinitionNodeRef<'ast, 'db> {
|
||||
pub(crate) unpack: Option<(UnpackPosition, Unpack<'db>)>,
|
||||
pub(crate) value: &'ast ast::Expr,
|
||||
pub(crate) target: &'ast ast::Expr,
|
||||
pub struct AssignmentDefinitionNodeRef<'ast, 'db> {
|
||||
pub unpack: Option<(UnpackPosition, Unpack<'db>)>,
|
||||
pub value: &'ast ast::Expr,
|
||||
pub target: &'ast ast::Expr,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct AnnotatedAssignmentDefinitionNodeRef<'ast> {
|
||||
pub(crate) node: &'ast ast::StmtAnnAssign,
|
||||
pub(crate) annotation: &'ast ast::Expr,
|
||||
pub(crate) value: Option<&'ast ast::Expr>,
|
||||
pub(crate) target: &'ast ast::Expr,
|
||||
pub struct AnnotatedAssignmentDefinitionNodeRef<'ast> {
|
||||
pub node: &'ast ast::StmtAnnAssign,
|
||||
pub annotation: &'ast ast::Expr,
|
||||
pub value: Option<&'ast ast::Expr>,
|
||||
pub target: &'ast ast::Expr,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct WithItemDefinitionNodeRef<'ast, 'db> {
|
||||
pub(crate) unpack: Option<(UnpackPosition, Unpack<'db>)>,
|
||||
pub(crate) context_expr: &'ast ast::Expr,
|
||||
pub(crate) target: &'ast ast::Expr,
|
||||
pub(crate) is_async: bool,
|
||||
pub struct WithItemDefinitionNodeRef<'ast, 'db> {
|
||||
pub unpack: Option<(UnpackPosition, Unpack<'db>)>,
|
||||
pub context_expr: &'ast ast::Expr,
|
||||
pub target: &'ast ast::Expr,
|
||||
pub is_async: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct ForStmtDefinitionNodeRef<'ast, 'db> {
|
||||
pub(crate) unpack: Option<(UnpackPosition, Unpack<'db>)>,
|
||||
pub(crate) iterable: &'ast ast::Expr,
|
||||
pub(crate) target: &'ast ast::Expr,
|
||||
pub(crate) is_async: bool,
|
||||
pub struct ForStmtDefinitionNodeRef<'ast, 'db> {
|
||||
pub unpack: Option<(UnpackPosition, Unpack<'db>)>,
|
||||
pub iterable: &'ast ast::Expr,
|
||||
pub target: &'ast ast::Expr,
|
||||
pub is_async: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct ExceptHandlerDefinitionNodeRef<'ast> {
|
||||
pub(crate) handler: &'ast ast::ExceptHandlerExceptHandler,
|
||||
pub(crate) is_star: bool,
|
||||
pub struct ExceptHandlerDefinitionNodeRef<'ast> {
|
||||
pub handler: &'ast ast::ExceptHandlerExceptHandler,
|
||||
pub is_star: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct ComprehensionDefinitionNodeRef<'ast, 'db> {
|
||||
pub(crate) unpack: Option<(UnpackPosition, Unpack<'db>)>,
|
||||
pub(crate) iterable: &'ast ast::Expr,
|
||||
pub(crate) target: &'ast ast::Expr,
|
||||
pub(crate) first: bool,
|
||||
pub(crate) is_async: bool,
|
||||
pub struct ComprehensionDefinitionNodeRef<'ast, 'db> {
|
||||
pub unpack: Option<(UnpackPosition, Unpack<'db>)>,
|
||||
pub iterable: &'ast ast::Expr,
|
||||
pub target: &'ast ast::Expr,
|
||||
pub first: bool,
|
||||
pub is_async: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct MatchPatternDefinitionNodeRef<'ast> {
|
||||
pub struct MatchPatternDefinitionNodeRef<'ast> {
|
||||
/// The outermost pattern node in which the identifier being defined occurs.
|
||||
pub(crate) pattern: &'ast ast::Pattern,
|
||||
pub pattern: &'ast ast::Pattern,
|
||||
/// The identifier being defined.
|
||||
pub(crate) identifier: &'ast ast::Identifier,
|
||||
pub identifier: &'ast ast::Identifier,
|
||||
/// The index of the identifier in the pattern when visiting the `pattern` node in evaluation
|
||||
/// order.
|
||||
pub(crate) index: u32,
|
||||
pub index: u32,
|
||||
}
|
||||
|
||||
impl<'db> DefinitionNodeRef<'_, 'db> {
|
||||
@@ -688,7 +688,7 @@ impl<'db> DefinitionNodeRef<'_, 'db> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) enum DefinitionCategory {
|
||||
pub enum DefinitionCategory {
|
||||
/// A Definition which binds a value to a name (e.g. `x = 1`).
|
||||
Binding,
|
||||
/// A Definition which declares the upper-bound of acceptable types for this name (`x: int`).
|
||||
@@ -704,7 +704,7 @@ impl DefinitionCategory {
|
||||
/// type not assignable to the declared type.
|
||||
///
|
||||
/// Annotations establish a declared type. So do function and class definitions, and imports.
|
||||
pub(crate) fn is_declaration(self) -> bool {
|
||||
pub fn is_declaration(self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
DefinitionCategory::Declaration | DefinitionCategory::DeclarationAndBinding
|
||||
@@ -714,7 +714,7 @@ impl DefinitionCategory {
|
||||
/// True if this definition assigns a value to the place.
|
||||
///
|
||||
/// False only for annotated assignments without a RHS.
|
||||
pub(crate) fn is_binding(self) -> bool {
|
||||
pub fn is_binding(self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
DefinitionCategory::Binding | DefinitionCategory::DeclarationAndBinding
|
||||
@@ -756,7 +756,7 @@ pub enum DefinitionKind<'db> {
|
||||
}
|
||||
|
||||
impl DefinitionKind<'_> {
|
||||
pub(crate) fn is_reexported(&self) -> bool {
|
||||
pub fn is_reexported(&self) -> bool {
|
||||
match self {
|
||||
DefinitionKind::Import(import) => import.is_reexported(),
|
||||
DefinitionKind::ImportFrom(import) => import.is_reexported(),
|
||||
@@ -765,21 +765,21 @@ impl DefinitionKind<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn as_star_import(&self) -> Option<&StarImportDefinitionKind> {
|
||||
pub const fn as_star_import(&self) -> Option<&StarImportDefinitionKind> {
|
||||
match self {
|
||||
DefinitionKind::StarImport(import) => Some(import),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn as_class(&self) -> Option<&AstNodeRef<ast::StmtClassDef>> {
|
||||
pub const fn as_class(&self) -> Option<&AstNodeRef<ast::StmtClassDef>> {
|
||||
match self {
|
||||
DefinitionKind::Class(class) => Some(class),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_import(&self) -> bool {
|
||||
pub fn is_import(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
DefinitionKind::Import(_)
|
||||
@@ -789,11 +789,11 @@ impl DefinitionKind<'_> {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_unannotated_assignment(&self) -> bool {
|
||||
pub const fn is_unannotated_assignment(&self) -> bool {
|
||||
matches!(self, DefinitionKind::Assignment(_))
|
||||
}
|
||||
|
||||
pub(crate) const fn is_function_def(&self) -> bool {
|
||||
pub const fn is_function_def(&self) -> bool {
|
||||
matches!(self, DefinitionKind::Function(_))
|
||||
}
|
||||
|
||||
@@ -801,7 +801,7 @@ impl DefinitionKind<'_> {
|
||||
///
|
||||
/// A definition target would mainly be the node representing the place being defined i.e.,
|
||||
/// [`ast::ExprName`], [`ast::Identifier`], [`ast::ExprAttribute`] or [`ast::ExprSubscript`] but could also be other nodes.
|
||||
pub(crate) fn target_range(&self, module: &ParsedModuleRef) -> TextRange {
|
||||
pub fn target_range(&self, module: &ParsedModuleRef) -> TextRange {
|
||||
match self {
|
||||
DefinitionKind::Import(import) => import.alias(module).range(),
|
||||
DefinitionKind::ImportFrom(import) => import.alias(module).range(),
|
||||
@@ -839,7 +839,7 @@ impl DefinitionKind<'_> {
|
||||
}
|
||||
|
||||
/// Returns the [`TextRange`] of the entire definition.
|
||||
pub(crate) fn full_range(&self, module: &ParsedModuleRef) -> TextRange {
|
||||
pub fn full_range(&self, module: &ParsedModuleRef) -> TextRange {
|
||||
match self {
|
||||
DefinitionKind::Import(import) => import.alias(module).range(),
|
||||
DefinitionKind::ImportFrom(import) => import.alias(module).range(),
|
||||
@@ -883,7 +883,7 @@ impl DefinitionKind<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn category(&self, in_stub: bool, module: &ParsedModuleRef) -> DefinitionCategory {
|
||||
pub fn category(&self, in_stub: bool, module: &ParsedModuleRef) -> DefinitionCategory {
|
||||
match self {
|
||||
// functions, classes, and imports always bind, and we consider them declarations
|
||||
DefinitionKind::Function(_)
|
||||
@@ -941,7 +941,7 @@ impl DefinitionKind<'_> {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Hash, get_size2::GetSize)]
|
||||
pub(crate) enum TargetKind<'db> {
|
||||
pub enum TargetKind<'db> {
|
||||
Sequence(UnpackPosition, Unpack<'db>),
|
||||
/// Name, attribute, or subscript.
|
||||
Single,
|
||||
@@ -967,7 +967,7 @@ impl StarImportDefinitionKind {
|
||||
self.node.node(module)
|
||||
}
|
||||
|
||||
pub(crate) fn alias<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Alias {
|
||||
pub fn alias<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Alias {
|
||||
// INVARIANT: for an invalid-syntax statement such as `from foo import *, bar, *`,
|
||||
// we only create a `StarImportDefinitionKind` for the *first* `*` alias in the names list.
|
||||
self.node
|
||||
@@ -981,7 +981,7 @@ impl StarImportDefinitionKind {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn symbol_id(&self) -> ScopedSymbolId {
|
||||
pub fn symbol_id(&self) -> ScopedSymbolId {
|
||||
self.symbol_id
|
||||
}
|
||||
}
|
||||
@@ -994,11 +994,11 @@ pub struct MatchPatternDefinitionKind {
|
||||
}
|
||||
|
||||
impl MatchPatternDefinitionKind {
|
||||
pub(crate) fn pattern<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Pattern {
|
||||
pub fn pattern<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Pattern {
|
||||
self.pattern.node(module)
|
||||
}
|
||||
|
||||
pub(crate) fn index(&self) -> u32 {
|
||||
pub fn index(&self) -> u32 {
|
||||
self.index
|
||||
}
|
||||
}
|
||||
@@ -1018,23 +1018,23 @@ pub struct ComprehensionDefinitionKind<'db> {
|
||||
}
|
||||
|
||||
impl<'db> ComprehensionDefinitionKind<'db> {
|
||||
pub(crate) fn iterable<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
pub fn iterable<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
self.iterable.node(module)
|
||||
}
|
||||
|
||||
pub(crate) fn target_kind(&self) -> TargetKind<'db> {
|
||||
pub fn target_kind(&self) -> TargetKind<'db> {
|
||||
self.target_kind
|
||||
}
|
||||
|
||||
pub(crate) fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
pub fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
self.target.node(module)
|
||||
}
|
||||
|
||||
pub(crate) fn is_first(&self) -> bool {
|
||||
pub fn is_first(&self) -> bool {
|
||||
self.first
|
||||
}
|
||||
|
||||
pub(crate) fn is_async(&self) -> bool {
|
||||
pub fn is_async(&self) -> bool {
|
||||
self.is_async
|
||||
}
|
||||
}
|
||||
@@ -1051,11 +1051,11 @@ impl ImportDefinitionKind {
|
||||
self.node.node(module)
|
||||
}
|
||||
|
||||
pub(crate) fn alias<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Alias {
|
||||
pub fn alias<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Alias {
|
||||
&self.node.node(module).names[self.alias_index]
|
||||
}
|
||||
|
||||
pub(crate) fn is_reexported(&self) -> bool {
|
||||
pub fn is_reexported(&self) -> bool {
|
||||
self.is_reexported
|
||||
}
|
||||
}
|
||||
@@ -1072,11 +1072,11 @@ impl ImportFromDefinitionKind {
|
||||
self.node.node(module)
|
||||
}
|
||||
|
||||
pub(crate) fn alias<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Alias {
|
||||
pub fn alias<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Alias {
|
||||
&self.node.node(module).names[self.alias_index]
|
||||
}
|
||||
|
||||
pub(crate) fn is_reexported(&self) -> bool {
|
||||
pub fn is_reexported(&self) -> bool {
|
||||
self.is_reexported
|
||||
}
|
||||
}
|
||||
@@ -1099,7 +1099,7 @@ pub struct AssignmentDefinitionKind<'db> {
|
||||
}
|
||||
|
||||
impl<'db> AssignmentDefinitionKind<'db> {
|
||||
pub(crate) fn target_kind(&self) -> TargetKind<'db> {
|
||||
pub fn target_kind(&self) -> TargetKind<'db> {
|
||||
self.target_kind
|
||||
}
|
||||
|
||||
@@ -1107,7 +1107,7 @@ impl<'db> AssignmentDefinitionKind<'db> {
|
||||
self.value.node(module)
|
||||
}
|
||||
|
||||
pub(crate) fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
pub fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
self.target.node(module)
|
||||
}
|
||||
}
|
||||
@@ -1120,15 +1120,15 @@ pub struct AnnotatedAssignmentDefinitionKind {
|
||||
}
|
||||
|
||||
impl AnnotatedAssignmentDefinitionKind {
|
||||
pub(crate) fn value<'ast>(&self, module: &'ast ParsedModuleRef) -> Option<&'ast ast::Expr> {
|
||||
pub fn value<'ast>(&self, module: &'ast ParsedModuleRef) -> Option<&'ast ast::Expr> {
|
||||
self.value.as_ref().map(|value| value.node(module))
|
||||
}
|
||||
|
||||
pub(crate) fn annotation<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
pub fn annotation<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
self.annotation.node(module)
|
||||
}
|
||||
|
||||
pub(crate) fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
pub fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
self.target.node(module)
|
||||
}
|
||||
}
|
||||
@@ -1142,19 +1142,19 @@ pub struct WithItemDefinitionKind<'db> {
|
||||
}
|
||||
|
||||
impl<'db> WithItemDefinitionKind<'db> {
|
||||
pub(crate) fn context_expr<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
pub fn context_expr<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
self.context_expr.node(module)
|
||||
}
|
||||
|
||||
pub(crate) fn target_kind(&self) -> TargetKind<'db> {
|
||||
pub fn target_kind(&self) -> TargetKind<'db> {
|
||||
self.target_kind
|
||||
}
|
||||
|
||||
pub(crate) fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
pub fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
self.target.node(module)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_async(&self) -> bool {
|
||||
pub const fn is_async(&self) -> bool {
|
||||
self.is_async
|
||||
}
|
||||
}
|
||||
@@ -1168,19 +1168,19 @@ pub struct ForStmtDefinitionKind<'db> {
|
||||
}
|
||||
|
||||
impl<'db> ForStmtDefinitionKind<'db> {
|
||||
pub(crate) fn iterable<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
pub fn iterable<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
self.iterable.node(module)
|
||||
}
|
||||
|
||||
pub(crate) fn target_kind(&self) -> TargetKind<'db> {
|
||||
pub fn target_kind(&self) -> TargetKind<'db> {
|
||||
self.target_kind
|
||||
}
|
||||
|
||||
pub(crate) fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
pub fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
self.target.node(module)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_async(&self) -> bool {
|
||||
pub const fn is_async(&self) -> bool {
|
||||
self.is_async
|
||||
}
|
||||
}
|
||||
@@ -1192,27 +1192,27 @@ pub struct ExceptHandlerDefinitionKind {
|
||||
}
|
||||
|
||||
impl ExceptHandlerDefinitionKind {
|
||||
pub(crate) fn node<'ast>(
|
||||
pub fn node<'ast>(
|
||||
&self,
|
||||
module: &'ast ParsedModuleRef,
|
||||
) -> &'ast ast::ExceptHandlerExceptHandler {
|
||||
self.handler.node(module)
|
||||
}
|
||||
|
||||
pub(crate) fn handled_exceptions<'ast>(
|
||||
pub fn handled_exceptions<'ast>(
|
||||
&self,
|
||||
module: &'ast ParsedModuleRef,
|
||||
) -> Option<&'ast ast::Expr> {
|
||||
self.node(module).type_.as_deref()
|
||||
}
|
||||
|
||||
pub(crate) fn is_star(&self) -> bool {
|
||||
pub fn is_star(&self) -> bool {
|
||||
self.is_star
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) struct DefinitionNodeKey(NodeKey);
|
||||
pub struct DefinitionNodeKey(NodeKey);
|
||||
|
||||
impl From<&ast::Alias> for DefinitionNodeKey {
|
||||
fn from(node: &ast::Alias) -> Self {
|
||||
|
||||
@@ -11,7 +11,7 @@ use salsa;
|
||||
/// `<annotation>` is inferred as a type expression, while `<value>` is inferred
|
||||
/// as a normal expression.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)]
|
||||
pub(crate) enum ExpressionKind {
|
||||
pub enum ExpressionKind {
|
||||
Normal,
|
||||
TypeExpression,
|
||||
}
|
||||
@@ -32,18 +32,18 @@ pub(crate) enum ExpressionKind {
|
||||
/// * a field of a type that is a return type of a cross-module query
|
||||
/// * an argument of a cross-module query
|
||||
#[salsa::tracked(debug, heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) struct Expression<'db> {
|
||||
pub struct Expression<'db> {
|
||||
/// The file in which the expression occurs.
|
||||
pub(crate) file: File,
|
||||
pub file: File,
|
||||
|
||||
/// The scope in which the expression occurs.
|
||||
pub(crate) file_scope: FileScopeId,
|
||||
pub file_scope: FileScopeId,
|
||||
|
||||
/// The expression node.
|
||||
#[no_eq]
|
||||
#[tracked]
|
||||
#[returns(ref)]
|
||||
pub(crate) _node_ref: AstNodeRef<ast::Expr>,
|
||||
pub _node_ref: AstNodeRef<ast::Expr>,
|
||||
|
||||
/// An assignment statement, if this expression is immediately used as the rhs of that
|
||||
/// assignment.
|
||||
@@ -54,25 +54,21 @@ pub(crate) struct Expression<'db> {
|
||||
/// to the target, and so have `None` for this field.)
|
||||
#[no_eq]
|
||||
#[tracked]
|
||||
pub(crate) assigned_to: Option<AstNodeRef<ast::StmtAssign>>,
|
||||
pub assigned_to: Option<AstNodeRef<ast::StmtAssign>>,
|
||||
|
||||
/// Should this expression be inferred as a normal expression or a type expression?
|
||||
pub(crate) kind: ExpressionKind,
|
||||
pub kind: ExpressionKind,
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for Expression<'_> {}
|
||||
|
||||
impl<'db> Expression<'db> {
|
||||
pub(crate) fn node_ref<'ast>(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
parsed: &'ast ParsedModuleRef,
|
||||
) -> &'ast ast::Expr {
|
||||
pub fn node_ref<'ast>(self, db: &'db dyn Db, parsed: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
self._node_ref(db).node(parsed)
|
||||
}
|
||||
|
||||
pub(crate) fn scope(self, db: &'db dyn Db) -> ScopeId<'db> {
|
||||
pub fn scope(self, db: &'db dyn Db) -> ScopeId<'db> {
|
||||
self.file_scope(db).to_scope_id(db, self.file(db))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// A member access, e.g. `x.y` or `x[1]` or `x["foo"]`.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, get_size2::GetSize)]
|
||||
pub(crate) struct Member {
|
||||
pub struct Member {
|
||||
expression: MemberExpr,
|
||||
flags: MemberFlags,
|
||||
}
|
||||
@@ -26,7 +26,7 @@ impl Member {
|
||||
/// Returns the left most part of the member expression, e.g. `x` in `x.y.z`.
|
||||
///
|
||||
/// This is the symbol on which the member access is performed.
|
||||
pub(crate) fn symbol_name(&self) -> &str {
|
||||
pub fn symbol_name(&self) -> &str {
|
||||
self.expression.symbol_name()
|
||||
}
|
||||
|
||||
@@ -35,12 +35,12 @@ impl Member {
|
||||
}
|
||||
|
||||
/// Is the place given a value in its containing scope?
|
||||
pub(crate) const fn is_bound(&self) -> bool {
|
||||
pub const fn is_bound(&self) -> bool {
|
||||
self.flags.contains(MemberFlags::IS_BOUND)
|
||||
}
|
||||
|
||||
/// Is the place declared in its containing scope?
|
||||
pub(crate) fn is_declared(&self) -> bool {
|
||||
pub fn is_declared(&self) -> bool {
|
||||
self.flags.contains(MemberFlags::IS_DECLARED)
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ impl Member {
|
||||
}
|
||||
|
||||
/// Is the place an instance attribute?
|
||||
pub(crate) fn is_instance_attribute(&self) -> bool {
|
||||
pub fn is_instance_attribute(&self) -> bool {
|
||||
let is_instance_attribute = self.flags.contains(MemberFlags::IS_INSTANCE_ATTRIBUTE);
|
||||
if is_instance_attribute {
|
||||
debug_assert!(self.is_instance_attribute_candidate());
|
||||
@@ -109,7 +109,7 @@ impl Member {
|
||||
}
|
||||
|
||||
/// Return `Some(<ATTRIBUTE>)` if the place expression is an instance attribute.
|
||||
pub(crate) fn as_instance_attribute(&self) -> Option<&str> {
|
||||
pub fn as_instance_attribute(&self) -> Option<&str> {
|
||||
if self.is_instance_attribute() {
|
||||
debug_assert!(self.as_instance_attribute_candidate().is_some());
|
||||
self.as_instance_attribute_candidate()
|
||||
@@ -367,7 +367,7 @@ impl MemberTable {
|
||||
/// ## Panics
|
||||
/// If the ID is not valid for this table.
|
||||
#[track_caller]
|
||||
pub(crate) fn member(&self, id: ScopedMemberId) -> &Member {
|
||||
pub(super) fn member(&self, id: ScopedMemberId) -> &Member {
|
||||
&self.members[id]
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ impl MemberTable {
|
||||
}
|
||||
|
||||
/// Returns an iterator over all members in the table.
|
||||
pub(crate) fn iter(&self) -> std::slice::Iter<'_, Member> {
|
||||
pub(super) fn iter(&self) -> std::slice::Iter<'_, Member> {
|
||||
self.members.iter()
|
||||
}
|
||||
|
||||
@@ -390,7 +390,7 @@ impl MemberTable {
|
||||
}
|
||||
|
||||
/// Returns the ID of the member with the given expression, if it exists.
|
||||
pub(crate) fn member_id<'a>(
|
||||
pub(super) fn member_id<'a>(
|
||||
&self,
|
||||
member: impl Into<MemberExprRef<'a>>,
|
||||
) -> Option<ScopedMemberId> {
|
||||
@@ -401,7 +401,7 @@ impl MemberTable {
|
||||
.copied()
|
||||
}
|
||||
|
||||
pub(crate) fn place_id_by_instance_attribute_name(&self, name: &str) -> Option<ScopedMemberId> {
|
||||
pub(super) fn place_id_by_instance_attribute_name(&self, name: &str) -> Option<ScopedMemberId> {
|
||||
for (id, member) in self.members.iter_enumerated() {
|
||||
if member.is_instance_attribute_named(name) {
|
||||
return Some(id);
|
||||
|
||||
@@ -38,10 +38,10 @@ use crate::semantic_index::scope::FileScopeId;
|
||||
/// A constraint is a list of [`Predicate`]s that each constrain the type of the binding's place.
|
||||
///
|
||||
/// [`Predicate`]: crate::semantic_index::predicate::Predicate
|
||||
pub(crate) type ScopedNarrowingConstraint = List<ScopedNarrowingConstraintPredicate>;
|
||||
pub type ScopedNarrowingConstraint = List<ScopedNarrowingConstraintPredicate>;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub(crate) enum ConstraintKey {
|
||||
pub enum ConstraintKey {
|
||||
NarrowingConstraint(ScopedNarrowingConstraint),
|
||||
NestedScope(FileScopeId),
|
||||
UseId(ScopedUseId),
|
||||
@@ -56,11 +56,11 @@ pub(crate) enum ConstraintKey {
|
||||
///
|
||||
/// [`Predicate`]: crate::semantic_index::predicate::Predicate
|
||||
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, get_size2::GetSize)]
|
||||
pub(crate) struct ScopedNarrowingConstraintPredicate(ScopedPredicateId);
|
||||
pub struct ScopedNarrowingConstraintPredicate(ScopedPredicateId);
|
||||
|
||||
impl ScopedNarrowingConstraintPredicate {
|
||||
/// Returns (the ID of) the `Predicate`
|
||||
pub(crate) fn predicate(self) -> ScopedPredicateId {
|
||||
pub fn predicate(self) -> ScopedPredicateId {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ impl From<ScopedPredicateId> for ScopedNarrowingConstraintPredicate {
|
||||
|
||||
/// A collection of narrowing constraints for a given scope.
|
||||
#[derive(Debug, Eq, PartialEq, get_size2::GetSize)]
|
||||
pub(crate) struct NarrowingConstraints {
|
||||
pub struct NarrowingConstraints {
|
||||
lists: ListStorage<ScopedNarrowingConstraintPredicate>,
|
||||
}
|
||||
|
||||
@@ -82,19 +82,19 @@ pub(crate) struct NarrowingConstraints {
|
||||
|
||||
/// A builder for creating narrowing constraints.
|
||||
#[derive(Debug, Default, Eq, PartialEq)]
|
||||
pub(crate) struct NarrowingConstraintsBuilder {
|
||||
pub struct NarrowingConstraintsBuilder {
|
||||
lists: ListBuilder<ScopedNarrowingConstraintPredicate>,
|
||||
}
|
||||
|
||||
impl NarrowingConstraintsBuilder {
|
||||
pub(crate) fn build(self) -> NarrowingConstraints {
|
||||
pub fn build(self) -> NarrowingConstraints {
|
||||
NarrowingConstraints {
|
||||
lists: self.lists.build(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a predicate to an existing narrowing constraint.
|
||||
pub(crate) fn add_predicate_to_constraint(
|
||||
pub fn add_predicate_to_constraint(
|
||||
&mut self,
|
||||
constraint: ScopedNarrowingConstraint,
|
||||
predicate: ScopedNarrowingConstraintPredicate,
|
||||
@@ -104,7 +104,7 @@ impl NarrowingConstraintsBuilder {
|
||||
|
||||
/// Returns the intersection of two narrowing constraints. The result contains the predicates
|
||||
/// that appear in both inputs.
|
||||
pub(crate) fn intersect_constraints(
|
||||
pub fn intersect_constraints(
|
||||
&mut self,
|
||||
a: ScopedNarrowingConstraint,
|
||||
b: ScopedNarrowingConstraint,
|
||||
@@ -137,7 +137,7 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
impl ScopedNarrowingConstraintPredicate {
|
||||
pub(crate) fn as_u32(self) -> u32 {
|
||||
pub fn as_u32(self) -> u32 {
|
||||
self.0.as_u32()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use std::iter::FusedIterator;
|
||||
|
||||
/// An expression that can be the target of a `Definition`.
|
||||
#[derive(Eq, PartialEq, Debug, get_size2::GetSize)]
|
||||
pub(crate) enum PlaceExpr {
|
||||
pub enum PlaceExpr {
|
||||
/// A simple symbol, e.g. `x`.
|
||||
Symbol(Symbol),
|
||||
|
||||
@@ -23,7 +23,7 @@ impl PlaceExpr {
|
||||
/// Create a new `PlaceExpr` from a name.
|
||||
///
|
||||
/// This always returns a `PlaceExpr::Symbol` with empty flags and `name`.
|
||||
pub(crate) fn from_expr_name(name: &ast::ExprName) -> Self {
|
||||
pub fn from_expr_name(name: &ast::ExprName) -> Self {
|
||||
PlaceExpr::Symbol(Symbol::new(name.id.clone()))
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ impl PlaceExpr {
|
||||
/// * name: `x`
|
||||
/// * attribute: `x.y`
|
||||
/// * subscripts with integer or string literals: `x[0]`, `x['key']`
|
||||
pub(crate) fn try_from_expr<'e>(expr: impl Into<ast::ExprRef<'e>>) -> Option<Self> {
|
||||
pub fn try_from_expr<'e>(expr: impl Into<ast::ExprRef<'e>>) -> Option<Self> {
|
||||
let expr = expr.into();
|
||||
|
||||
if let ast::ExprRef::Name(name) = expr {
|
||||
@@ -60,14 +60,14 @@ impl std::fmt::Display for PlaceExpr {
|
||||
///
|
||||
/// Needed so that we can iterate over all places without cloning them.
|
||||
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
||||
pub(crate) enum PlaceExprRef<'a> {
|
||||
pub enum PlaceExprRef<'a> {
|
||||
Symbol(&'a Symbol),
|
||||
Member(&'a Member),
|
||||
}
|
||||
|
||||
impl<'a> PlaceExprRef<'a> {
|
||||
/// Returns `Some` if the reference is a `Symbol`, otherwise `None`.
|
||||
pub(crate) const fn as_symbol(self) -> Option<&'a Symbol> {
|
||||
pub const fn as_symbol(self) -> Option<&'a Symbol> {
|
||||
if let PlaceExprRef::Symbol(symbol) = self {
|
||||
Some(symbol)
|
||||
} else {
|
||||
@@ -76,25 +76,25 @@ impl<'a> PlaceExprRef<'a> {
|
||||
}
|
||||
|
||||
/// Returns `true` if the reference is a `Symbol`, otherwise `false`.
|
||||
pub(crate) const fn is_symbol(self) -> bool {
|
||||
pub const fn is_symbol(self) -> bool {
|
||||
matches!(self, PlaceExprRef::Symbol(_))
|
||||
}
|
||||
|
||||
pub(crate) fn is_declared(self) -> bool {
|
||||
pub fn is_declared(self) -> bool {
|
||||
match self {
|
||||
Self::Symbol(symbol) => symbol.is_declared(),
|
||||
Self::Member(member) => member.is_declared(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn is_bound(self) -> bool {
|
||||
pub const fn is_bound(self) -> bool {
|
||||
match self {
|
||||
PlaceExprRef::Symbol(symbol) => symbol.is_bound(),
|
||||
PlaceExprRef::Member(member) => member.is_bound(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn num_member_segments(self) -> usize {
|
||||
pub fn num_member_segments(self) -> usize {
|
||||
match self {
|
||||
PlaceExprRef::Symbol(_) => 0,
|
||||
PlaceExprRef::Member(member) => member.expression().num_segments(),
|
||||
@@ -140,7 +140,7 @@ pub enum ScopedPlaceId {
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) struct PlaceTable {
|
||||
pub struct PlaceTable {
|
||||
symbols: SymbolTable,
|
||||
members: MemberTable,
|
||||
}
|
||||
@@ -149,10 +149,7 @@ impl PlaceTable {
|
||||
/// Iterate over the "root" expressions of the place (e.g. `x.y.z`, `x.y`, `x` for `x.y.z[0]`).
|
||||
///
|
||||
/// Note, this iterator may skip some parents if they are not defined in the current scope.
|
||||
pub(crate) fn parents<'a>(
|
||||
&'a self,
|
||||
place_expr: impl Into<PlaceExprRef<'a>>,
|
||||
) -> ParentPlaceIter<'a> {
|
||||
pub fn parents<'a>(&'a self, place_expr: impl Into<PlaceExprRef<'a>>) -> ParentPlaceIter<'a> {
|
||||
match place_expr.into() {
|
||||
PlaceExprRef::Symbol(_) => ParentPlaceIter::for_symbol(),
|
||||
PlaceExprRef::Member(member) => {
|
||||
@@ -162,12 +159,12 @@ impl PlaceTable {
|
||||
}
|
||||
|
||||
/// Iterator over all symbols in this scope.
|
||||
pub(crate) fn symbols(&self) -> std::slice::Iter<'_, Symbol> {
|
||||
pub fn symbols(&self) -> std::slice::Iter<'_, Symbol> {
|
||||
self.symbols.iter()
|
||||
}
|
||||
|
||||
/// Iterator over all members in this scope.
|
||||
pub(crate) fn members(&self) -> std::slice::Iter<'_, Member> {
|
||||
pub fn members(&self) -> std::slice::Iter<'_, Member> {
|
||||
self.members.iter()
|
||||
}
|
||||
|
||||
@@ -176,14 +173,14 @@ impl PlaceTable {
|
||||
/// ## Panics
|
||||
/// If the symbol ID is not found in the table.
|
||||
#[track_caller]
|
||||
pub(crate) fn symbol(&self, id: ScopedSymbolId) -> &Symbol {
|
||||
pub fn symbol(&self, id: ScopedSymbolId) -> &Symbol {
|
||||
self.symbols.symbol(id)
|
||||
}
|
||||
|
||||
/// Looks up a symbol by its name and returns a reference to it, if it exists.
|
||||
///
|
||||
/// This should only be used in diagnostics and tests.
|
||||
pub(crate) fn symbol_by_name(&self, name: &str) -> Option<&Symbol> {
|
||||
pub fn symbol_by_name(&self, name: &str) -> Option<&Symbol> {
|
||||
self.symbols.symbol_id(name).map(|id| self.symbol(id))
|
||||
}
|
||||
|
||||
@@ -192,20 +189,17 @@ impl PlaceTable {
|
||||
/// ## Panics
|
||||
/// If the member ID is not found in the table.
|
||||
#[track_caller]
|
||||
pub(crate) fn member(&self, id: ScopedMemberId) -> &Member {
|
||||
pub fn member(&self, id: ScopedMemberId) -> &Member {
|
||||
self.members.member(id)
|
||||
}
|
||||
|
||||
/// Returns the [`ScopedSymbolId`] of the place named `name`.
|
||||
pub(crate) fn symbol_id(&self, name: &str) -> Option<ScopedSymbolId> {
|
||||
pub fn symbol_id(&self, name: &str) -> Option<ScopedSymbolId> {
|
||||
self.symbols.symbol_id(name)
|
||||
}
|
||||
|
||||
/// Returns the [`ScopedPlaceId`] of the place expression.
|
||||
pub(crate) fn place_id<'e>(
|
||||
&self,
|
||||
place_expr: impl Into<PlaceExprRef<'e>>,
|
||||
) -> Option<ScopedPlaceId> {
|
||||
pub fn place_id<'e>(&self, place_expr: impl Into<PlaceExprRef<'e>>) -> Option<ScopedPlaceId> {
|
||||
let place_expr = place_expr.into();
|
||||
|
||||
match place_expr {
|
||||
@@ -221,23 +215,20 @@ impl PlaceTable {
|
||||
/// ## Panics
|
||||
/// If the place ID is not found in the table.
|
||||
#[track_caller]
|
||||
pub(crate) fn place(&self, place_id: impl Into<ScopedPlaceId>) -> PlaceExprRef<'_> {
|
||||
pub fn place(&self, place_id: impl Into<ScopedPlaceId>) -> PlaceExprRef<'_> {
|
||||
match place_id.into() {
|
||||
ScopedPlaceId::Symbol(symbol) => self.symbol(symbol).into(),
|
||||
ScopedPlaceId::Member(member) => self.member(member).into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn member_id_by_instance_attribute_name(
|
||||
&self,
|
||||
name: &str,
|
||||
) -> Option<ScopedMemberId> {
|
||||
pub fn member_id_by_instance_attribute_name(&self, name: &str) -> Option<ScopedMemberId> {
|
||||
self.members.place_id_by_instance_attribute_name(name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct PlaceTableBuilder {
|
||||
pub struct PlaceTableBuilder {
|
||||
symbols: SymbolTableBuilder,
|
||||
member: MemberTableBuilder,
|
||||
|
||||
@@ -276,32 +267,32 @@ impl PlaceTableBuilder {
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub(crate) fn place(&self, place_id: impl Into<ScopedPlaceId>) -> PlaceExprRef<'_> {
|
||||
pub fn place(&self, place_id: impl Into<ScopedPlaceId>) -> PlaceExprRef<'_> {
|
||||
match place_id.into() {
|
||||
ScopedPlaceId::Symbol(id) => PlaceExprRef::Symbol(self.symbols.symbol(id)),
|
||||
ScopedPlaceId::Member(id) => PlaceExprRef::Member(self.member.member(id)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn associated_place_ids(&self, place: ScopedPlaceId) -> &[ScopedMemberId] {
|
||||
pub fn associated_place_ids(&self, place: ScopedPlaceId) -> &[ScopedMemberId] {
|
||||
match place {
|
||||
ScopedPlaceId::Symbol(symbol) => &self.associated_symbol_members[symbol],
|
||||
ScopedPlaceId::Member(member) => &self.associated_sub_members[member],
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = PlaceExprRef<'_>> {
|
||||
pub fn iter(&self) -> impl Iterator<Item = PlaceExprRef<'_>> {
|
||||
self.symbols
|
||||
.iter()
|
||||
.map(Into::into)
|
||||
.chain(self.member.iter().map(PlaceExprRef::Member))
|
||||
}
|
||||
|
||||
pub(crate) fn symbols(&self) -> impl Iterator<Item = &Symbol> {
|
||||
pub fn symbols(&self) -> impl Iterator<Item = &Symbol> {
|
||||
self.symbols.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn add_symbol(&mut self, symbol: Symbol) -> (ScopedSymbolId, bool) {
|
||||
pub fn add_symbol(&mut self, symbol: Symbol) -> (ScopedSymbolId, bool) {
|
||||
let (id, is_new) = self.symbols.add(symbol);
|
||||
|
||||
if is_new {
|
||||
@@ -312,7 +303,7 @@ impl PlaceTableBuilder {
|
||||
(id, is_new)
|
||||
}
|
||||
|
||||
pub(crate) fn add_member(&mut self, member: Member) -> (ScopedMemberId, bool) {
|
||||
pub fn add_member(&mut self, member: Member) -> (ScopedMemberId, bool) {
|
||||
let (id, is_new) = self.member.add(member);
|
||||
|
||||
if is_new {
|
||||
@@ -339,7 +330,7 @@ impl PlaceTableBuilder {
|
||||
(id, is_new)
|
||||
}
|
||||
|
||||
pub(crate) fn add_place(&mut self, place: PlaceExpr) -> (ScopedPlaceId, bool) {
|
||||
pub fn add_place(&mut self, place: PlaceExpr) -> (ScopedPlaceId, bool) {
|
||||
match place {
|
||||
PlaceExpr::Symbol(symbol) => {
|
||||
let (id, is_new) = self.add_symbol(symbol);
|
||||
@@ -376,7 +367,7 @@ impl PlaceTableBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn finish(self) -> PlaceTable {
|
||||
pub fn finish(self) -> PlaceTable {
|
||||
PlaceTable {
|
||||
symbols: self.symbols.build(),
|
||||
members: self.member.build(),
|
||||
@@ -454,7 +445,7 @@ impl FilePlaceId {
|
||||
self.scope
|
||||
}
|
||||
|
||||
pub(crate) fn scoped_place_id(self) -> ScopedPlaceId {
|
||||
pub fn scoped_place_id(self) -> ScopedPlaceId {
|
||||
self.scoped_place_id
|
||||
}
|
||||
}
|
||||
@@ -465,7 +456,7 @@ impl From<FilePlaceId> for ScopedPlaceId {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ParentPlaceIter<'a> {
|
||||
pub struct ParentPlaceIter<'a> {
|
||||
state: Option<ParentPlaceIterState<'a>>,
|
||||
}
|
||||
|
||||
|
||||
@@ -19,14 +19,14 @@ use crate::semantic_index::symbol::ScopedSymbolId;
|
||||
|
||||
// A scoped identifier for each `Predicate` in a scope.
|
||||
#[derive(Clone, Debug, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, get_size2::GetSize)]
|
||||
pub(crate) struct ScopedPredicateId(u32);
|
||||
pub struct ScopedPredicateId(u32);
|
||||
|
||||
impl ScopedPredicateId {
|
||||
/// A special ID that is used for an "always true" predicate.
|
||||
pub(crate) const ALWAYS_TRUE: ScopedPredicateId = ScopedPredicateId(0xffff_ffff);
|
||||
pub const ALWAYS_TRUE: ScopedPredicateId = ScopedPredicateId(0xffff_ffff);
|
||||
|
||||
/// A special ID that is used for an "always false" predicate.
|
||||
pub(crate) const ALWAYS_FALSE: ScopedPredicateId = ScopedPredicateId(0xffff_fffe);
|
||||
pub const ALWAYS_FALSE: ScopedPredicateId = ScopedPredicateId(0xffff_fffe);
|
||||
|
||||
const SMALLEST_TERMINAL: ScopedPredicateId = Self::ALWAYS_FALSE;
|
||||
|
||||
@@ -35,7 +35,7 @@ impl ScopedPredicateId {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn as_u32(self) -> u32 {
|
||||
pub fn as_u32(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
@@ -56,10 +56,10 @@ impl Idx for ScopedPredicateId {
|
||||
}
|
||||
|
||||
// A collection of predicates for a given scope.
|
||||
pub(crate) type Predicates<'db> = IndexVec<ScopedPredicateId, Predicate<'db>>;
|
||||
pub type Predicates<'db> = IndexVec<ScopedPredicateId, Predicate<'db>>;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct PredicatesBuilder<'db> {
|
||||
pub struct PredicatesBuilder<'db> {
|
||||
predicates: IndexVec<ScopedPredicateId, Predicate<'db>>,
|
||||
}
|
||||
|
||||
@@ -78,13 +78,13 @@ impl<'db> PredicatesBuilder<'db> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) struct Predicate<'db> {
|
||||
pub(crate) node: PredicateNode<'db>,
|
||||
pub(crate) is_positive: bool,
|
||||
pub struct Predicate<'db> {
|
||||
pub node: PredicateNode<'db>,
|
||||
pub is_positive: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) enum PredicateOrLiteral<'db> {
|
||||
pub enum PredicateOrLiteral<'db> {
|
||||
Literal(bool),
|
||||
Predicate(Predicate<'db>),
|
||||
}
|
||||
@@ -104,13 +104,13 @@ impl PredicateOrLiteral<'_> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) struct CallableAndCallExpr<'db> {
|
||||
pub(crate) callable: Expression<'db>,
|
||||
pub(crate) call_expr: Expression<'db>,
|
||||
pub struct CallableAndCallExpr<'db> {
|
||||
pub callable: Expression<'db>,
|
||||
pub call_expr: Expression<'db>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) enum PredicateNode<'db> {
|
||||
pub enum PredicateNode<'db> {
|
||||
Expression(Expression<'db>),
|
||||
ReturnsNever(CallableAndCallExpr<'db>),
|
||||
Pattern(PatternPredicate<'db>),
|
||||
@@ -118,20 +118,20 @@ pub(crate) enum PredicateNode<'db> {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) enum ClassPatternKind {
|
||||
pub enum ClassPatternKind {
|
||||
Irrefutable,
|
||||
Refutable,
|
||||
}
|
||||
|
||||
impl ClassPatternKind {
|
||||
pub(crate) fn is_irrefutable(self) -> bool {
|
||||
pub fn is_irrefutable(self) -> bool {
|
||||
matches!(self, ClassPatternKind::Irrefutable)
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern kinds for which we support type narrowing and/or static reachability analysis.
|
||||
#[derive(Debug, Clone, Hash, PartialEq, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) enum PatternPredicateKind<'db> {
|
||||
pub enum PatternPredicateKind<'db> {
|
||||
Singleton(Singleton),
|
||||
Value(Expression<'db>),
|
||||
Or(Vec<PatternPredicateKind<'db>>),
|
||||
@@ -141,27 +141,27 @@ pub(crate) enum PatternPredicateKind<'db> {
|
||||
}
|
||||
|
||||
#[salsa::tracked(debug, heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) struct PatternPredicate<'db> {
|
||||
pub(crate) file: File,
|
||||
pub struct PatternPredicate<'db> {
|
||||
pub file: File,
|
||||
|
||||
pub(crate) file_scope: FileScopeId,
|
||||
pub file_scope: FileScopeId,
|
||||
|
||||
pub(crate) subject: Expression<'db>,
|
||||
pub subject: Expression<'db>,
|
||||
|
||||
#[returns(ref)]
|
||||
pub(crate) kind: PatternPredicateKind<'db>,
|
||||
pub kind: PatternPredicateKind<'db>,
|
||||
|
||||
pub(crate) guard: Option<Expression<'db>>,
|
||||
pub guard: Option<Expression<'db>>,
|
||||
|
||||
/// A reference to the pattern of the previous match case
|
||||
pub(crate) previous_predicate: Option<Box<PatternPredicate<'db>>>,
|
||||
pub previous_predicate: Option<Box<PatternPredicate<'db>>>,
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for PatternPredicate<'_> {}
|
||||
|
||||
impl<'db> PatternPredicate<'db> {
|
||||
pub(crate) fn scope(self, db: &'db dyn Db) -> ScopeId<'db> {
|
||||
pub fn scope(self, db: &'db dyn Db) -> ScopeId<'db> {
|
||||
self.file_scope(db).to_scope_id(db, self.file(db))
|
||||
}
|
||||
}
|
||||
@@ -207,8 +207,8 @@ impl<'db> PatternPredicate<'db> {
|
||||
///
|
||||
/// [Truthiness]: [crate::types::Truthiness]
|
||||
#[salsa::tracked(debug, heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) struct StarImportPlaceholderPredicate<'db> {
|
||||
pub(crate) importing_file: File,
|
||||
pub struct StarImportPlaceholderPredicate<'db> {
|
||||
pub importing_file: File,
|
||||
|
||||
/// Each symbol imported by a `*` import has a separate predicate associated with it:
|
||||
/// this field identifies which symbol that is.
|
||||
@@ -219,16 +219,16 @@ pub(crate) struct StarImportPlaceholderPredicate<'db> {
|
||||
/// for valid `*`-import definitions, and valid `*`-import definitions can only ever
|
||||
/// exist in the global scope; thus, we know that the `symbol_id` here will be relative
|
||||
/// to the global scope of the importing file.
|
||||
pub(crate) symbol_id: ScopedSymbolId,
|
||||
pub symbol_id: ScopedSymbolId,
|
||||
|
||||
pub(crate) referenced_file: File,
|
||||
pub referenced_file: File,
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for StarImportPlaceholderPredicate<'_> {}
|
||||
|
||||
impl<'db> StarImportPlaceholderPredicate<'db> {
|
||||
pub(crate) fn scope(self, db: &'db dyn Db) -> ScopeId<'db> {
|
||||
pub fn scope(self, db: &'db dyn Db) -> ScopeId<'db> {
|
||||
// See doc-comment above [`StarImportPlaceholderPredicate::symbol_id`]:
|
||||
// valid `*`-import definitions can only take place in the global scope.
|
||||
global_scope(db, self.importing_file(db))
|
||||
|
||||
@@ -198,19 +198,8 @@ use std::cmp::Ordering;
|
||||
use ruff_index::{Idx, IndexVec};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::Db;
|
||||
use crate::dunder_all::dunder_all_names;
|
||||
use crate::place::{RequiresExplicitReExport, imported_symbol};
|
||||
use crate::rank::RankBitBox;
|
||||
use crate::semantic_index::place_table;
|
||||
use crate::semantic_index::predicate::{
|
||||
CallableAndCallExpr, PatternPredicate, PatternPredicateKind, Predicate, PredicateNode,
|
||||
Predicates, ScopedPredicateId,
|
||||
};
|
||||
use crate::types::{
|
||||
CallableTypes, IntersectionBuilder, Truthiness, Type, TypeContext, UnionBuilder, UnionType,
|
||||
infer_expression_type, static_expression_truthiness,
|
||||
};
|
||||
use crate::semantic_index::predicate::ScopedPredicateId;
|
||||
|
||||
/// A ternary formula that defines under what conditions a binding is visible. (A ternary formula
|
||||
/// is just like a boolean formula, but with `Ambiguous` as a third potential result. See the
|
||||
@@ -231,7 +220,7 @@ use crate::types::{
|
||||
/// reachability constraints are normalized, so equivalent constraints are guaranteed to have equal
|
||||
/// IDs.
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq, get_size2::GetSize)]
|
||||
pub(crate) struct ScopedReachabilityConstraintId(u32);
|
||||
pub struct ScopedReachabilityConstraintId(u32);
|
||||
|
||||
impl std::fmt::Debug for ScopedReachabilityConstraintId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
@@ -259,35 +248,36 @@ impl std::fmt::Debug for ScopedReachabilityConstraintId {
|
||||
// _Interior nodes_ provide the TDD structure for the formula. Interior nodes are stored in an
|
||||
// arena Vec, with the constraint ID providing an index into the arena.
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
|
||||
struct InteriorNode {
|
||||
/// An interior node in the TDD (Ternary Decision Diagram).
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, get_size2::GetSize)]
|
||||
pub struct InteriorNode {
|
||||
/// A "variable" that is evaluated as part of a TDD ternary function. For reachability
|
||||
/// constraints, this is a `Predicate` that represents some runtime property of the Python
|
||||
/// code that we are evaluating.
|
||||
atom: ScopedPredicateId,
|
||||
if_true: ScopedReachabilityConstraintId,
|
||||
if_ambiguous: ScopedReachabilityConstraintId,
|
||||
if_false: ScopedReachabilityConstraintId,
|
||||
pub atom: ScopedPredicateId,
|
||||
pub if_true: ScopedReachabilityConstraintId,
|
||||
pub if_ambiguous: ScopedReachabilityConstraintId,
|
||||
pub if_false: ScopedReachabilityConstraintId,
|
||||
}
|
||||
|
||||
impl ScopedReachabilityConstraintId {
|
||||
/// A special ID that is used for an "always true" / "always visible" constraint.
|
||||
pub(crate) const ALWAYS_TRUE: ScopedReachabilityConstraintId =
|
||||
pub const ALWAYS_TRUE: ScopedReachabilityConstraintId =
|
||||
ScopedReachabilityConstraintId(0xffff_ffff);
|
||||
|
||||
/// A special ID that is used for an ambiguous constraint.
|
||||
pub(crate) const AMBIGUOUS: ScopedReachabilityConstraintId =
|
||||
pub const AMBIGUOUS: ScopedReachabilityConstraintId =
|
||||
ScopedReachabilityConstraintId(0xffff_fffe);
|
||||
|
||||
/// A special ID that is used for an "always false" / "never visible" constraint.
|
||||
pub(crate) const ALWAYS_FALSE: ScopedReachabilityConstraintId =
|
||||
pub const ALWAYS_FALSE: ScopedReachabilityConstraintId =
|
||||
ScopedReachabilityConstraintId(0xffff_fffd);
|
||||
|
||||
fn is_terminal(self) -> bool {
|
||||
pub fn is_terminal(self) -> bool {
|
||||
self.0 >= SMALLEST_TERMINAL.0
|
||||
}
|
||||
|
||||
fn as_u32(self) -> u32 {
|
||||
pub fn as_u32(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
@@ -313,120 +303,9 @@ const AMBIGUOUS: ScopedReachabilityConstraintId = ScopedReachabilityConstraintId
|
||||
const ALWAYS_FALSE: ScopedReachabilityConstraintId = ScopedReachabilityConstraintId::ALWAYS_FALSE;
|
||||
const SMALLEST_TERMINAL: ScopedReachabilityConstraintId = ALWAYS_FALSE;
|
||||
|
||||
fn singleton_to_type(db: &dyn Db, singleton: ruff_python_ast::Singleton) -> Type<'_> {
|
||||
let ty = match singleton {
|
||||
ruff_python_ast::Singleton::None => Type::none(db),
|
||||
ruff_python_ast::Singleton::True => Type::BooleanLiteral(true),
|
||||
ruff_python_ast::Singleton::False => Type::BooleanLiteral(false),
|
||||
};
|
||||
debug_assert!(ty.is_singleton(db));
|
||||
ty
|
||||
}
|
||||
|
||||
/// Turn a `match` pattern kind into a type that represents the set of all values that would definitely
|
||||
/// match that pattern.
|
||||
fn pattern_kind_to_type<'db>(db: &'db dyn Db, kind: &PatternPredicateKind<'db>) -> Type<'db> {
|
||||
match kind {
|
||||
PatternPredicateKind::Singleton(singleton) => singleton_to_type(db, *singleton),
|
||||
PatternPredicateKind::Value(value) => {
|
||||
infer_expression_type(db, *value, TypeContext::default())
|
||||
}
|
||||
PatternPredicateKind::Class(class_expr, kind) => {
|
||||
if kind.is_irrefutable() {
|
||||
infer_expression_type(db, *class_expr, TypeContext::default())
|
||||
.to_instance(db)
|
||||
.unwrap_or(Type::Never)
|
||||
.top_materialization(db)
|
||||
} else {
|
||||
Type::Never
|
||||
}
|
||||
}
|
||||
PatternPredicateKind::Or(predicates) => {
|
||||
UnionType::from_elements(db, predicates.iter().map(|p| pattern_kind_to_type(db, p)))
|
||||
}
|
||||
PatternPredicateKind::As(pattern, _) => pattern
|
||||
.as_deref()
|
||||
.map(|p| pattern_kind_to_type(db, p))
|
||||
.unwrap_or_else(Type::object),
|
||||
PatternPredicateKind::Unsupported => Type::Never,
|
||||
}
|
||||
}
|
||||
|
||||
/// Go through the list of previous match cases, and accumulate a union of all types that were already
|
||||
/// matched by these patterns.
|
||||
fn type_excluded_by_previous_patterns<'db>(
|
||||
db: &'db dyn Db,
|
||||
mut predicate: PatternPredicate<'db>,
|
||||
) -> Type<'db> {
|
||||
let mut builder = UnionBuilder::new(db);
|
||||
while let Some(previous) = predicate.previous_predicate(db) {
|
||||
predicate = *previous;
|
||||
|
||||
if predicate.guard(db).is_none() {
|
||||
builder = builder.add(pattern_kind_to_type(db, predicate.kind(db)));
|
||||
}
|
||||
}
|
||||
builder.build()
|
||||
}
|
||||
|
||||
/// Analyze a pattern predicate to determine its static truthiness.
|
||||
///
|
||||
/// This is a Salsa tracked function to enable memoization. Without memoization, for a match
|
||||
/// statement with N cases where each case references the subject (e.g., `self`), we would
|
||||
/// re-analyze each pattern O(N) times (once per reference), leading to O(N²) total work.
|
||||
/// With memoization, each pattern is analyzed exactly once.
|
||||
#[salsa::tracked(cycle_initial = analyze_pattern_predicate_cycle_initial, heap_size = get_size2::GetSize::get_heap_size)]
|
||||
fn analyze_pattern_predicate<'db>(db: &'db dyn Db, predicate: PatternPredicate<'db>) -> Truthiness {
|
||||
let subject_ty = infer_expression_type(db, predicate.subject(db), TypeContext::default());
|
||||
|
||||
let narrowed_subject = IntersectionBuilder::new(db)
|
||||
.add_positive(subject_ty)
|
||||
.add_negative(type_excluded_by_previous_patterns(db, predicate));
|
||||
|
||||
let narrowed_subject_ty = narrowed_subject.clone().build();
|
||||
|
||||
// Consider a case where we match on a subject type of `Self` with an upper bound of `Answer`,
|
||||
// where `Answer` is a {YES, NO} enum. After a previous pattern matching on `NO`, the narrowed
|
||||
// subject type is `Self & ~Literal[NO]`. This type is *not* equivalent to `Literal[YES]`,
|
||||
// because `Self` could also specialize to `Literal[NO]` or `Never`, making the intersection
|
||||
// empty. However, if the current pattern matches on `YES`, the *next* narrowed subject type
|
||||
// will be `Self & ~Literal[NO] & ~Literal[YES]`, which *is* always equivalent to `Never`. This
|
||||
// means that subsequent patterns can never match. And we know that if we reach this point,
|
||||
// the current pattern will have to match. We return `AlwaysTrue` here, since the call to
|
||||
// `analyze_single_pattern_predicate_kind` below would return `Ambiguous` in this case.
|
||||
let next_narrowed_subject_ty = narrowed_subject
|
||||
.add_negative(pattern_kind_to_type(db, predicate.kind(db)))
|
||||
.build();
|
||||
if !narrowed_subject_ty.is_never() && next_narrowed_subject_ty.is_never() {
|
||||
return Truthiness::AlwaysTrue;
|
||||
}
|
||||
|
||||
let truthiness = ReachabilityConstraints::analyze_single_pattern_predicate_kind(
|
||||
db,
|
||||
predicate.kind(db),
|
||||
narrowed_subject_ty,
|
||||
);
|
||||
|
||||
if truthiness == Truthiness::AlwaysTrue && predicate.guard(db).is_some() {
|
||||
// Fall back to ambiguous, the guard might change the result.
|
||||
// TODO: actually analyze guard truthiness
|
||||
Truthiness::Ambiguous
|
||||
} else {
|
||||
truthiness
|
||||
}
|
||||
}
|
||||
|
||||
fn analyze_pattern_predicate_cycle_initial<'db>(
|
||||
_db: &'db dyn Db,
|
||||
_id: salsa::Id,
|
||||
_predicate: PatternPredicate<'db>,
|
||||
) -> Truthiness {
|
||||
Truthiness::Ambiguous
|
||||
}
|
||||
|
||||
/// A collection of reachability constraints for a given scope.
|
||||
#[derive(Debug, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) struct ReachabilityConstraints {
|
||||
pub struct ReachabilityConstraints {
|
||||
/// The interior TDD nodes that were marked as used when being built.
|
||||
used_interiors: Box<[InteriorNode]>,
|
||||
/// A bit vector indicating which interior TDD nodes were marked as used. This is indexed by
|
||||
@@ -435,6 +314,18 @@ pub(crate) struct ReachabilityConstraints {
|
||||
used_indices: RankBitBox,
|
||||
}
|
||||
|
||||
impl ReachabilityConstraints {
|
||||
/// Returns a reference to the used interior nodes.
|
||||
pub fn used_interiors(&self) -> &[InteriorNode] {
|
||||
&self.used_interiors
|
||||
}
|
||||
|
||||
/// Returns a reference to the used indices bit vector.
|
||||
pub fn used_indices(&self) -> &RankBitBox {
|
||||
&self.used_indices
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
pub(crate) struct ReachabilityConstraintsBuilder {
|
||||
interiors: IndexVec<ScopedReachabilityConstraintId, InteriorNode>,
|
||||
@@ -730,244 +621,3 @@ impl ReachabilityConstraintsBuilder {
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl ReachabilityConstraints {
|
||||
/// Analyze the statically known reachability for a given constraint.
|
||||
pub(crate) fn evaluate<'db>(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
predicates: &Predicates<'db>,
|
||||
mut id: ScopedReachabilityConstraintId,
|
||||
) -> Truthiness {
|
||||
loop {
|
||||
let node = match id {
|
||||
ALWAYS_TRUE => return Truthiness::AlwaysTrue,
|
||||
AMBIGUOUS => return Truthiness::Ambiguous,
|
||||
ALWAYS_FALSE => return Truthiness::AlwaysFalse,
|
||||
_ => {
|
||||
// `id` gives us the index of this node in the IndexVec that we used when
|
||||
// constructing this BDD. When finalizing the builder, we threw away any
|
||||
// interior nodes that weren't marked as used. The `used_indices` bit vector
|
||||
// lets us verify that this node was marked as used, and the rank of that bit
|
||||
// in the bit vector tells us where this node lives in the "condensed"
|
||||
// `used_interiors` vector.
|
||||
let raw_index = id.as_u32() as usize;
|
||||
debug_assert!(
|
||||
self.used_indices.get_bit(raw_index).unwrap_or(false),
|
||||
"all used reachability constraints should have been marked as used",
|
||||
);
|
||||
let index = self.used_indices.rank(raw_index) as usize;
|
||||
self.used_interiors[index]
|
||||
}
|
||||
};
|
||||
let predicate = &predicates[node.atom];
|
||||
match Self::analyze_single(db, predicate) {
|
||||
Truthiness::AlwaysTrue => id = node.if_true,
|
||||
Truthiness::Ambiguous => id = node.if_ambiguous,
|
||||
Truthiness::AlwaysFalse => id = node.if_false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn analyze_single_pattern_predicate_kind<'db>(
|
||||
db: &'db dyn Db,
|
||||
predicate_kind: &PatternPredicateKind<'db>,
|
||||
subject_ty: Type<'db>,
|
||||
) -> Truthiness {
|
||||
match predicate_kind {
|
||||
PatternPredicateKind::Value(value) => {
|
||||
let value_ty = infer_expression_type(db, *value, TypeContext::default());
|
||||
|
||||
if subject_ty.is_single_valued(db) {
|
||||
Truthiness::from(subject_ty.is_equivalent_to(db, value_ty))
|
||||
} else {
|
||||
Truthiness::Ambiguous
|
||||
}
|
||||
}
|
||||
PatternPredicateKind::Singleton(singleton) => {
|
||||
let singleton_ty = singleton_to_type(db, *singleton);
|
||||
|
||||
if subject_ty.is_equivalent_to(db, singleton_ty) {
|
||||
Truthiness::AlwaysTrue
|
||||
} else if subject_ty.is_disjoint_from(db, singleton_ty) {
|
||||
Truthiness::AlwaysFalse
|
||||
} else {
|
||||
Truthiness::Ambiguous
|
||||
}
|
||||
}
|
||||
PatternPredicateKind::Or(predicates) => {
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
let mut excluded_types = vec![];
|
||||
let (ControlFlow::Break(truthiness) | ControlFlow::Continue(truthiness)) =
|
||||
predicates
|
||||
.iter()
|
||||
.map(|p| {
|
||||
let narrowed_subject_ty = IntersectionBuilder::new(db)
|
||||
.add_positive(subject_ty)
|
||||
.add_negative(UnionType::from_elements(db, excluded_types.iter()))
|
||||
.build();
|
||||
|
||||
excluded_types.push(pattern_kind_to_type(db, p));
|
||||
|
||||
Self::analyze_single_pattern_predicate_kind(db, p, narrowed_subject_ty)
|
||||
})
|
||||
// this is just a "max", but with a slight optimization: `AlwaysTrue` is the "greatest" possible element, so we short-circuit if we get there
|
||||
.try_fold(Truthiness::AlwaysFalse, |acc, next| match (acc, next) {
|
||||
(Truthiness::AlwaysTrue, _) | (_, Truthiness::AlwaysTrue) => {
|
||||
ControlFlow::Break(Truthiness::AlwaysTrue)
|
||||
}
|
||||
(Truthiness::Ambiguous, _) | (_, Truthiness::Ambiguous) => {
|
||||
ControlFlow::Continue(Truthiness::Ambiguous)
|
||||
}
|
||||
(Truthiness::AlwaysFalse, Truthiness::AlwaysFalse) => {
|
||||
ControlFlow::Continue(Truthiness::AlwaysFalse)
|
||||
}
|
||||
});
|
||||
truthiness
|
||||
}
|
||||
PatternPredicateKind::Class(class_expr, kind) => {
|
||||
let class_ty = infer_expression_type(db, *class_expr, TypeContext::default())
|
||||
.as_class_literal()
|
||||
.map(|class| Type::instance(db, class.top_materialization(db)));
|
||||
|
||||
class_ty.map_or(Truthiness::Ambiguous, |class_ty| {
|
||||
if subject_ty.is_subtype_of(db, class_ty) {
|
||||
if kind.is_irrefutable() {
|
||||
Truthiness::AlwaysTrue
|
||||
} else {
|
||||
// A class pattern like `case Point(x=0, y=0)` is not irrefutable,
|
||||
// i.e. it does not match all instances of `Point`. This means that
|
||||
// we can't tell for sure if this pattern will match or not.
|
||||
Truthiness::Ambiguous
|
||||
}
|
||||
} else if subject_ty.is_disjoint_from(db, class_ty) {
|
||||
Truthiness::AlwaysFalse
|
||||
} else {
|
||||
Truthiness::Ambiguous
|
||||
}
|
||||
})
|
||||
}
|
||||
PatternPredicateKind::As(pattern, _) => pattern
|
||||
.as_deref()
|
||||
.map(|p| Self::analyze_single_pattern_predicate_kind(db, p, subject_ty))
|
||||
.unwrap_or(Truthiness::AlwaysTrue),
|
||||
PatternPredicateKind::Unsupported => Truthiness::Ambiguous,
|
||||
}
|
||||
}
|
||||
|
||||
fn analyze_single(db: &dyn Db, predicate: &Predicate) -> Truthiness {
|
||||
let _span = tracing::trace_span!("analyze_single", ?predicate).entered();
|
||||
|
||||
match predicate.node {
|
||||
PredicateNode::Expression(test_expr) => {
|
||||
static_expression_truthiness(db, test_expr).negate_if(!predicate.is_positive)
|
||||
}
|
||||
PredicateNode::ReturnsNever(CallableAndCallExpr {
|
||||
callable,
|
||||
call_expr,
|
||||
}) => {
|
||||
// We first infer just the type of the callable. In the most likely case that the
|
||||
// function is not marked with `NoReturn`, or that it always returns `NoReturn`,
|
||||
// doing so allows us to avoid the more expensive work of inferring the entire call
|
||||
// expression (which could involve inferring argument types to possibly run the overload
|
||||
// selection algorithm).
|
||||
// Avoiding this on the happy-path is important because these constraints can be
|
||||
// very large in number, since we add them on all statement level function calls.
|
||||
let ty = infer_expression_type(db, callable, TypeContext::default());
|
||||
|
||||
// Short-circuit for well known types that are known not to return `Never` when called.
|
||||
// Without the short-circuit, we've seen that threads keep blocking each other
|
||||
// because they all try to acquire Salsa's `CallableType` lock that ensures each type
|
||||
// is only interned once. The lock is so heavily congested because there are only
|
||||
// very few dynamic types, in which case Salsa's sharding the locks by value
|
||||
// doesn't help much.
|
||||
// See <https://github.com/astral-sh/ty/issues/968>.
|
||||
if matches!(ty, Type::Dynamic(_)) {
|
||||
return Truthiness::AlwaysFalse.negate_if(!predicate.is_positive);
|
||||
}
|
||||
|
||||
let overloads_iterator = if let Some(callable) = ty
|
||||
.try_upcast_to_callable(db)
|
||||
.and_then(CallableTypes::exactly_one)
|
||||
{
|
||||
callable.signatures(db).overloads.iter()
|
||||
} else {
|
||||
return Truthiness::AlwaysFalse.negate_if(!predicate.is_positive);
|
||||
};
|
||||
|
||||
let (no_overloads_return_never, all_overloads_return_never) = overloads_iterator
|
||||
.fold((true, true), |(none, all), overload| {
|
||||
let overload_returns_never =
|
||||
overload.return_ty.is_some_and(|return_type| {
|
||||
return_type.is_equivalent_to(db, Type::Never)
|
||||
});
|
||||
|
||||
(
|
||||
none && !overload_returns_never,
|
||||
all && overload_returns_never,
|
||||
)
|
||||
});
|
||||
|
||||
if no_overloads_return_never {
|
||||
Truthiness::AlwaysFalse
|
||||
} else if all_overloads_return_never {
|
||||
Truthiness::AlwaysTrue
|
||||
} else {
|
||||
let call_expr_ty = infer_expression_type(db, call_expr, TypeContext::default());
|
||||
if call_expr_ty.is_equivalent_to(db, Type::Never) {
|
||||
Truthiness::AlwaysTrue
|
||||
} else {
|
||||
Truthiness::AlwaysFalse
|
||||
}
|
||||
}
|
||||
.negate_if(!predicate.is_positive)
|
||||
}
|
||||
PredicateNode::Pattern(inner) => analyze_pattern_predicate(db, inner),
|
||||
PredicateNode::StarImportPlaceholder(star_import) => {
|
||||
let place_table = place_table(db, star_import.scope(db));
|
||||
let symbol = place_table.symbol(star_import.symbol_id(db));
|
||||
let referenced_file = star_import.referenced_file(db);
|
||||
|
||||
let requires_explicit_reexport = match dunder_all_names(db, referenced_file) {
|
||||
Some(all_names) => {
|
||||
if all_names.contains(symbol.name()) {
|
||||
Some(RequiresExplicitReExport::No)
|
||||
} else {
|
||||
tracing::trace!(
|
||||
"Symbol `{}` (via star import) not found in `__all__` of `{}`",
|
||||
symbol.name(),
|
||||
referenced_file.path(db)
|
||||
);
|
||||
return Truthiness::AlwaysFalse;
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
match imported_symbol(
|
||||
db,
|
||||
referenced_file,
|
||||
symbol.name(),
|
||||
requires_explicit_reexport,
|
||||
)
|
||||
.place
|
||||
{
|
||||
crate::place::Place::Defined(
|
||||
_,
|
||||
_,
|
||||
crate::place::Definedness::AlwaysDefined,
|
||||
_,
|
||||
) => Truthiness::AlwaysTrue,
|
||||
crate::place::Place::Defined(
|
||||
_,
|
||||
_,
|
||||
crate::place::Definedness::PossiblyUndefined,
|
||||
_,
|
||||
) => Truthiness::Ambiguous,
|
||||
crate::place::Place::Undefined => Truthiness::AlwaysFalse,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ use crate::{
|
||||
semantic_index::{
|
||||
SemanticIndex, reachability_constraints::ScopedReachabilityConstraintId, semantic_index,
|
||||
},
|
||||
types::{GenericContext, binding_type, infer_definition_types},
|
||||
};
|
||||
|
||||
/// A cross-module identifier of a scope that can be used as a salsa query parameter.
|
||||
@@ -27,20 +26,20 @@ pub struct ScopeId<'db> {
|
||||
impl get_size2::GetSize for ScopeId<'_> {}
|
||||
|
||||
impl<'db> ScopeId<'db> {
|
||||
pub(crate) fn is_annotation(self, db: &'db dyn Db) -> bool {
|
||||
pub fn is_annotation(self, db: &'db dyn Db) -> bool {
|
||||
self.node(db).scope_kind().is_annotation()
|
||||
}
|
||||
|
||||
pub(crate) fn node(self, db: &dyn Db) -> &NodeWithScopeKind {
|
||||
pub fn node(self, db: &dyn Db) -> &NodeWithScopeKind {
|
||||
self.scope(db).node()
|
||||
}
|
||||
|
||||
pub(crate) fn scope(self, db: &dyn Db) -> &Scope {
|
||||
pub fn scope(self, db: &dyn Db) -> &Scope {
|
||||
semantic_index(db, self.file(db)).scope(self.file_scope_id(db))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn name<'ast>(self, db: &'db dyn Db, module: &'ast ParsedModuleRef) -> &'ast str {
|
||||
#[cfg(any(test, feature = "testing"))]
|
||||
pub fn name<'ast>(self, db: &'db dyn Db, module: &'ast ParsedModuleRef) -> &'ast str {
|
||||
match self.node(db) {
|
||||
NodeWithScopeKind::Module => "<module>",
|
||||
NodeWithScopeKind::Class(class) | NodeWithScopeKind::ClassTypeParameters(class) => {
|
||||
@@ -86,13 +85,13 @@ impl FileScopeId {
|
||||
index.scope_ids_by_scope[self]
|
||||
}
|
||||
|
||||
pub(crate) fn is_generator_function(self, index: &SemanticIndex) -> bool {
|
||||
pub fn is_generator_function(self, index: &SemanticIndex) -> bool {
|
||||
index.generator_functions.contains(&self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) struct Scope {
|
||||
pub struct Scope {
|
||||
/// The parent scope, if any.
|
||||
parent: Option<FileScopeId>,
|
||||
|
||||
@@ -126,23 +125,23 @@ impl Scope {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parent(&self) -> Option<FileScopeId> {
|
||||
pub fn parent(&self) -> Option<FileScopeId> {
|
||||
self.parent
|
||||
}
|
||||
|
||||
pub(crate) fn node(&self) -> &NodeWithScopeKind {
|
||||
pub fn node(&self) -> &NodeWithScopeKind {
|
||||
&self.node
|
||||
}
|
||||
|
||||
pub(crate) fn kind(&self) -> ScopeKind {
|
||||
pub fn kind(&self) -> ScopeKind {
|
||||
self.node().scope_kind()
|
||||
}
|
||||
|
||||
pub(crate) fn visibility(&self) -> ScopeVisibility {
|
||||
pub fn visibility(&self) -> ScopeVisibility {
|
||||
self.kind().visibility()
|
||||
}
|
||||
|
||||
pub(crate) fn descendants(&self) -> Range<FileScopeId> {
|
||||
pub fn descendants(&self) -> Range<FileScopeId> {
|
||||
self.descendants.clone()
|
||||
}
|
||||
|
||||
@@ -150,21 +149,21 @@ impl Scope {
|
||||
self.descendants = self.descendants.start..children_end;
|
||||
}
|
||||
|
||||
pub(crate) fn is_eager(&self) -> bool {
|
||||
pub fn is_eager(&self) -> bool {
|
||||
self.kind().is_eager()
|
||||
}
|
||||
|
||||
pub(crate) fn reachability(&self) -> ScopedReachabilityConstraintId {
|
||||
pub fn reachability(&self) -> ScopedReachabilityConstraintId {
|
||||
self.reachability
|
||||
}
|
||||
|
||||
pub(crate) fn in_type_checking_block(&self) -> bool {
|
||||
pub fn in_type_checking_block(&self) -> bool {
|
||||
self.in_type_checking_block
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, get_size2::GetSize)]
|
||||
pub(crate) enum ScopeVisibility {
|
||||
pub enum ScopeVisibility {
|
||||
/// The scope is private (e.g. function, type alias, comprehension scope).
|
||||
Private,
|
||||
/// The scope is public (e.g. module, class scope).
|
||||
@@ -172,17 +171,17 @@ pub(crate) enum ScopeVisibility {
|
||||
}
|
||||
|
||||
impl ScopeVisibility {
|
||||
pub(crate) const fn is_public(self) -> bool {
|
||||
pub const fn is_public(self) -> bool {
|
||||
matches!(self, ScopeVisibility::Public)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_private(self) -> bool {
|
||||
pub const fn is_private(self) -> bool {
|
||||
matches!(self, ScopeVisibility::Private)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, get_size2::GetSize)]
|
||||
pub(crate) enum ScopeLaziness {
|
||||
pub enum ScopeLaziness {
|
||||
/// The scope is evaluated lazily (e.g. function, type alias scope).
|
||||
Lazy,
|
||||
/// The scope is evaluated eagerly (e.g. module, class, comprehension scope).
|
||||
@@ -190,17 +189,17 @@ pub(crate) enum ScopeLaziness {
|
||||
}
|
||||
|
||||
impl ScopeLaziness {
|
||||
pub(crate) const fn is_eager(self) -> bool {
|
||||
pub const fn is_eager(self) -> bool {
|
||||
matches!(self, ScopeLaziness::Eager)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_lazy(self) -> bool {
|
||||
pub const fn is_lazy(self) -> bool {
|
||||
matches!(self, ScopeLaziness::Lazy)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum ScopeKind {
|
||||
pub enum ScopeKind {
|
||||
Module,
|
||||
TypeParams,
|
||||
Class,
|
||||
@@ -211,11 +210,11 @@ pub(crate) enum ScopeKind {
|
||||
}
|
||||
|
||||
impl ScopeKind {
|
||||
pub(crate) const fn is_eager(self) -> bool {
|
||||
pub const fn is_eager(self) -> bool {
|
||||
self.laziness().is_eager()
|
||||
}
|
||||
|
||||
pub(crate) const fn laziness(self) -> ScopeLaziness {
|
||||
pub const fn laziness(self) -> ScopeLaziness {
|
||||
match self {
|
||||
ScopeKind::Module
|
||||
| ScopeKind::Class
|
||||
@@ -225,7 +224,7 @@ impl ScopeKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn visibility(self) -> ScopeVisibility {
|
||||
pub const fn visibility(self) -> ScopeVisibility {
|
||||
match self {
|
||||
ScopeKind::Module | ScopeKind::Class => ScopeVisibility::Public,
|
||||
ScopeKind::TypeParams
|
||||
@@ -236,7 +235,7 @@ impl ScopeKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn is_function_like(self) -> bool {
|
||||
pub const fn is_function_like(self) -> bool {
|
||||
// Type parameter scopes behave like function scopes in terms of name resolution; CPython
|
||||
// symbol table also uses the term "function-like" for these scopes.
|
||||
matches!(
|
||||
@@ -249,26 +248,26 @@ impl ScopeKind {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_class(self) -> bool {
|
||||
pub const fn is_class(self) -> bool {
|
||||
matches!(self, ScopeKind::Class)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_module(self) -> bool {
|
||||
pub const fn is_module(self) -> bool {
|
||||
matches!(self, ScopeKind::Module)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_annotation(self) -> bool {
|
||||
pub const fn is_annotation(self) -> bool {
|
||||
matches!(self, ScopeKind::TypeParams | ScopeKind::TypeAlias)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_non_lambda_function(self) -> bool {
|
||||
pub const fn is_non_lambda_function(self) -> bool {
|
||||
matches!(self, ScopeKind::Function)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reference to a node that introduces a new scope.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) enum NodeWithScopeRef<'a> {
|
||||
pub enum NodeWithScopeRef<'a> {
|
||||
Module,
|
||||
Class(&'a ast::StmtClassDef),
|
||||
Function(&'a ast::StmtFunctionDef),
|
||||
@@ -326,7 +325,7 @@ impl NodeWithScopeRef<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn node_key(self) -> NodeWithScopeKey {
|
||||
pub fn node_key(self) -> NodeWithScopeKey {
|
||||
match self {
|
||||
NodeWithScopeRef::Module => NodeWithScopeKey::Module,
|
||||
NodeWithScopeRef::Class(class) => NodeWithScopeKey::Class(NodeKey::from_node(class)),
|
||||
@@ -366,7 +365,7 @@ impl NodeWithScopeRef<'_> {
|
||||
|
||||
/// Node that introduces a new scope.
|
||||
#[derive(Clone, Debug, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) enum NodeWithScopeKind {
|
||||
pub enum NodeWithScopeKind {
|
||||
Module,
|
||||
Class(AstNodeRef<ast::StmtClassDef>),
|
||||
ClassTypeParameters(AstNodeRef<ast::StmtClassDef>),
|
||||
@@ -382,7 +381,7 @@ pub(crate) enum NodeWithScopeKind {
|
||||
}
|
||||
|
||||
impl NodeWithScopeKind {
|
||||
pub(crate) const fn scope_kind(&self) -> ScopeKind {
|
||||
pub const fn scope_kind(&self) -> ScopeKind {
|
||||
match self {
|
||||
Self::Module => ScopeKind::Module,
|
||||
Self::Class(_) => ScopeKind::Class,
|
||||
@@ -399,74 +398,42 @@ impl NodeWithScopeKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_class(&self) -> Option<&AstNodeRef<ast::StmtClassDef>> {
|
||||
pub fn as_class(&self) -> Option<&AstNodeRef<ast::StmtClassDef>> {
|
||||
match self {
|
||||
Self::Class(class) => Some(class),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn expect_class(&self) -> &AstNodeRef<ast::StmtClassDef> {
|
||||
pub fn expect_class(&self) -> &AstNodeRef<ast::StmtClassDef> {
|
||||
self.as_class().expect("expected class")
|
||||
}
|
||||
|
||||
pub(crate) fn as_function(&self) -> Option<&AstNodeRef<ast::StmtFunctionDef>> {
|
||||
pub fn as_function(&self) -> Option<&AstNodeRef<ast::StmtFunctionDef>> {
|
||||
match self {
|
||||
Self::Function(function) => Some(function),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn expect_function(&self) -> &AstNodeRef<ast::StmtFunctionDef> {
|
||||
pub fn expect_function(&self) -> &AstNodeRef<ast::StmtFunctionDef> {
|
||||
self.as_function().expect("expected function")
|
||||
}
|
||||
|
||||
pub(crate) fn as_type_alias(&self) -> Option<&AstNodeRef<ast::StmtTypeAlias>> {
|
||||
pub fn as_type_alias(&self) -> Option<&AstNodeRef<ast::StmtTypeAlias>> {
|
||||
match self {
|
||||
Self::TypeAlias(type_alias) => Some(type_alias),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn expect_type_alias(&self) -> &AstNodeRef<ast::StmtTypeAlias> {
|
||||
pub fn expect_type_alias(&self) -> &AstNodeRef<ast::StmtTypeAlias> {
|
||||
self.as_type_alias().expect("expected type alias")
|
||||
}
|
||||
|
||||
pub(crate) fn generic_context<'db>(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
index: &SemanticIndex<'db>,
|
||||
) -> Option<GenericContext<'db>> {
|
||||
match self {
|
||||
NodeWithScopeKind::Class(class) => {
|
||||
let definition = index.expect_single_definition(class);
|
||||
binding_type(db, definition)
|
||||
.as_class_literal()?
|
||||
.generic_context(db)
|
||||
}
|
||||
NodeWithScopeKind::Function(function) => {
|
||||
let definition = index.expect_single_definition(function);
|
||||
infer_definition_types(db, definition)
|
||||
.undecorated_type()
|
||||
.expect("function should have undecorated type")
|
||||
.as_function_literal()?
|
||||
.last_definition_signature(db)
|
||||
.generic_context
|
||||
}
|
||||
NodeWithScopeKind::TypeAlias(type_alias) => {
|
||||
let definition = index.expect_single_definition(type_alias);
|
||||
binding_type(db, definition)
|
||||
.as_type_alias()?
|
||||
.as_pep_695_type_alias()?
|
||||
.generic_context(db)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
|
||||
pub(crate) enum NodeWithScopeKey {
|
||||
pub enum NodeWithScopeKey {
|
||||
Module,
|
||||
Class(NodeKey),
|
||||
ClassTypeParameters(NodeKey),
|
||||
|
||||
@@ -13,7 +13,7 @@ pub struct ScopedSymbolId;
|
||||
|
||||
/// A symbol in a given scope.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, get_size2::GetSize, salsa::Update)]
|
||||
pub(crate) struct Symbol {
|
||||
pub struct Symbol {
|
||||
name: Name,
|
||||
flags: SymbolFlags,
|
||||
}
|
||||
@@ -52,32 +52,32 @@ impl Symbol {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn name(&self) -> &Name {
|
||||
pub fn name(&self) -> &Name {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// Is the symbol used in its containing scope?
|
||||
pub(crate) fn is_used(&self) -> bool {
|
||||
pub fn is_used(&self) -> bool {
|
||||
self.flags.contains(SymbolFlags::IS_USED)
|
||||
}
|
||||
|
||||
/// Is the symbol given a value in its containing scope?
|
||||
pub(crate) const fn is_bound(&self) -> bool {
|
||||
pub const fn is_bound(&self) -> bool {
|
||||
self.flags.contains(SymbolFlags::IS_BOUND)
|
||||
}
|
||||
|
||||
/// Is the symbol declared in its containing scope?
|
||||
pub(crate) fn is_declared(&self) -> bool {
|
||||
pub fn is_declared(&self) -> bool {
|
||||
self.flags.contains(SymbolFlags::IS_DECLARED)
|
||||
}
|
||||
|
||||
/// Is the symbol `global` its containing scope?
|
||||
pub(crate) fn is_global(&self) -> bool {
|
||||
pub fn is_global(&self) -> bool {
|
||||
self.flags.contains(SymbolFlags::MARKED_GLOBAL)
|
||||
}
|
||||
|
||||
/// Is the symbol `nonlocal` its containing scope?
|
||||
pub(crate) fn is_nonlocal(&self) -> bool {
|
||||
pub fn is_nonlocal(&self) -> bool {
|
||||
self.flags.contains(SymbolFlags::MARKED_NONLOCAL)
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ impl Symbol {
|
||||
/// In cases like this, the resolution isn't known until runtime, and in fact it varies from
|
||||
/// one use to the next. The semantic index alone can't resolve this, and instead it's a
|
||||
/// special case in type inference (see `infer_place_load`).
|
||||
pub(crate) fn is_local(&self) -> bool {
|
||||
pub fn is_local(&self) -> bool {
|
||||
!self.is_global() && !self.is_nonlocal() && (self.is_bound() || self.is_declared())
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ impl Symbol {
|
||||
self.flags.contains(SymbolFlags::IS_REASSIGNED)
|
||||
}
|
||||
|
||||
pub(crate) fn is_parameter(&self) -> bool {
|
||||
pub fn is_parameter(&self) -> bool {
|
||||
self.flags.contains(SymbolFlags::IS_PARAMETER)
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ impl SymbolTable {
|
||||
/// ## Panics
|
||||
/// If the ID is not valid for this symbol table.
|
||||
#[track_caller]
|
||||
pub(crate) fn symbol(&self, id: ScopedSymbolId) -> &Symbol {
|
||||
pub(super) fn symbol(&self, id: ScopedSymbolId) -> &Symbol {
|
||||
&self.symbols[id]
|
||||
}
|
||||
|
||||
@@ -182,19 +182,19 @@ impl SymbolTable {
|
||||
/// ## Panics
|
||||
/// If the ID is not valid for this symbol table.
|
||||
#[track_caller]
|
||||
pub(crate) fn symbol_mut(&mut self, id: ScopedSymbolId) -> &mut Symbol {
|
||||
pub(super) fn symbol_mut(&mut self, id: ScopedSymbolId) -> &mut Symbol {
|
||||
&mut self.symbols[id]
|
||||
}
|
||||
|
||||
/// Look up the ID of a symbol by its name.
|
||||
pub(crate) fn symbol_id(&self, name: &str) -> Option<ScopedSymbolId> {
|
||||
pub(super) fn symbol_id(&self, name: &str) -> Option<ScopedSymbolId> {
|
||||
self.map
|
||||
.find(Self::hash_name(name), |id| self.symbols[*id].name == name)
|
||||
.copied()
|
||||
}
|
||||
|
||||
/// Iterate over the symbols in this symbol table.
|
||||
pub(crate) fn iter(&self) -> std::slice::Iter<'_, Symbol> {
|
||||
pub(super) fn iter(&self) -> std::slice::Iter<'_, Symbol> {
|
||||
self.symbols.iter()
|
||||
}
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ use ruff_index::{IndexVec, newtype_index};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::node_key::NodeKey;
|
||||
use crate::place::BoundnessAnalysis;
|
||||
use crate::place_qualifiers::BoundnessAnalysis;
|
||||
use crate::semantic_index::ast_ids::ScopedUseId;
|
||||
use crate::semantic_index::definition::{Definition, DefinitionState};
|
||||
use crate::semantic_index::member::ScopedMemberId;
|
||||
@@ -266,13 +266,12 @@ use crate::semantic_index::use_def::place_state::{
|
||||
LiveDeclarationsIterator, PlaceState, PreviousDefinitions, ScopedDefinitionId,
|
||||
};
|
||||
use crate::semantic_index::{EnclosingSnapshotResult, SemanticIndex};
|
||||
use crate::types::{IntersectionBuilder, Truthiness, Type, infer_narrowing_constraint};
|
||||
|
||||
mod place_state;
|
||||
|
||||
/// Applicable definitions and constraints for every use of a name.
|
||||
#[derive(Debug, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) struct UseDefMap<'db> {
|
||||
pub struct UseDefMap<'db> {
|
||||
/// Array of [`Definition`] in this scope. Only the first entry should be [`DefinitionState::Undefined`];
|
||||
/// this represents the implicit "unbound"/"undeclared" definition of every place.
|
||||
all_definitions: IndexVec<ScopedDefinitionId, DefinitionState<'db>>,
|
||||
@@ -348,23 +347,20 @@ pub(crate) struct UseDefMap<'db> {
|
||||
end_of_scope_reachability: ScopedReachabilityConstraintId,
|
||||
}
|
||||
|
||||
pub(crate) enum ApplicableConstraints<'map, 'db> {
|
||||
pub enum ApplicableConstraints<'map, 'db> {
|
||||
UnboundBinding(ConstraintsIterator<'map, 'db>),
|
||||
ConstrainedBindings(BindingWithConstraintsIterator<'map, 'db>),
|
||||
}
|
||||
|
||||
impl<'db> UseDefMap<'db> {
|
||||
pub(crate) fn bindings_at_use(
|
||||
&self,
|
||||
use_id: ScopedUseId,
|
||||
) -> BindingWithConstraintsIterator<'_, 'db> {
|
||||
pub fn bindings_at_use(&self, use_id: ScopedUseId) -> BindingWithConstraintsIterator<'_, 'db> {
|
||||
self.bindings_iterator(
|
||||
&self.bindings_by_use[use_id],
|
||||
BoundnessAnalysis::BasedOnUnboundVisibility,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn applicable_constraints(
|
||||
pub fn applicable_constraints(
|
||||
&self,
|
||||
constraint_key: ConstraintKey,
|
||||
enclosing_scope: FileScopeId,
|
||||
@@ -394,36 +390,33 @@ impl<'db> UseDefMap<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn is_reachable(
|
||||
&self,
|
||||
db: &dyn crate::Db,
|
||||
reachability: ScopedReachabilityConstraintId,
|
||||
) -> bool {
|
||||
self.reachability_constraints
|
||||
.evaluate(db, &self.predicates, reachability)
|
||||
.may_be_true()
|
||||
/// Returns a reference to the reachability constraints.
|
||||
pub fn reachability_constraints(&self) -> &ReachabilityConstraints {
|
||||
&self.reachability_constraints
|
||||
}
|
||||
|
||||
/// Check whether or not a given expression is reachable from the start of the scope. This
|
||||
/// is a local analysis which does not capture the possibility that the entire scope might
|
||||
/// be unreachable. Use [`super::SemanticIndex::is_node_reachable`] for the global
|
||||
/// analysis.
|
||||
/// Returns a reference to the predicates.
|
||||
pub fn predicates(&self) -> &Predicates<'db> {
|
||||
&self.predicates
|
||||
}
|
||||
|
||||
/// Returns the end-of-scope reachability constraint ID.
|
||||
pub fn end_of_scope_reachability(&self) -> ScopedReachabilityConstraintId {
|
||||
self.end_of_scope_reachability
|
||||
}
|
||||
|
||||
/// Returns the reachability constraint ID for a given node.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if the node key is not in the reachability map.
|
||||
#[track_caller]
|
||||
pub(super) fn is_node_reachable(&self, db: &dyn crate::Db, node_key: NodeKey) -> bool {
|
||||
self
|
||||
.reachability_constraints
|
||||
.evaluate(
|
||||
db,
|
||||
&self.predicates,
|
||||
*self
|
||||
.node_reachability
|
||||
.get(&node_key)
|
||||
.expect("`is_node_reachable` should only be called on AST nodes with recorded reachability"),
|
||||
)
|
||||
.may_be_true()
|
||||
pub fn node_reachability(&self, node_key: NodeKey) -> ScopedReachabilityConstraintId {
|
||||
*self.node_reachability.get(&node_key).expect(
|
||||
"`node_reachability` should only be called on AST nodes with recorded reachability",
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn end_of_scope_bindings(
|
||||
pub fn end_of_scope_bindings(
|
||||
&self,
|
||||
place: ScopedPlaceId,
|
||||
) -> BindingWithConstraintsIterator<'_, 'db> {
|
||||
@@ -433,7 +426,7 @@ impl<'db> UseDefMap<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn end_of_scope_symbol_bindings(
|
||||
pub fn end_of_scope_symbol_bindings(
|
||||
&self,
|
||||
symbol: ScopedSymbolId,
|
||||
) -> BindingWithConstraintsIterator<'_, 'db> {
|
||||
@@ -453,7 +446,7 @@ impl<'db> UseDefMap<'db> {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn reachable_bindings(
|
||||
pub fn reachable_bindings(
|
||||
&self,
|
||||
place: ScopedPlaceId,
|
||||
) -> BindingWithConstraintsIterator<'_, 'db> {
|
||||
@@ -463,7 +456,7 @@ impl<'db> UseDefMap<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn reachable_symbol_bindings(
|
||||
pub fn reachable_symbol_bindings(
|
||||
&self,
|
||||
symbol: ScopedSymbolId,
|
||||
) -> BindingWithConstraintsIterator<'_, 'db> {
|
||||
@@ -471,7 +464,7 @@ impl<'db> UseDefMap<'db> {
|
||||
self.bindings_iterator(bindings, BoundnessAnalysis::AssumeBound)
|
||||
}
|
||||
|
||||
pub(crate) fn reachable_member_bindings(
|
||||
pub fn reachable_member_bindings(
|
||||
&self,
|
||||
symbol: ScopedMemberId,
|
||||
) -> BindingWithConstraintsIterator<'_, 'db> {
|
||||
@@ -501,7 +494,7 @@ impl<'db> UseDefMap<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn bindings_at_definition(
|
||||
pub fn bindings_at_definition(
|
||||
&self,
|
||||
definition: Definition<'db>,
|
||||
) -> BindingWithConstraintsIterator<'_, 'db> {
|
||||
@@ -511,7 +504,7 @@ impl<'db> UseDefMap<'db> {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn declarations_at_binding(
|
||||
pub fn declarations_at_binding(
|
||||
&self,
|
||||
binding: Definition<'db>,
|
||||
) -> DeclarationsIterator<'_, 'db> {
|
||||
@@ -521,7 +514,7 @@ impl<'db> UseDefMap<'db> {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn end_of_scope_declarations<'map>(
|
||||
pub fn end_of_scope_declarations<'map>(
|
||||
&'map self,
|
||||
place: ScopedPlaceId,
|
||||
) -> DeclarationsIterator<'map, 'db> {
|
||||
@@ -531,7 +524,7 @@ impl<'db> UseDefMap<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn end_of_scope_symbol_declarations<'map>(
|
||||
pub fn end_of_scope_symbol_declarations<'map>(
|
||||
&'map self,
|
||||
symbol: ScopedSymbolId,
|
||||
) -> DeclarationsIterator<'map, 'db> {
|
||||
@@ -547,7 +540,7 @@ impl<'db> UseDefMap<'db> {
|
||||
self.declarations_iterator(declarations, BoundnessAnalysis::BasedOnUnboundVisibility)
|
||||
}
|
||||
|
||||
pub(crate) fn reachable_symbol_declarations(
|
||||
pub fn reachable_symbol_declarations(
|
||||
&self,
|
||||
symbol: ScopedSymbolId,
|
||||
) -> DeclarationsIterator<'_, 'db> {
|
||||
@@ -555,7 +548,7 @@ impl<'db> UseDefMap<'db> {
|
||||
self.declarations_iterator(declarations, BoundnessAnalysis::AssumeBound)
|
||||
}
|
||||
|
||||
pub(crate) fn reachable_member_declarations(
|
||||
pub fn reachable_member_declarations(
|
||||
&self,
|
||||
member: ScopedMemberId,
|
||||
) -> DeclarationsIterator<'_, 'db> {
|
||||
@@ -563,17 +556,14 @@ impl<'db> UseDefMap<'db> {
|
||||
self.declarations_iterator(declarations, BoundnessAnalysis::AssumeBound)
|
||||
}
|
||||
|
||||
pub(crate) fn reachable_declarations(
|
||||
&self,
|
||||
place: ScopedPlaceId,
|
||||
) -> DeclarationsIterator<'_, 'db> {
|
||||
pub fn reachable_declarations(&self, place: ScopedPlaceId) -> DeclarationsIterator<'_, 'db> {
|
||||
match place {
|
||||
ScopedPlaceId::Symbol(symbol) => self.reachable_symbol_declarations(symbol),
|
||||
ScopedPlaceId::Member(member) => self.reachable_member_declarations(member),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn all_end_of_scope_symbol_declarations<'map>(
|
||||
pub fn all_end_of_scope_symbol_declarations<'map>(
|
||||
&'map self,
|
||||
) -> impl Iterator<Item = (ScopedSymbolId, DeclarationsIterator<'map, 'db>)> + 'map {
|
||||
self.end_of_scope_symbols
|
||||
@@ -581,7 +571,7 @@ impl<'db> UseDefMap<'db> {
|
||||
.map(|symbol_id| (symbol_id, self.end_of_scope_symbol_declarations(symbol_id)))
|
||||
}
|
||||
|
||||
pub(crate) fn all_end_of_scope_symbol_bindings<'map>(
|
||||
pub fn all_end_of_scope_symbol_bindings<'map>(
|
||||
&'map self,
|
||||
) -> impl Iterator<Item = (ScopedSymbolId, BindingWithConstraintsIterator<'map, 'db>)> + 'map
|
||||
{
|
||||
@@ -590,7 +580,7 @@ impl<'db> UseDefMap<'db> {
|
||||
.map(|symbol_id| (symbol_id, self.end_of_scope_symbol_bindings(symbol_id)))
|
||||
}
|
||||
|
||||
pub(crate) fn all_reachable_symbols<'map>(
|
||||
pub fn all_reachable_symbols<'map>(
|
||||
&'map self,
|
||||
) -> impl Iterator<
|
||||
Item = (
|
||||
@@ -614,26 +604,6 @@ impl<'db> UseDefMap<'db> {
|
||||
)
|
||||
}
|
||||
|
||||
/// This function is intended to be called only once inside `TypeInferenceBuilder::infer_function_body`.
|
||||
pub(crate) fn can_implicitly_return_none(&self, db: &dyn crate::Db) -> bool {
|
||||
!self
|
||||
.reachability_constraints
|
||||
.evaluate(db, &self.predicates, self.end_of_scope_reachability)
|
||||
.is_always_false()
|
||||
}
|
||||
|
||||
pub(crate) fn binding_reachability(
|
||||
&self,
|
||||
db: &dyn crate::Db,
|
||||
binding: &BindingWithConstraints<'_, 'db>,
|
||||
) -> Truthiness {
|
||||
self.reachability_constraints.evaluate(
|
||||
db,
|
||||
&self.predicates,
|
||||
binding.reachability_constraint,
|
||||
)
|
||||
}
|
||||
|
||||
fn bindings_iterator<'map>(
|
||||
&'map self,
|
||||
bindings: &'map Bindings,
|
||||
@@ -674,10 +644,10 @@ impl<'db> UseDefMap<'db> {
|
||||
/// There is a unique ID for each distinct [`EnclosingSnapshotKey`] in the file.
|
||||
#[newtype_index]
|
||||
#[derive(get_size2::GetSize)]
|
||||
pub(crate) struct ScopedEnclosingSnapshotId;
|
||||
pub struct ScopedEnclosingSnapshotId;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
|
||||
pub(crate) struct EnclosingSnapshotKey {
|
||||
pub struct EnclosingSnapshotKey {
|
||||
/// The enclosing scope containing the bindings
|
||||
pub(crate) enclosing_scope: FileScopeId,
|
||||
/// The referenced place (in the enclosing scope)
|
||||
@@ -695,12 +665,12 @@ pub(crate) struct EnclosingSnapshotKey {
|
||||
type EnclosingSnapshots = IndexVec<ScopedEnclosingSnapshotId, EnclosingSnapshot>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct BindingWithConstraintsIterator<'map, 'db> {
|
||||
pub struct BindingWithConstraintsIterator<'map, 'db> {
|
||||
all_definitions: &'map IndexVec<ScopedDefinitionId, DefinitionState<'db>>,
|
||||
pub(crate) predicates: &'map Predicates<'db>,
|
||||
pub(crate) narrowing_constraints: &'map NarrowingConstraints,
|
||||
pub(crate) reachability_constraints: &'map ReachabilityConstraints,
|
||||
pub(crate) boundness_analysis: BoundnessAnalysis,
|
||||
pub predicates: &'map Predicates<'db>,
|
||||
pub narrowing_constraints: &'map NarrowingConstraints,
|
||||
pub reachability_constraints: &'map ReachabilityConstraints,
|
||||
pub boundness_analysis: BoundnessAnalysis,
|
||||
inner: LiveBindingsIterator<'map>,
|
||||
}
|
||||
|
||||
@@ -727,13 +697,13 @@ impl<'map, 'db> Iterator for BindingWithConstraintsIterator<'map, 'db> {
|
||||
|
||||
impl std::iter::FusedIterator for BindingWithConstraintsIterator<'_, '_> {}
|
||||
|
||||
pub(crate) struct BindingWithConstraints<'map, 'db> {
|
||||
pub(crate) binding: DefinitionState<'db>,
|
||||
pub(crate) narrowing_constraint: ConstraintsIterator<'map, 'db>,
|
||||
pub(crate) reachability_constraint: ScopedReachabilityConstraintId,
|
||||
pub struct BindingWithConstraints<'map, 'db> {
|
||||
pub binding: DefinitionState<'db>,
|
||||
pub narrowing_constraint: ConstraintsIterator<'map, 'db>,
|
||||
pub reachability_constraint: ScopedReachabilityConstraintId,
|
||||
}
|
||||
|
||||
pub(crate) struct ConstraintsIterator<'map, 'db> {
|
||||
pub struct ConstraintsIterator<'map, 'db> {
|
||||
predicates: &'map Predicates<'db>,
|
||||
constraint_ids: NarrowingConstraintsIterator<'map>,
|
||||
}
|
||||
@@ -750,45 +720,21 @@ impl<'db> Iterator for ConstraintsIterator<'_, 'db> {
|
||||
|
||||
impl std::iter::FusedIterator for ConstraintsIterator<'_, '_> {}
|
||||
|
||||
impl<'db> ConstraintsIterator<'_, 'db> {
|
||||
pub(crate) fn narrow(
|
||||
self,
|
||||
db: &'db dyn crate::Db,
|
||||
base_ty: Type<'db>,
|
||||
place: ScopedPlaceId,
|
||||
) -> Type<'db> {
|
||||
let constraint_tys: Vec<_> = self
|
||||
.filter_map(|constraint| infer_narrowing_constraint(db, constraint, place))
|
||||
.collect();
|
||||
|
||||
if constraint_tys.is_empty() {
|
||||
base_ty
|
||||
} else {
|
||||
constraint_tys
|
||||
.into_iter()
|
||||
.rev()
|
||||
.fold(
|
||||
IntersectionBuilder::new(db).add_positive(base_ty),
|
||||
IntersectionBuilder::add_positive,
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
// The narrow() method was moved to ty_python_types::place as it depends on type inference
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct DeclarationsIterator<'map, 'db> {
|
||||
pub struct DeclarationsIterator<'map, 'db> {
|
||||
all_definitions: &'map IndexVec<ScopedDefinitionId, DefinitionState<'db>>,
|
||||
pub(crate) predicates: &'map Predicates<'db>,
|
||||
pub(crate) reachability_constraints: &'map ReachabilityConstraints,
|
||||
pub(crate) boundness_analysis: BoundnessAnalysis,
|
||||
pub predicates: &'map Predicates<'db>,
|
||||
pub reachability_constraints: &'map ReachabilityConstraints,
|
||||
pub boundness_analysis: BoundnessAnalysis,
|
||||
inner: LiveDeclarationsIterator<'map>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct DeclarationWithConstraint<'db> {
|
||||
pub(crate) declaration: DefinitionState<'db>,
|
||||
pub(crate) reachability_constraint: ScopedReachabilityConstraintId,
|
||||
pub struct DeclarationWithConstraint<'db> {
|
||||
pub declaration: DefinitionState<'db>,
|
||||
pub reachability_constraint: ScopedReachabilityConstraintId,
|
||||
}
|
||||
|
||||
impl<'db> Iterator for DeclarationsIterator<'_, 'db> {
|
||||
|
||||
@@ -7,9 +7,9 @@ use itertools::Either;
|
||||
use crate::Db;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub(crate) struct OutOfBoundsError;
|
||||
pub struct OutOfBoundsError;
|
||||
|
||||
pub(crate) trait PyIndex<'db> {
|
||||
pub trait PyIndex<'db> {
|
||||
type Item: 'db;
|
||||
|
||||
fn py_index(self, db: &'db dyn Db, index: i32) -> Result<Self::Item, OutOfBoundsError>;
|
||||
@@ -41,13 +41,13 @@ enum Position {
|
||||
AfterEnd,
|
||||
}
|
||||
|
||||
pub(crate) enum Nth {
|
||||
pub enum Nth {
|
||||
FromStart(usize),
|
||||
FromEnd(usize),
|
||||
}
|
||||
|
||||
impl Nth {
|
||||
pub(crate) fn from_index(index: i32) -> Self {
|
||||
pub fn from_index(index: i32) -> Self {
|
||||
if index >= 0 {
|
||||
Nth::FromStart(from_nonnegative_i32(index))
|
||||
} else {
|
||||
@@ -105,9 +105,9 @@ where
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub(crate) struct StepSizeZeroError;
|
||||
pub struct StepSizeZeroError;
|
||||
|
||||
pub(crate) trait PySlice<'db> {
|
||||
pub trait PySlice<'db> {
|
||||
type Item: 'db;
|
||||
|
||||
fn py_slice(
|
||||
|
||||
@@ -19,7 +19,6 @@ use crate::suppression::parser::{
|
||||
ParseError, ParseErrorKind, SuppressionComment, SuppressionParser,
|
||||
};
|
||||
use crate::suppression::unused::check_unused_suppressions;
|
||||
use crate::types::TypeCheckDiagnostics;
|
||||
use crate::{Db, declare_lint, lint::LintId};
|
||||
|
||||
declare_lint! {
|
||||
@@ -97,7 +96,7 @@ declare_lint! {
|
||||
}
|
||||
|
||||
#[salsa::tracked(returns(ref), heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) fn suppressions(db: &dyn Db, file: File) -> Suppressions {
|
||||
pub fn suppressions(db: &dyn Db, file: File) -> Suppressions {
|
||||
let parsed = parsed_module(db, file).load(db);
|
||||
let source = source_text(db, file);
|
||||
|
||||
@@ -152,7 +151,7 @@ pub(crate) fn suppressions(db: &dyn Db, file: File) -> Suppressions {
|
||||
builder.finish()
|
||||
}
|
||||
|
||||
pub(crate) fn check_suppressions(
|
||||
pub fn check_suppressions(
|
||||
db: &dyn Db,
|
||||
file: File,
|
||||
diagnostics: TypeCheckDiagnostics,
|
||||
@@ -252,7 +251,7 @@ impl<'a> CheckSuppressionsContext<'a> {
|
||||
///
|
||||
/// This type exists to separate the phases of "check if a diagnostic should
|
||||
/// be reported" and "build the actual diagnostic."
|
||||
pub(crate) struct SuppressionDiagnosticGuardBuilder<'ctx, 'db> {
|
||||
pub struct SuppressionDiagnosticGuardBuilder<'ctx, 'db> {
|
||||
ctx: &'ctx CheckSuppressionsContext<'db>,
|
||||
id: DiagnosticId,
|
||||
range: TextRange,
|
||||
@@ -296,7 +295,7 @@ impl<'ctx, 'db> SuppressionDiagnosticGuardBuilder<'ctx, 'db> {
|
||||
|
||||
/// The suppressions of a single file.
|
||||
#[derive(Debug, Eq, PartialEq, get_size2::GetSize)]
|
||||
pub(crate) struct Suppressions {
|
||||
pub struct Suppressions {
|
||||
/// Suppressions that apply to the entire file.
|
||||
///
|
||||
/// The suppressions are sorted by [`Suppression::comment_range`] and the [`Suppression::suppressed_range`]
|
||||
@@ -320,7 +319,7 @@ pub(crate) struct Suppressions {
|
||||
}
|
||||
|
||||
impl Suppressions {
|
||||
pub(crate) fn find_suppression(&self, range: TextRange, id: LintId) -> Option<&Suppression> {
|
||||
pub fn find_suppression(&self, range: TextRange, id: LintId) -> Option<&Suppression> {
|
||||
self.lint_suppressions(range, id).next()
|
||||
}
|
||||
|
||||
@@ -371,7 +370,7 @@ impl Suppressions {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type SuppressionsIter<'a> =
|
||||
pub type SuppressionsIter<'a> =
|
||||
std::iter::Chain<std::slice::Iter<'a, Suppression>, std::slice::Iter<'a, Suppression>>;
|
||||
|
||||
impl<'a> IntoIterator for &'a Suppressions {
|
||||
@@ -389,7 +388,7 @@ impl<'a> IntoIterator for &'a Suppressions {
|
||||
/// create multiple suppressions: one for every code.
|
||||
/// They all share the same `comment_range`.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, get_size2::GetSize)]
|
||||
pub(crate) struct Suppression {
|
||||
pub struct Suppression {
|
||||
target: SuppressionTarget,
|
||||
kind: SuppressionKind,
|
||||
|
||||
@@ -429,7 +428,7 @@ impl Suppression {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn id(&self) -> FileSuppressionId {
|
||||
pub fn id(&self) -> FileSuppressionId {
|
||||
FileSuppressionId(self.range)
|
||||
}
|
||||
}
|
||||
@@ -469,7 +468,90 @@ impl fmt::Display for SuppressionKind {
|
||||
/// This is unique enough because it is its exact
|
||||
/// location in the source.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
|
||||
pub(crate) struct FileSuppressionId(TextRange);
|
||||
pub struct FileSuppressionId(TextRange);
|
||||
|
||||
/// A collection of type check diagnostics.
|
||||
///
|
||||
/// This struct is kept in `ty_python_semantic` to avoid circular dependencies,
|
||||
/// since it's used by the suppression system.
|
||||
#[derive(Default, Eq, PartialEq, get_size2::GetSize)]
|
||||
pub struct TypeCheckDiagnostics {
|
||||
diagnostics: Vec<Diagnostic>,
|
||||
used_suppressions: rustc_hash::FxHashSet<FileSuppressionId>,
|
||||
}
|
||||
|
||||
impl TypeCheckDiagnostics {
|
||||
pub fn push(&mut self, diagnostic: Diagnostic) {
|
||||
self.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
pub fn extend(&mut self, other: &TypeCheckDiagnostics) {
|
||||
self.diagnostics.extend_from_slice(&other.diagnostics);
|
||||
self.used_suppressions.extend(&other.used_suppressions);
|
||||
}
|
||||
|
||||
pub fn extend_diagnostics(&mut self, diagnostics: impl IntoIterator<Item = Diagnostic>) {
|
||||
self.diagnostics.extend(diagnostics);
|
||||
}
|
||||
|
||||
pub fn mark_used(&mut self, suppression_id: FileSuppressionId) {
|
||||
self.used_suppressions.insert(suppression_id);
|
||||
}
|
||||
|
||||
pub fn is_used(&self, suppression_id: FileSuppressionId) -> bool {
|
||||
self.used_suppressions.contains(&suppression_id)
|
||||
}
|
||||
|
||||
pub fn used_len(&self) -> usize {
|
||||
self.used_suppressions.len()
|
||||
}
|
||||
|
||||
pub fn shrink_to_fit(&mut self) {
|
||||
self.used_suppressions.shrink_to_fit();
|
||||
self.diagnostics.shrink_to_fit();
|
||||
}
|
||||
|
||||
pub fn into_diagnostics(self) -> Vec<Diagnostic> {
|
||||
self.diagnostics
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.diagnostics.is_empty() && self.used_suppressions.is_empty()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> std::slice::Iter<'_, Diagnostic> {
|
||||
self.diagnostics().iter()
|
||||
}
|
||||
|
||||
fn diagnostics(&self) -> &[Diagnostic] {
|
||||
self.diagnostics.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for TypeCheckDiagnostics {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.diagnostics().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for TypeCheckDiagnostics {
|
||||
type Item = Diagnostic;
|
||||
type IntoIter = std::vec::IntoIter<Diagnostic>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.into_diagnostics().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a TypeCheckDiagnostics {
|
||||
type Item = &'a Diagnostic;
|
||||
type IntoIter = std::slice::Iter<'a, Diagnostic>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, get_size2::GetSize)]
|
||||
enum SuppressionTarget {
|
||||
|
||||
65
crates/ty_python_semantic/src/truthiness.rs
Normal file
65
crates/ty_python_semantic/src/truthiness.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
//! The `Truthiness` enum represents the possible boolean evaluation of a value.
|
||||
|
||||
/// The possible boolean values of a value.
|
||||
///
|
||||
/// This is used for type narrowing and reachability analysis.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, get_size2::GetSize)]
|
||||
pub enum Truthiness {
|
||||
/// For an object `x`, `bool(x)` will always return `True`
|
||||
AlwaysTrue,
|
||||
/// For an object `x`, `bool(x)` will always return `False`
|
||||
AlwaysFalse,
|
||||
/// For an object `x`, `bool(x)` could return either `True` or `False`
|
||||
Ambiguous,
|
||||
}
|
||||
|
||||
impl Truthiness {
|
||||
pub const fn is_ambiguous(self) -> bool {
|
||||
matches!(self, Truthiness::Ambiguous)
|
||||
}
|
||||
|
||||
pub const fn is_always_false(self) -> bool {
|
||||
matches!(self, Truthiness::AlwaysFalse)
|
||||
}
|
||||
|
||||
pub const fn may_be_true(self) -> bool {
|
||||
!self.is_always_false()
|
||||
}
|
||||
|
||||
pub const fn is_always_true(self) -> bool {
|
||||
matches!(self, Truthiness::AlwaysTrue)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn negate(self) -> Self {
|
||||
match self {
|
||||
Self::AlwaysTrue => Self::AlwaysFalse,
|
||||
Self::AlwaysFalse => Self::AlwaysTrue,
|
||||
Self::Ambiguous => Self::Ambiguous,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn negate_if(self, condition: bool) -> Self {
|
||||
if condition { self.negate() } else { self }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn or(self, other: Self) -> Self {
|
||||
match (self, other) {
|
||||
(Truthiness::AlwaysFalse, Truthiness::AlwaysFalse) => Truthiness::AlwaysFalse,
|
||||
(Truthiness::AlwaysTrue, _) | (_, Truthiness::AlwaysTrue) => Truthiness::AlwaysTrue,
|
||||
_ => Truthiness::Ambiguous,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Truthiness {
|
||||
fn from(value: bool) -> Self {
|
||||
if value {
|
||||
Truthiness::AlwaysTrue
|
||||
} else {
|
||||
Truthiness::AlwaysFalse
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,51 +27,47 @@ use crate::semantic_index::scope::{FileScopeId, ScopeId};
|
||||
/// * a field of a type that is a return type of a cross-module query
|
||||
/// * an argument of a cross-module query
|
||||
#[salsa::tracked(debug, heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) struct Unpack<'db> {
|
||||
pub(crate) file: File,
|
||||
pub struct Unpack<'db> {
|
||||
pub file: File,
|
||||
|
||||
pub(crate) value_file_scope: FileScopeId,
|
||||
pub value_file_scope: FileScopeId,
|
||||
|
||||
pub(crate) target_file_scope: FileScopeId,
|
||||
pub target_file_scope: FileScopeId,
|
||||
|
||||
/// The target expression that is being unpacked. For example, in `(a, b) = (1, 2)`, the target
|
||||
/// expression is `(a, b)`.
|
||||
#[no_eq]
|
||||
#[tracked]
|
||||
#[returns(ref)]
|
||||
pub(crate) _target: AstNodeRef<ast::Expr>,
|
||||
pub _target: AstNodeRef<ast::Expr>,
|
||||
|
||||
/// The ingredient representing the value expression of the unpacking. For example, in
|
||||
/// `(a, b) = (1, 2)`, the value expression is `(1, 2)`.
|
||||
pub(crate) value: UnpackValue<'db>,
|
||||
pub value: UnpackValue<'db>,
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for Unpack<'_> {}
|
||||
|
||||
impl<'db> Unpack<'db> {
|
||||
pub(crate) fn target<'ast>(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
parsed: &'ast ParsedModuleRef,
|
||||
) -> &'ast ast::Expr {
|
||||
pub fn target<'ast>(self, db: &'db dyn Db, parsed: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||
self._target(db).node(parsed)
|
||||
}
|
||||
|
||||
/// Returns the scope where the unpack target expression belongs to.
|
||||
pub(crate) fn target_scope(self, db: &'db dyn Db) -> ScopeId<'db> {
|
||||
pub fn target_scope(self, db: &'db dyn Db) -> ScopeId<'db> {
|
||||
self.target_file_scope(db).to_scope_id(db, self.file(db))
|
||||
}
|
||||
|
||||
/// Returns the range of the unpack target expression.
|
||||
pub(crate) fn range(self, db: &'db dyn Db, module: &ParsedModuleRef) -> TextRange {
|
||||
pub fn range(self, db: &'db dyn Db, module: &ParsedModuleRef) -> TextRange {
|
||||
self.target(db, module).range()
|
||||
}
|
||||
}
|
||||
|
||||
/// The expression that is being unpacked.
|
||||
#[derive(Clone, Copy, Debug, Hash, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) struct UnpackValue<'db> {
|
||||
pub struct UnpackValue<'db> {
|
||||
/// The kind of unpack expression
|
||||
kind: UnpackKind,
|
||||
/// The expression we are unpacking
|
||||
@@ -79,17 +75,17 @@ pub(crate) struct UnpackValue<'db> {
|
||||
}
|
||||
|
||||
impl<'db> UnpackValue<'db> {
|
||||
pub(crate) fn new(kind: UnpackKind, expression: Expression<'db>) -> Self {
|
||||
pub fn new(kind: UnpackKind, expression: Expression<'db>) -> Self {
|
||||
Self { kind, expression }
|
||||
}
|
||||
|
||||
/// Returns the underlying [`Expression`] that is being unpacked.
|
||||
pub(crate) const fn expression(self) -> Expression<'db> {
|
||||
pub const fn expression(self) -> Expression<'db> {
|
||||
self.expression
|
||||
}
|
||||
|
||||
/// Returns the expression as an [`AnyNodeRef`].
|
||||
pub(crate) fn as_any_node_ref<'ast>(
|
||||
pub fn as_any_node_ref<'ast>(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
module: &'ast ParsedModuleRef,
|
||||
@@ -97,19 +93,19 @@ impl<'db> UnpackValue<'db> {
|
||||
self.expression().node_ref(db, module).into()
|
||||
}
|
||||
|
||||
pub(crate) const fn kind(self) -> UnpackKind {
|
||||
pub const fn kind(self) -> UnpackKind {
|
||||
self.kind
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) enum EvaluationMode {
|
||||
pub enum EvaluationMode {
|
||||
Sync,
|
||||
Async,
|
||||
}
|
||||
|
||||
impl EvaluationMode {
|
||||
pub(crate) const fn from_is_async(is_async: bool) -> Self {
|
||||
pub const fn from_is_async(is_async: bool) -> Self {
|
||||
if is_async {
|
||||
EvaluationMode::Async
|
||||
} else {
|
||||
@@ -117,13 +113,13 @@ impl EvaluationMode {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn is_async(self) -> bool {
|
||||
pub const fn is_async(self) -> bool {
|
||||
matches!(self, EvaluationMode::Async)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) enum UnpackKind {
|
||||
pub enum UnpackKind {
|
||||
/// An iterable expression like the one in a `for` loop or a comprehension.
|
||||
Iterable { mode: EvaluationMode },
|
||||
/// An context manager expression like the one in a `with` statement.
|
||||
@@ -134,7 +130,7 @@ pub(crate) enum UnpackKind {
|
||||
|
||||
/// The position of the target element in an unpacking.
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) enum UnpackPosition {
|
||||
pub enum UnpackPosition {
|
||||
/// The target element is in the first position of the unpacking.
|
||||
First,
|
||||
/// The target element is in the position other than the first position of the unpacking.
|
||||
|
||||
80
crates/ty_python_types/Cargo.toml
Normal file
80
crates/ty_python_types/Cargo.toml
Normal file
@@ -0,0 +1,80 @@
|
||||
[package]
|
||||
name = "ty_python_types"
|
||||
version = "0.0.0"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
homepage = { workspace = true }
|
||||
documentation = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
license = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
ty_python_semantic = { workspace = true }
|
||||
ty_module_resolver = { workspace = true }
|
||||
|
||||
ruff_db = { workspace = true }
|
||||
ruff_diagnostics = { workspace = true }
|
||||
ruff_macros = { workspace = true }
|
||||
ruff_memory_usage = { workspace = true }
|
||||
ruff_python_ast = { workspace = true, features = ["salsa"] }
|
||||
ruff_python_parser = { workspace = true }
|
||||
ruff_python_stdlib = { workspace = true }
|
||||
ruff_source_file = { workspace = true }
|
||||
ruff_text_size = { workspace = true }
|
||||
ruff_python_literal = { workspace = true }
|
||||
|
||||
bitflags = { workspace = true }
|
||||
compact_str = { workspace = true }
|
||||
drop_bomb = { workspace = true }
|
||||
get-size2 = { workspace = true, features = ["indexmap", "ordermap"] }
|
||||
indexmap = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
ordermap = { workspace = true }
|
||||
salsa = { workspace = true, features = ["compact_str", "ordermap"] }
|
||||
tracing = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
schemars = { workspace = true, optional = true }
|
||||
serde = { workspace = true, optional = true }
|
||||
serde_json = { workspace = true, optional = true }
|
||||
smallvec = { workspace = true }
|
||||
static_assertions = { workspace = true }
|
||||
test-case = { workspace = true }
|
||||
memchr = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
ruff_db = { workspace = true, features = ["testing", "os"] }
|
||||
ruff_python_parser = { workspace = true }
|
||||
ty_python_semantic = { workspace = true, features = ["testing"] }
|
||||
ty_static = { workspace = true }
|
||||
ty_test = { workspace = true }
|
||||
ty_vendored = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
datatest-stable = { workspace = true }
|
||||
glob = { workspace = true }
|
||||
indoc = { workspace = true }
|
||||
insta = { workspace = true }
|
||||
pretty_assertions = { workspace = true }
|
||||
quickcheck = { version = "1.0.3", default-features = false }
|
||||
quickcheck_macros = { version = "1.0.0" }
|
||||
camino = { workspace = true }
|
||||
|
||||
[features]
|
||||
schemars = ["dep:schemars", "dep:serde_json"]
|
||||
serde = ["ruff_db/serde", "dep:serde", "ruff_python_ast/serde", "ty_python_semantic/serde"]
|
||||
testing = ["ty_python_semantic/testing"]
|
||||
|
||||
[[test]]
|
||||
name = "mdtest"
|
||||
harness = false
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.cargo-shear]
|
||||
# Used via macro expansion.
|
||||
ignored = ["ruff_macros"]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user