[red-knot] Detect semantic syntax errors (#17463)

Summary
--

This PR extends semantic syntax error detection to red-knot. The main
changes here are:

1. Adding `SemanticSyntaxChecker` and `Vec<SemanticSyntaxError>` fields
to the `SemanticIndexBuilder`
2. Calling `SemanticSyntaxChecker::visit_stmt` and `visit_expr` in the
`SemanticIndexBuilder`'s `visit_stmt` and `visit_expr` methods
3. Implementing `SemanticSyntaxContext` for `SemanticIndexBuilder`
4. Adding new mdtests to test the context implementation and show
diagnostics

(3) is definitely the trickiest and required (I think) a minor addition
to the `SemanticIndexBuilder`. I tried to look around for existing code
performing the necessary checks, but I definitely could have missed
something or misused the existing code even when I found it.

There's still one TODO around `global` statement handling. I don't think
there's an existing way to look this up, but I'm happy to work on that
here or in a separate PR. This currently only affects detection of one
error (`LoadBeforeGlobalDeclaration` or
[PLE0118](https://docs.astral.sh/ruff/rules/load-before-global-declaration/)
in ruff), so it's not too big of a problem even if we leave the TODO.

Test Plan
--

New mdtests, as well as new errors for existing mdtests

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
Brent Westbrook 2025-04-23 09:52:58 -04:00 committed by GitHub
parent 624f5c6c22
commit e7f38fe74b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 431 additions and 66 deletions

View file

@ -5,6 +5,7 @@ use ruff_db::files::File;
use ruff_db::parsed::parsed_module;
use ruff_index::{IndexSlice, IndexVec};
use ruff_python_parser::semantic_errors::SemanticSyntaxError;
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
use salsa::plumbing::AsId;
use salsa::Update;
@ -175,6 +176,9 @@ pub(crate) struct SemanticIndex<'db> {
/// Map of all of the eager bindings that appear in this file.
eager_bindings: FxHashMap<EagerBindingsKey, ScopedEagerBindingsId>,
/// List of all semantic syntax errors in this file.
semantic_syntax_errors: Vec<SemanticSyntaxError>,
}
impl<'db> SemanticIndex<'db> {
@ -399,6 +403,10 @@ impl<'db> SemanticIndex<'db> {
None => EagerBindingsResult::NotFound,
}
}
pub(crate) fn semantic_syntax_errors(&self) -> &[SemanticSyntaxError] {
&self.semantic_syntax_errors
}
}
pub struct AncestorsIter<'a> {