Skip to content

Commit 64165be

Browse files
authored
red-knot: Use parse_unchecked to get all parse errors (#11725)
1 parent 0c75548 commit 64165be

File tree

8 files changed

+58
-125
lines changed

8 files changed

+58
-125
lines changed

Cargo.lock

Lines changed: 0 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/red_knot/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ tracing-subscriber = { workspace = true }
3535
tracing-tree = { workspace = true }
3636

3737
[dev-dependencies]
38-
textwrap = { version = "0.16.1" }
3938
tempfile = { workspace = true }
4039

4140
[lints]

crates/red_knot/src/lint.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use std::time::Duration;
55

66
use ruff_python_ast::visitor::Visitor;
77
use ruff_python_ast::{ModModule, StringLiteral};
8+
use ruff_python_parser::Parsed;
89

910
use crate::cache::KeyValueCache;
1011
use crate::db::{LintDb, LintJar, QueryResult};
1112
use crate::files::FileId;
1213
use crate::module::ModuleName;
13-
use crate::parse::{parse, Parsed};
14+
use crate::parse::parse;
1415
use crate::source::{source_text, Source};
1516
use crate::symbols::{
1617
resolve_global_symbol, symbol_table, Definition, GlobalSymbolId, SymbolId, SymbolTable,
@@ -40,7 +41,7 @@ pub(crate) fn lint_syntax(db: &dyn LintDb, file_id: FileId) -> QueryResult<Diagn
4041
let parsed = parse(db.upcast(), *file_id)?;
4142

4243
if parsed.errors().is_empty() {
43-
let ast = parsed.ast();
44+
let ast = parsed.syntax();
4445

4546
let mut visitor = SyntaxLintVisitor {
4647
diagnostics,
@@ -86,7 +87,7 @@ pub(crate) fn lint_semantic(db: &dyn LintDb, file_id: FileId) -> QueryResult<Dia
8687
let context = SemanticLintContext {
8788
file_id: *file_id,
8889
source,
89-
parsed,
90+
parsed: &parsed,
9091
symbols,
9192
db,
9293
diagnostics: RefCell::new(Vec::new()),
@@ -194,7 +195,7 @@ fn lint_bad_overrides(context: &SemanticLintContext) -> QueryResult<()> {
194195
pub struct SemanticLintContext<'a> {
195196
file_id: FileId,
196197
source: Source,
197-
parsed: Parsed,
198+
parsed: &'a Parsed<ModModule>,
198199
symbols: Arc<SymbolTable>,
199200
db: &'a dyn LintDb,
200201
diagnostics: RefCell<Vec<String>>,
@@ -209,8 +210,8 @@ impl<'a> SemanticLintContext<'a> {
209210
self.file_id
210211
}
211212

212-
pub fn ast(&self) -> &ModModule {
213-
self.parsed.ast()
213+
pub fn ast(&self) -> &'a ModModule {
214+
self.parsed.syntax()
214215
}
215216

216217
pub fn symbols(&self) -> &SymbolTable {

crates/red_knot/src/parse.rs

Lines changed: 9 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,33 @@
11
use std::ops::{Deref, DerefMut};
22
use std::sync::Arc;
33

4-
use ruff_python_ast as ast;
5-
use ruff_python_parser::{Mode, ParseError};
6-
use ruff_text_size::{Ranged, TextRange};
4+
use ruff_python_ast::ModModule;
5+
use ruff_python_parser::Parsed;
76

87
use crate::cache::KeyValueCache;
98
use crate::db::{QueryResult, SourceDb};
109
use crate::files::FileId;
1110
use crate::source::source_text;
1211

13-
#[derive(Debug, Clone, PartialEq)]
14-
pub struct Parsed {
15-
inner: Arc<ParsedInner>,
16-
}
17-
18-
#[derive(Debug, PartialEq)]
19-
struct ParsedInner {
20-
ast: ast::ModModule,
21-
errors: Vec<ParseError>,
22-
}
23-
24-
impl Parsed {
25-
fn new(ast: ast::ModModule, errors: Vec<ParseError>) -> Self {
26-
Self {
27-
inner: Arc::new(ParsedInner { ast, errors }),
28-
}
29-
}
30-
31-
pub(crate) fn from_text(text: &str) -> Self {
32-
let result = ruff_python_parser::parse(text, Mode::Module);
33-
34-
let (module, errors) = match result {
35-
Ok(parsed) => match parsed.into_syntax() {
36-
ast::Mod::Module(module) => (module, vec![]),
37-
ast::Mod::Expression(expression) => (
38-
ast::ModModule {
39-
range: expression.range(),
40-
body: vec![ast::Stmt::Expr(ast::StmtExpr {
41-
range: expression.range(),
42-
value: expression.body,
43-
})],
44-
},
45-
vec![],
46-
),
47-
},
48-
Err(errors) => (
49-
ast::ModModule {
50-
range: TextRange::default(),
51-
body: Vec::new(),
52-
},
53-
vec![errors],
54-
),
55-
};
56-
57-
Parsed::new(module, errors)
58-
}
59-
60-
pub fn ast(&self) -> &ast::ModModule {
61-
&self.inner.ast
62-
}
63-
64-
pub fn errors(&self) -> &[ParseError] {
65-
&self.inner.errors
66-
}
67-
}
68-
6912
#[tracing::instrument(level = "debug", skip(db))]
70-
pub(crate) fn parse(db: &dyn SourceDb, file_id: FileId) -> QueryResult<Parsed> {
13+
pub(crate) fn parse(db: &dyn SourceDb, file_id: FileId) -> QueryResult<Arc<Parsed<ModModule>>> {
7114
let jar = db.jar()?;
7215

7316
jar.parsed.get(&file_id, |file_id| {
7417
let source = source_text(db, *file_id)?;
7518

76-
Ok(Parsed::from_text(source.text()))
19+
Ok(Arc::new(ruff_python_parser::parse_unchecked_source(
20+
source.text(),
21+
source.kind().into(),
22+
)))
7723
})
7824
}
7925

8026
#[derive(Debug, Default)]
81-
pub struct ParsedStorage(KeyValueCache<FileId, Parsed>);
27+
pub struct ParsedStorage(KeyValueCache<FileId, Arc<Parsed<ModModule>>>);
8228

8329
impl Deref for ParsedStorage {
84-
type Target = KeyValueCache<FileId, Parsed>;
30+
type Target = KeyValueCache<FileId, Arc<Parsed<ModModule>>>;
8531

8632
fn deref(&self) -> &Self::Target {
8733
&self.0

crates/red_knot/src/source.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ pub enum SourceKind {
5353
IpyNotebook(Arc<Notebook>),
5454
}
5555

56+
impl<'a> From<&'a SourceKind> for PySourceType {
57+
fn from(value: &'a SourceKind) -> Self {
58+
match value {
59+
SourceKind::Python(_) => PySourceType::Python,
60+
SourceKind::Stub(_) => PySourceType::Stub,
61+
SourceKind::IpyNotebook(_) => PySourceType::Ipynb,
62+
}
63+
}
64+
}
65+
5666
#[derive(Debug, Clone, PartialEq)]
5767
pub struct Source {
5868
kind: SourceKind,

crates/red_knot/src/symbols.rs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub fn symbol_table(db: &dyn SemanticDb, file_id: FileId) -> QueryResult<Arc<Sym
2828

2929
jar.symbol_tables.get(&file_id, |_| {
3030
let parsed = parse(db.upcast(), file_id)?;
31-
Ok(Arc::from(SymbolTable::from_ast(parsed.ast())))
31+
Ok(Arc::from(SymbolTable::from_ast(parsed.syntax())))
3232
})
3333
}
3434

@@ -903,13 +903,16 @@ mod tests {
903903
use crate::symbols::{ScopeKind, SymbolFlags, SymbolTable};
904904

905905
mod from_ast {
906-
use crate::parse::Parsed;
907-
use crate::symbols::{Definition, ScopeKind, SymbolId, SymbolIterator, SymbolTable};
908906
use ruff_python_ast as ast;
909-
use textwrap::dedent;
907+
use ruff_python_ast::ModModule;
908+
use ruff_python_parser::{Mode, Parsed};
909+
910+
use crate::symbols::{Definition, ScopeKind, SymbolId, SymbolIterator, SymbolTable};
910911

911-
fn parse(code: &str) -> Parsed {
912-
Parsed::from_text(&dedent(code))
912+
fn parse(code: &str) -> Parsed<ModModule> {
913+
ruff_python_parser::parse_unchecked(code, Mode::Module)
914+
.try_into_module()
915+
.unwrap()
913916
}
914917

915918
fn names<I>(it: SymbolIterator<I>) -> Vec<&str>
@@ -924,14 +927,14 @@ mod tests {
924927
#[test]
925928
fn empty() {
926929
let parsed = parse("");
927-
let table = SymbolTable::from_ast(parsed.ast());
930+
let table = SymbolTable::from_ast(parsed.syntax());
928931
assert_eq!(names(table.root_symbols()).len(), 0);
929932
}
930933

931934
#[test]
932935
fn simple() {
933936
let parsed = parse("x");
934-
let table = SymbolTable::from_ast(parsed.ast());
937+
let table = SymbolTable::from_ast(parsed.syntax());
935938
assert_eq!(names(table.root_symbols()), vec!["x"]);
936939
assert_eq!(
937940
table
@@ -944,15 +947,15 @@ mod tests {
944947
#[test]
945948
fn annotation_only() {
946949
let parsed = parse("x: int");
947-
let table = SymbolTable::from_ast(parsed.ast());
950+
let table = SymbolTable::from_ast(parsed.syntax());
948951
assert_eq!(names(table.root_symbols()), vec!["int", "x"]);
949952
// TODO record definition
950953
}
951954

952955
#[test]
953956
fn import() {
954957
let parsed = parse("import foo");
955-
let table = SymbolTable::from_ast(parsed.ast());
958+
let table = SymbolTable::from_ast(parsed.syntax());
956959
assert_eq!(names(table.root_symbols()), vec!["foo"]);
957960
assert_eq!(
958961
table
@@ -965,21 +968,21 @@ mod tests {
965968
#[test]
966969
fn import_sub() {
967970
let parsed = parse("import foo.bar");
968-
let table = SymbolTable::from_ast(parsed.ast());
971+
let table = SymbolTable::from_ast(parsed.syntax());
969972
assert_eq!(names(table.root_symbols()), vec!["foo"]);
970973
}
971974

972975
#[test]
973976
fn import_as() {
974977
let parsed = parse("import foo.bar as baz");
975-
let table = SymbolTable::from_ast(parsed.ast());
978+
let table = SymbolTable::from_ast(parsed.syntax());
976979
assert_eq!(names(table.root_symbols()), vec!["baz"]);
977980
}
978981

979982
#[test]
980983
fn import_from() {
981984
let parsed = parse("from bar import foo");
982-
let table = SymbolTable::from_ast(parsed.ast());
985+
let table = SymbolTable::from_ast(parsed.syntax());
983986
assert_eq!(names(table.root_symbols()), vec!["foo"]);
984987
assert_eq!(
985988
table
@@ -999,7 +1002,7 @@ mod tests {
9991002
#[test]
10001003
fn assign() {
10011004
let parsed = parse("x = foo");
1002-
let table = SymbolTable::from_ast(parsed.ast());
1005+
let table = SymbolTable::from_ast(parsed.syntax());
10031006
assert_eq!(names(table.root_symbols()), vec!["foo", "x"]);
10041007
assert_eq!(
10051008
table
@@ -1025,7 +1028,7 @@ mod tests {
10251028
y = 2
10261029
",
10271030
);
1028-
let table = SymbolTable::from_ast(parsed.ast());
1031+
let table = SymbolTable::from_ast(parsed.syntax());
10291032
assert_eq!(names(table.root_symbols()), vec!["C", "y"]);
10301033
let scopes = table.root_child_scope_ids();
10311034
assert_eq!(scopes.len(), 1);
@@ -1050,7 +1053,7 @@ mod tests {
10501053
y = 2
10511054
",
10521055
);
1053-
let table = SymbolTable::from_ast(parsed.ast());
1056+
let table = SymbolTable::from_ast(parsed.syntax());
10541057
assert_eq!(names(table.root_symbols()), vec!["func", "y"]);
10551058
let scopes = table.root_child_scope_ids();
10561059
assert_eq!(scopes.len(), 1);
@@ -1076,7 +1079,7 @@ mod tests {
10761079
y = 2
10771080
",
10781081
);
1079-
let table = SymbolTable::from_ast(parsed.ast());
1082+
let table = SymbolTable::from_ast(parsed.syntax());
10801083
assert_eq!(names(table.root_symbols()), vec!["func"]);
10811084
let scopes = table.root_child_scope_ids();
10821085
assert_eq!(scopes.len(), 2);
@@ -1104,7 +1107,7 @@ mod tests {
11041107
x = 1
11051108
",
11061109
);
1107-
let table = SymbolTable::from_ast(parsed.ast());
1110+
let table = SymbolTable::from_ast(parsed.syntax());
11081111
assert_eq!(names(table.root_symbols()), vec!["func"]);
11091112
let scopes = table.root_child_scope_ids();
11101113
assert_eq!(scopes.len(), 1);
@@ -1130,7 +1133,7 @@ mod tests {
11301133
x = 1
11311134
",
11321135
);
1133-
let table = SymbolTable::from_ast(parsed.ast());
1136+
let table = SymbolTable::from_ast(parsed.syntax());
11341137
assert_eq!(names(table.root_symbols()), vec!["C"]);
11351138
let scopes = table.root_child_scope_ids();
11361139
assert_eq!(scopes.len(), 1);
@@ -1157,7 +1160,7 @@ mod tests {
11571160
#[test]
11581161
fn reachability_trivial() {
11591162
let parsed = parse("x = 1; x");
1160-
let ast = parsed.ast();
1163+
let ast = parsed.syntax();
11611164
let table = SymbolTable::from_ast(ast);
11621165
let x_sym = table
11631166
.root_symbol_id_by_name("x")

0 commit comments

Comments
 (0)