Skip to content

Commit

Permalink
internal: Compute syntax validation errors on demand
Browse files Browse the repository at this point in the history
  • Loading branch information
Veykril committed Mar 4, 2024
1 parent 4303e74 commit e6a3f3d
Show file tree
Hide file tree
Showing 11 changed files with 39 additions and 38 deletions.
5 changes: 3 additions & 2 deletions crates/hir-def/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -788,11 +788,12 @@ impl<'a> AssocItemCollector<'a> {
};
self.diagnostics.push(diag);
}
if let errors @ [_, ..] = parse.errors() {
let errors = parse.errors();
if !errors.is_empty() {
self.diagnostics.push(DefDiagnostic::macro_expansion_parse_error(
self.module_id.local_id,
error_call_kind(),
errors,
errors.into_boxed_slice(),
));
}

Expand Down
6 changes: 4 additions & 2 deletions crates/hir-def/src/nameres/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1384,7 +1384,9 @@ impl DefCollector<'_> {
// First, fetch the raw expansion result for purposes of error reporting. This goes through
// `parse_macro_expansion_error` to avoid depending on the full expansion result (to improve
// incrementality).
let ExpandResult { value, err } = self.db.parse_macro_expansion_error(macro_call_id);
// FIXME: This kind of error fetching feels a bit odd?
let ExpandResult { value: errors, err } =
self.db.parse_macro_expansion_error(macro_call_id);
if let Some(err) = err {
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
let diag = match err {
Expand All @@ -1398,7 +1400,7 @@ impl DefCollector<'_> {

self.def_map.diagnostics.push(diag);
}
if let errors @ [_, ..] = &*value {
if !errors.is_empty() {
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, errors);
self.def_map.diagnostics.push(diag);
Expand Down
7 changes: 2 additions & 5 deletions crates/hir-def/src/nameres/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,11 @@ impl DefDiagnostic {
pub(crate) fn macro_expansion_parse_error(
container: LocalModuleId,
ast: MacroCallKind,
errors: &[SyntaxError],
errors: Box<[SyntaxError]>,
) -> Self {
Self {
in_module: container,
kind: DefDiagnosticKind::MacroExpansionParseError {
ast,
errors: errors.to_vec().into_boxed_slice(),
},
kind: DefDiagnosticKind::MacroExpansionParseError { ast, errors },
}
}

Expand Down
4 changes: 2 additions & 2 deletions crates/hir-expand/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ fn parse_macro_expansion_error(
macro_call_id: MacroCallId,
) -> ExpandResult<Box<[SyntaxError]>> {
db.parse_macro_expansion(MacroFileId { macro_call_id })
.map(|it| it.0.errors().to_vec().into_boxed_slice())
.map(|it| it.0.errors().into_boxed_slice())
}

pub(crate) fn parse_with_map(
Expand Down Expand Up @@ -445,7 +445,7 @@ fn macro_arg(

if matches!(loc.def.kind, MacroDefKind::BuiltInEager(..)) {
match parse.errors() {
[] => ValueResult::ok((Arc::new(tt), undo_info)),
errors if errors.is_empty() => ValueResult::ok((Arc::new(tt), undo_info)),
errors => ValueResult::new(
(Arc::new(tt), undo_info),
// Box::<[_]>::from(res.errors()), not stable yet
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-expand/src/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ impl InFile<&SyntaxNode> {
map_node_range_up(db, &db.expansion_span_map(file_id), self.value.text_range())?;

// FIXME: Figure out an API that makes proper use of ctx, this only exists to
// keep pre-token map rewrite behaviour.
// keep pre-token map rewrite behavior.
if !ctx.is_root() {
return None;
}
Expand Down
2 changes: 1 addition & 1 deletion crates/ide-diagnostics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ pub fn diagnostics(
let mut res = Vec::new();

// [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
res.extend(parse.errors().iter().take(128).map(|err| {
res.extend(parse.errors().into_iter().take(128).map(|err| {
Diagnostic::new(
DiagnosticCode::RustcHardError("syntax-error"),
format!("Syntax Error: {err}"),
Expand Down
4 changes: 3 additions & 1 deletion crates/rust-analyzer/src/integrated_benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ fn integrated_highlighting_benchmark() {
vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {path}"))
};

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

{
let _it = stdx::timeit("initial");
Expand All @@ -72,6 +72,8 @@ fn integrated_highlighting_benchmark() {
host.apply_change(change);
}

let _g = crate::tracing::hprof::init("*>50");

{
let _it = stdx::timeit("after change");
let _span = profile::cpu_span();
Expand Down
4 changes: 2 additions & 2 deletions crates/rust-analyzer/src/tracing/hprof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use tracing_subscriber::{

use crate::tracing::hprof;

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

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

let subscriber = Registry::default().with(layer);
tracing::subscriber::set_global_default(subscriber).unwrap();
tracing::subscriber::set_default(subscriber)
}

#[derive(Default, Debug)]
Expand Down
11 changes: 6 additions & 5 deletions crates/syntax/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,11 @@ impl<T> Parse<T> {
pub fn syntax_node(&self) -> SyntaxNode {
SyntaxNode::new_root(self.green.clone())
}
pub fn errors(&self) -> &[SyntaxError] {
self.errors.as_deref().unwrap_or_default()

pub fn errors(&self) -> Vec<SyntaxError> {
let mut errors = if let Some(e) = self.errors.as_deref() { e.to_vec() } else { vec![] };
validation::validate(&self.syntax_node(), &mut errors);
errors
}
}

Expand Down Expand Up @@ -169,11 +172,9 @@ pub use crate::ast::SourceFile;
impl SourceFile {
pub fn parse(text: &str) -> Parse<SourceFile> {
let _p = tracing::span!(tracing::Level::INFO, "SourceFile::parse").entered();
let (green, mut errors) = parsing::parse_text(text);
let (green, errors) = parsing::parse_text(text);
let root = SyntaxNode::new_root(green.clone());

errors.extend(validation::validate(&root));

assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
Parse {
green,
Expand Down
2 changes: 1 addition & 1 deletion crates/syntax/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ fn validation_tests() {
dir_tests(&test_data_dir(), &["parser/validation"], "rast", |text, path| {
let parse = SourceFile::parse(text);
let errors = parse.errors();
assert_errors_are_present(errors, path);
assert_errors_are_present(&errors, path);
parse.debug_dump()
});
}
Expand Down
30 changes: 14 additions & 16 deletions crates/syntax/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,32 @@ use crate::{
SyntaxNode, SyntaxToken, TextSize, T,
};

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

let mut errors = Vec::new();
for node in root.descendants() {
match_ast! {
match node {
ast::Literal(it) => validate_literal(it, &mut errors),
ast::Const(it) => validate_const(it, &mut errors),
ast::BlockExpr(it) => block::validate_block_expr(it, &mut errors),
ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), &mut errors),
ast::RecordExprField(it) => validate_numeric_name(it.name_ref(), &mut errors),
ast::Visibility(it) => validate_visibility(it, &mut errors),
ast::RangeExpr(it) => validate_range_expr(it, &mut errors),
ast::PathSegment(it) => validate_path_keywords(it, &mut errors),
ast::RefType(it) => validate_trait_object_ref_ty(it, &mut errors),
ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors),
ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors),
ast::MacroRules(it) => validate_macro_rules(it, &mut errors),
ast::LetExpr(it) => validate_let_expr(it, &mut errors),
ast::Literal(it) => validate_literal(it, errors),
ast::Const(it) => validate_const(it, errors),
ast::BlockExpr(it) => block::validate_block_expr(it, errors),
ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), errors),
ast::RecordExprField(it) => validate_numeric_name(it.name_ref(), errors),
ast::Visibility(it) => validate_visibility(it, errors),
ast::RangeExpr(it) => validate_range_expr(it, errors),
ast::PathSegment(it) => validate_path_keywords(it, errors),
ast::RefType(it) => validate_trait_object_ref_ty(it, errors),
ast::PtrType(it) => validate_trait_object_ptr_ty(it, errors),
ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, errors),
ast::MacroRules(it) => validate_macro_rules(it, errors),
ast::LetExpr(it) => validate_let_expr(it, errors),
_ => (),
}
}
}
errors
}

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

0 comments on commit e6a3f3d

Please sign in to comment.