Skip to content

Commit a7e9f12

Browse files
committed
Auto merge of #16748 - Veykril:on-demand-validation-err, r=Veykril
internal: Compute syntax validation errors on demand The LRU cache causes us to re-parse trees quite often, yet we don't use the validation errors at all. With this we push calculating them off to the caller who is interested in them.
2 parents 99a1b8f + c3c9f5f commit a7e9f12

File tree

11 files changed

+45
-44
lines changed

11 files changed

+45
-44
lines changed

crates/hir-def/src/data.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -788,11 +788,12 @@ impl<'a> AssocItemCollector<'a> {
788788
};
789789
self.diagnostics.push(diag);
790790
}
791-
if let errors @ [_, ..] = parse.errors() {
791+
let errors = parse.errors();
792+
if !errors.is_empty() {
792793
self.diagnostics.push(DefDiagnostic::macro_expansion_parse_error(
793794
self.module_id.local_id,
794795
error_call_kind(),
795-
errors,
796+
errors.into_boxed_slice(),
796797
));
797798
}
798799

crates/hir-def/src/nameres/collector.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,7 +1384,9 @@ impl DefCollector<'_> {
13841384
// First, fetch the raw expansion result for purposes of error reporting. This goes through
13851385
// `parse_macro_expansion_error` to avoid depending on the full expansion result (to improve
13861386
// incrementality).
1387-
let ExpandResult { value, err } = self.db.parse_macro_expansion_error(macro_call_id);
1387+
// FIXME: This kind of error fetching feels a bit odd?
1388+
let ExpandResult { value: errors, err } =
1389+
self.db.parse_macro_expansion_error(macro_call_id);
13881390
if let Some(err) = err {
13891391
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
13901392
let diag = match err {
@@ -1398,7 +1400,7 @@ impl DefCollector<'_> {
13981400

13991401
self.def_map.diagnostics.push(diag);
14001402
}
1401-
if let errors @ [_, ..] = &*value {
1403+
if !errors.is_empty() {
14021404
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
14031405
let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, errors);
14041406
self.def_map.diagnostics.push(diag);

crates/hir-def/src/nameres/diagnostics.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,11 @@ impl DefDiagnostic {
117117
pub(crate) fn macro_expansion_parse_error(
118118
container: LocalModuleId,
119119
ast: MacroCallKind,
120-
errors: &[SyntaxError],
120+
errors: Box<[SyntaxError]>,
121121
) -> Self {
122122
Self {
123123
in_module: container,
124-
kind: DefDiagnosticKind::MacroExpansionParseError {
125-
ast,
126-
errors: errors.to_vec().into_boxed_slice(),
127-
},
124+
kind: DefDiagnosticKind::MacroExpansionParseError { ast, errors },
128125
}
129126
}
130127

crates/hir-expand/src/db.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ fn parse_macro_expansion_error(
303303
macro_call_id: MacroCallId,
304304
) -> ExpandResult<Box<[SyntaxError]>> {
305305
db.parse_macro_expansion(MacroFileId { macro_call_id })
306-
.map(|it| it.0.errors().to_vec().into_boxed_slice())
306+
.map(|it| it.0.errors().into_boxed_slice())
307307
}
308308

309309
pub(crate) fn parse_with_map(
@@ -445,7 +445,7 @@ fn macro_arg(
445445

446446
if matches!(loc.def.kind, MacroDefKind::BuiltInEager(..)) {
447447
match parse.errors() {
448-
[] => ValueResult::ok((Arc::new(tt), undo_info)),
448+
errors if errors.is_empty() => ValueResult::ok((Arc::new(tt), undo_info)),
449449
errors => ValueResult::new(
450450
(Arc::new(tt), undo_info),
451451
// Box::<[_]>::from(res.errors()), not stable yet

crates/hir-expand/src/files.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ impl InFile<&SyntaxNode> {
252252
map_node_range_up(db, &db.expansion_span_map(file_id), self.value.text_range())?;
253253

254254
// FIXME: Figure out an API that makes proper use of ctx, this only exists to
255-
// keep pre-token map rewrite behaviour.
255+
// keep pre-token map rewrite behavior.
256256
if !ctx.is_root() {
257257
return None;
258258
}

crates/ide-diagnostics/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ pub fn diagnostics(
299299
let mut res = Vec::new();
300300

301301
// [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
302-
res.extend(parse.errors().iter().take(128).map(|err| {
302+
res.extend(parse.errors().into_iter().take(128).map(|err| {
303303
Diagnostic::new(
304304
DiagnosticCode::RustcHardError("syntax-error"),
305305
format!("Syntax Error: {err}"),

crates/rust-analyzer/src/integrated_benchmarks.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ fn integrated_highlighting_benchmark() {
5555
vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {path}"))
5656
};
5757

58-
crate::tracing::hprof::init("*>100");
58+
let _g = crate::tracing::hprof::init("*>150");
5959

6060
{
6161
let _it = stdx::timeit("initial");
@@ -72,6 +72,8 @@ fn integrated_highlighting_benchmark() {
7272
host.apply_change(change);
7373
}
7474

75+
let _g = crate::tracing::hprof::init("*>50");
76+
7577
{
7678
let _it = stdx::timeit("after change");
7779
let _span = profile::cpu_span();

crates/rust-analyzer/src/tracing/hprof.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use tracing_subscriber::{
5252

5353
use crate::tracing::hprof;
5454

55-
pub fn init(spec: &str) {
55+
pub fn init(spec: &str) -> tracing::subscriber::DefaultGuard {
5656
let (write_filter, allowed_names) = WriteFilter::from_spec(spec);
5757

5858
// this filter the first pass for `tracing`: these are all the "profiling" spans, but things like
@@ -76,7 +76,7 @@ pub fn init(spec: &str) {
7676
.with_filter(profile_filter);
7777

7878
let subscriber = Registry::default().with(layer);
79-
tracing::subscriber::set_global_default(subscriber).unwrap();
79+
tracing::subscriber::set_default(subscriber)
8080
}
8181

8282
#[derive(Default, Debug)]

crates/syntax/src/lib.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,11 @@ impl<T> Parse<T> {
9797
pub fn syntax_node(&self) -> SyntaxNode {
9898
SyntaxNode::new_root(self.green.clone())
9999
}
100-
pub fn errors(&self) -> &[SyntaxError] {
101-
self.errors.as_deref().unwrap_or_default()
100+
101+
pub fn errors(&self) -> Vec<SyntaxError> {
102+
let mut errors = if let Some(e) = self.errors.as_deref() { e.to_vec() } else { vec![] };
103+
validation::validate(&self.syntax_node(), &mut errors);
104+
errors
102105
}
103106
}
104107

@@ -111,10 +114,10 @@ impl<T: AstNode> Parse<T> {
111114
T::cast(self.syntax_node()).unwrap()
112115
}
113116

114-
pub fn ok(self) -> Result<T, Arc<[SyntaxError]>> {
115-
match self.errors {
116-
Some(e) => Err(e),
117-
None => Ok(self.tree()),
117+
pub fn ok(self) -> Result<T, Vec<SyntaxError>> {
118+
match self.errors() {
119+
errors if !errors.is_empty() => Err(errors),
120+
_ => Ok(self.tree()),
118121
}
119122
}
120123
}
@@ -132,7 +135,7 @@ impl Parse<SyntaxNode> {
132135
impl Parse<SourceFile> {
133136
pub fn debug_dump(&self) -> String {
134137
let mut buf = format!("{:#?}", self.tree().syntax());
135-
for err in self.errors.as_deref().into_iter().flat_map(<[_]>::iter) {
138+
for err in self.errors() {
136139
format_to!(buf, "error {:?}: {}\n", err.range(), err);
137140
}
138141
buf
@@ -169,11 +172,9 @@ pub use crate::ast::SourceFile;
169172
impl SourceFile {
170173
pub fn parse(text: &str) -> Parse<SourceFile> {
171174
let _p = tracing::span!(tracing::Level::INFO, "SourceFile::parse").entered();
172-
let (green, mut errors) = parsing::parse_text(text);
175+
let (green, errors) = parsing::parse_text(text);
173176
let root = SyntaxNode::new_root(green.clone());
174177

175-
errors.extend(validation::validate(&root));
176-
177178
assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
178179
Parse {
179180
green,

crates/syntax/src/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fn benchmark_parser() {
3939
let tree = {
4040
let _b = bench("parsing");
4141
let p = SourceFile::parse(&data);
42-
assert!(p.errors.is_none());
42+
assert!(p.errors().is_empty());
4343
assert_eq!(p.tree().syntax.text_range().len(), 352474.into());
4444
p.tree()
4545
};
@@ -57,7 +57,7 @@ fn validation_tests() {
5757
dir_tests(&test_data_dir(), &["parser/validation"], "rast", |text, path| {
5858
let parse = SourceFile::parse(text);
5959
let errors = parse.errors();
60-
assert_errors_are_present(errors, path);
60+
assert_errors_are_present(&errors, path);
6161
parse.debug_dump()
6262
});
6363
}

crates/syntax/src/validation.rs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,32 @@ use crate::{
1515
SyntaxNode, SyntaxToken, TextSize, T,
1616
};
1717

18-
pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
18+
pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec<SyntaxError>) {
1919
let _p = tracing::span!(tracing::Level::INFO, "parser::validate").entered();
2020
// FIXME:
2121
// * Add unescape validation of raw string literals and raw byte string literals
2222
// * Add validation of doc comments are being attached to nodes
2323

24-
let mut errors = Vec::new();
2524
for node in root.descendants() {
2625
match_ast! {
2726
match node {
28-
ast::Literal(it) => validate_literal(it, &mut errors),
29-
ast::Const(it) => validate_const(it, &mut errors),
30-
ast::BlockExpr(it) => block::validate_block_expr(it, &mut errors),
31-
ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), &mut errors),
32-
ast::RecordExprField(it) => validate_numeric_name(it.name_ref(), &mut errors),
33-
ast::Visibility(it) => validate_visibility(it, &mut errors),
34-
ast::RangeExpr(it) => validate_range_expr(it, &mut errors),
35-
ast::PathSegment(it) => validate_path_keywords(it, &mut errors),
36-
ast::RefType(it) => validate_trait_object_ref_ty(it, &mut errors),
37-
ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors),
38-
ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors),
39-
ast::MacroRules(it) => validate_macro_rules(it, &mut errors),
40-
ast::LetExpr(it) => validate_let_expr(it, &mut errors),
27+
ast::Literal(it) => validate_literal(it, errors),
28+
ast::Const(it) => validate_const(it, errors),
29+
ast::BlockExpr(it) => block::validate_block_expr(it, errors),
30+
ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), errors),
31+
ast::RecordExprField(it) => validate_numeric_name(it.name_ref(), errors),
32+
ast::Visibility(it) => validate_visibility(it, errors),
33+
ast::RangeExpr(it) => validate_range_expr(it, errors),
34+
ast::PathSegment(it) => validate_path_keywords(it, errors),
35+
ast::RefType(it) => validate_trait_object_ref_ty(it, errors),
36+
ast::PtrType(it) => validate_trait_object_ptr_ty(it, errors),
37+
ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, errors),
38+
ast::MacroRules(it) => validate_macro_rules(it, errors),
39+
ast::LetExpr(it) => validate_let_expr(it, errors),
4140
_ => (),
4241
}
4342
}
4443
}
45-
errors
4644
}
4745

4846
fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> (&'static str, bool) {

0 commit comments

Comments
 (0)