diff --git a/crates/ty_project/src/lib.rs b/crates/ty_project/src/lib.rs index 00a3fa0fea3ff..e486f8c23971d 100644 --- a/crates/ty_project/src/lib.rs +++ b/crates/ty_project/src/lib.rs @@ -257,8 +257,11 @@ impl Project { tracing::debug_span!(parent: project_span, "check_file", ?file); let _entered = check_file_span.entered(); - let result = self.check_file_impl(&db, file); - file_diagnostics.lock().unwrap().extend(result); + let result = check_file_impl(&db, file); + file_diagnostics + .lock() + .unwrap() + .extend(result.iter().map(Clone::clone)); reporter.report_file(&file); }); @@ -285,7 +288,7 @@ impl Project { return Vec::new(); } - self.check_file_impl(db, file) + check_file_impl(db, file).iter().map(Clone::clone).collect() } /// Opens a file in the project. @@ -466,71 +469,73 @@ impl Project { self.set_file_set(db).to(IndexedFiles::lazy()); } } +} - fn check_file_impl(self, db: &dyn Db, file: File) -> Vec { - let mut diagnostics: Vec = Vec::new(); - - // Abort checking if there are IO errors. - let source = source_text(db, file); - - if let Some(read_error) = source.read_error() { - diagnostics.push( - IOErrorDiagnostic { - file: Some(file), - error: read_error.clone().into(), - } - .to_diagnostic(), - ); - return diagnostics; - } +#[salsa::tracked(returns(deref), heap_size=get_size2::GetSize::get_heap_size)] +pub(crate) fn check_file_impl(db: &dyn Db, file: File) -> Box<[Diagnostic]> { + let mut diagnostics: Vec = Vec::new(); - let parsed = parsed_module(db, file); + // Abort checking if there are IO errors. + let source = source_text(db, file); - let parsed_ref = parsed.load(db); - diagnostics.extend( - parsed_ref - .errors() - .iter() - .map(|error| Diagnostic::invalid_syntax(file, &error.error, error)), + if let Some(read_error) = source.read_error() { + diagnostics.push( + IOErrorDiagnostic { + file: Some(file), + error: read_error.clone().into(), + } + .to_diagnostic(), ); + return diagnostics.into_boxed_slice(); + } - diagnostics.extend(parsed_ref.unsupported_syntax_errors().iter().map(|error| { - let mut error = Diagnostic::invalid_syntax(file, error, error); - add_inferred_python_version_hint_to_diagnostic(db, &mut error, "parsing syntax"); - error - })); - - { - let db = AssertUnwindSafe(db); - match catch(&**db, file, || check_types(*db, file)) { - Ok(Some(type_check_diagnostics)) => { - diagnostics.extend(type_check_diagnostics.into_iter().cloned()); - } - Ok(None) => {} - Err(diagnostic) => diagnostics.push(diagnostic), + let parsed = parsed_module(db, file); + + let parsed_ref = parsed.load(db); + diagnostics.extend( + parsed_ref + .errors() + .iter() + .map(|error| Diagnostic::invalid_syntax(file, &error.error, error)), + ); + + diagnostics.extend(parsed_ref.unsupported_syntax_errors().iter().map(|error| { + let mut error = Diagnostic::invalid_syntax(file, error, error); + add_inferred_python_version_hint_to_diagnostic(db, &mut error, "parsing syntax"); + error + })); + + { + let db = AssertUnwindSafe(db); + match catch(&**db, file, || check_types(*db, file)) { + Ok(Some(type_check_diagnostics)) => { + diagnostics.extend(type_check_diagnostics); } + Ok(None) => {} + Err(diagnostic) => diagnostics.push(diagnostic), } + } - if self - .open_fileset(db) - .is_none_or(|files| !files.contains(&file)) - { - // Drop the AST now that we are done checking this file. It is not currently open, - // so it is unlikely to be accessed again soon. If any queries need to access the AST - // from across files, it will be re-parsed. - parsed.clear(); - } + if db + .project() + .open_fileset(db) + .is_none_or(|files| !files.contains(&file)) + { + // Drop the AST now that we are done checking this file. It is not currently open, + // so it is unlikely to be accessed again soon. If any queries need to access the AST + // from across files, it will be re-parsed. + parsed.clear(); + } - diagnostics.sort_unstable_by_key(|diagnostic| { - diagnostic - .primary_span() - .and_then(|span| span.range()) - .unwrap_or_default() - .start() - }); + diagnostics.sort_unstable_by_key(|diagnostic| { + diagnostic + .primary_span() + .and_then(|span| span.range()) + .unwrap_or_default() + .start() + }); - diagnostics - } + diagnostics.into_boxed_slice() } #[derive(Debug)] @@ -701,8 +706,8 @@ where #[cfg(test)] mod tests { - use crate::Db; use crate::ProjectMetadata; + use crate::check_file_impl; use crate::db::tests::TestDb; use ruff_db::Db as _; use ruff_db::files::system_path_to_file; @@ -741,9 +746,8 @@ mod tests { assert_eq!(source_text(&db, file).as_str(), ""); assert_eq!( - db.project() - .check_file_impl(&db, file) - .into_iter() + check_file_impl(&db, file) + .iter() .map(|diagnostic| diagnostic.primary_message().to_string()) .collect::>(), vec!["Failed to read file: No such file or directory".to_string()] @@ -758,9 +762,8 @@ mod tests { assert_eq!(source_text(&db, file).as_str(), ""); assert_eq!( - db.project() - .check_file_impl(&db, file) - .into_iter() + check_file_impl(&db, file) + .iter() .map(|diagnostic| diagnostic.primary_message().to_string()) .collect::>(), vec![] as Vec diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index f8a6f623663c3..47c4708769ee2 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -88,8 +88,7 @@ mod definition; #[cfg(test)] mod property_tests; -#[salsa::tracked(returns(ref), heap_size=get_size2::GetSize::get_heap_size)] -pub fn check_types(db: &dyn Db, file: File) -> TypeCheckDiagnostics { +pub fn check_types(db: &dyn Db, file: File) -> Vec { let _span = tracing::trace_span!("check_types", ?file).entered(); tracing::debug!("Checking file '{path}'", path = file.path(db)); @@ -111,7 +110,7 @@ pub fn check_types(db: &dyn Db, file: File) -> TypeCheckDiagnostics { check_suppressions(db, file, &mut diagnostics); - diagnostics + diagnostics.into_vec() } /// Infer the type of a binding. diff --git a/crates/ty_python_semantic/src/types/diagnostic.rs b/crates/ty_python_semantic/src/types/diagnostic.rs index ecc870530d8b5..e3cf81f75fb45 100644 --- a/crates/ty_python_semantic/src/types/diagnostic.rs +++ b/crates/ty_python_semantic/src/types/diagnostic.rs @@ -1598,6 +1598,10 @@ impl TypeCheckDiagnostics { self.diagnostics.shrink_to_fit(); } + pub(crate) fn into_vec(self) -> Vec { + self.diagnostics + } + pub fn iter(&self) -> std::slice::Iter<'_, Diagnostic> { self.diagnostics.iter() } diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index 6cc0a6ec3b8c0..8790a1d0d35e7 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -10035,7 +10035,7 @@ mod tests { } #[track_caller] - fn assert_diagnostic_messages(diagnostics: &TypeCheckDiagnostics, expected: &[&str]) { + fn assert_diagnostic_messages(diagnostics: &[Diagnostic], expected: &[&str]) { let messages: Vec<&str> = diagnostics .iter() .map(Diagnostic::primary_message) @@ -10048,7 +10048,7 @@ mod tests { let file = system_path_to_file(db, filename).unwrap(); let diagnostics = check_types(db, file); - assert_diagnostic_messages(diagnostics, expected); + assert_diagnostic_messages(&diagnostics, expected); } #[test] diff --git a/crates/ty_test/src/lib.rs b/crates/ty_test/src/lib.rs index 827d6faaef3b4..8532bbdd0204d 100644 --- a/crates/ty_test/src/lib.rs +++ b/crates/ty_test/src/lib.rs @@ -340,7 +340,7 @@ fn run_test( Err(failures) => return Some(failures), }; - diagnostics.extend(type_diagnostics.into_iter().cloned()); + diagnostics.extend(type_diagnostics); diagnostics.sort_by(|left, right| { left.rendering_sort_key(db) .cmp(&right.rendering_sort_key(db))