From a4d3c4bf8bbaaf2f3b818dfe0330bc6b0af70de5 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Fri, 11 Apr 2025 10:03:59 -0400 Subject: [PATCH] red_knot_python_semantic: make the guards implement DerefMut This is the payoff from removing a bit of indirection. The types still exist, but now callers don't need to do builder -> reporter -> diagnostic. They can just conceptually think of it as builder -> diagnostic. --- .../src/types/call/bind.rs | 3 +- .../src/types/context.rs | 50 +++++++++++-------- .../src/types/diagnostic.rs | 4 +- .../src/types/infer.rs | 12 ++--- 4 files changed, 37 insertions(+), 32 deletions(-) diff --git a/crates/red_knot_python_semantic/src/types/call/bind.rs b/crates/red_knot_python_semantic/src/types/call/bind.rs index 8beb6667be..0e7f049116 100644 --- a/crates/red_knot_python_semantic/src/types/call/bind.rs +++ b/crates/red_knot_python_semantic/src/types/call/bind.rs @@ -1254,9 +1254,8 @@ impl<'db> BindingError<'db> { let provided_ty_display = provided_ty.display(context.db()); let expected_ty_display = expected_ty.display(context.db()); - let mut reporter = builder.build("Argument to this function is incorrect"); - let diag = reporter.diagnostic(); + let mut diag = builder.build("Argument to this function is incorrect"); let span = context.span(Self::get_node(node, *argument_index)); diag.annotate(Annotation::primary(span).message(format_args!( "Expected `{expected_ty_display}`, found `{provided_ty_display}`" diff --git a/crates/red_knot_python_semantic/src/types/context.rs b/crates/red_knot_python_semantic/src/types/context.rs index e8144c03e8..bfbca28803 100644 --- a/crates/red_knot_python_semantic/src/types/context.rs +++ b/crates/red_knot_python_semantic/src/types/context.rs @@ -85,8 +85,7 @@ impl<'db> InferContext<'db> { let Some(builder) = self.report_lint(lint) else { return; }; - let mut reporter = builder.build(""); - let diag = reporter.diagnostic(); + let mut diag = builder.build(""); let span = Span::from(self.file).with_range(ranged.range()); diag.annotate(Annotation::primary(span).message(message)); } @@ -240,15 +239,17 @@ pub(super) struct LintDiagnosticGuard<'db, 'ctx> { lint_id: LintId, } -impl LintDiagnosticGuard<'_, '_> { - /// Return a mutable borrow of the diagnostic on this reporter. - /// - /// Callers may mutate the diagnostic to add new sub-diagnostics - /// or annotations. - /// - /// The diagnostic is added to the typing context, if appropriate, - /// when this reporter is dropped. - pub(super) fn diagnostic(&mut self) -> &mut Diagnostic { +impl std::ops::Deref for LintDiagnosticGuard<'_, '_> { + type Target = Diagnostic; + + fn deref(&self) -> &Diagnostic { + // OK because `self.diag` is only `None` within `Drop`. + self.diag.as_ref().unwrap() + } +} + +impl std::ops::DerefMut for LintDiagnosticGuard<'_, '_> { + fn deref_mut(&mut self) -> &mut Diagnostic { // OK because `self.diag` is only `None` within `Drop`. self.diag.as_mut().unwrap() } @@ -398,15 +399,24 @@ pub(super) struct DiagnosticGuard<'db, 'ctx> { diag: Option, } -impl DiagnosticGuard<'_, '_> { - /// Return a mutable borrow of the diagnostic on this reporter. - /// - /// Callers may mutate the diagnostic to add new sub-diagnostics - /// or annotations. - /// - /// The diagnostic is added to the typing context, if appropriate, - /// when this reporter is dropped. - pub(super) fn diagnostic(&mut self) -> &mut Diagnostic { +impl std::ops::Deref for DiagnosticGuard<'_, '_> { + type Target = Diagnostic; + + fn deref(&self) -> &Diagnostic { + // OK because `self.diag` is only `None` within `Drop`. + self.diag.as_ref().unwrap() + } +} + +/// Return a mutable borrow of the diagnostic on this reporter. +/// +/// Callers may mutate the diagnostic to add new sub-diagnostics +/// or annotations. +/// +/// The diagnostic is added to the typing context, if appropriate, +/// when this reporter is dropped. +impl std::ops::DerefMut for DiagnosticGuard<'_, '_> { + fn deref_mut(&mut self) -> &mut Diagnostic { // OK because `self.diag` is only `None` within `Drop`. self.diag.as_mut().unwrap() } diff --git a/crates/red_knot_python_semantic/src/types/diagnostic.rs b/crates/red_knot_python_semantic/src/types/diagnostic.rs index a6a956a7ca..e4d7ab4329 100644 --- a/crates/red_knot_python_semantic/src/types/diagnostic.rs +++ b/crates/red_knot_python_semantic/src/types/diagnostic.rs @@ -1075,9 +1075,7 @@ pub(super) fn report_invalid_return_type( let object_span = Span::from(context.file()).with_range(object_range.range()); let return_type_span = Span::from(context.file()).with_range(return_type_range.range()); - let mut reporter = builder.build("Return type does not match returned value"); - - let diag = reporter.diagnostic(); + let mut diag = builder.build("Return type does not match returned value"); diag.annotate(Annotation::primary(object_span).message(format_args!( "Expected `{expected_ty}`, found `{actual_ty}`", expected_ty = expected_ty.display(context.db()), diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index 25f888a886..600ecb7ee8 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -4174,14 +4174,12 @@ impl<'db> TypeInferenceBuilder<'db> { .context .report_diagnostic(DiagnosticId::RevealedType, Severity::Info) { - let mut reporter = builder.build("Revealed type"); + let mut diag = builder.into_diagnostic("Revealed type"); let span = self.context.span(call_expression); - reporter.diagnostic().annotate( - Annotation::primary(span).message(format_args!( - "`{}`", - revealed_type.display(self.db()) - )), - ); + diag.annotate(Annotation::primary(span).message(format_args!( + "`{}`", + revealed_type.display(self.db()) + ))); } } }