Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/diagnostics.rs')
| -rw-r--r-- | crates/hir-ty/src/infer/diagnostics.rs | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/crates/hir-ty/src/infer/diagnostics.rs b/crates/hir-ty/src/infer/diagnostics.rs new file mode 100644 index 0000000000..032dc37899 --- /dev/null +++ b/crates/hir-ty/src/infer/diagnostics.rs @@ -0,0 +1,128 @@ +//! This file contains the [`Diagnostics`] type used during inference, +//! and a wrapper around [`TyLoweringContext`] ([`InferenceTyLoweringContext`]) that replaces +//! it and takes care of diagnostics in inference. + +use std::cell::RefCell; +use std::ops::{Deref, DerefMut}; + +use hir_def::body::HygieneId; +use hir_def::hir::ExprOrPatId; +use hir_def::path::{Path, PathSegment, PathSegments}; +use hir_def::resolver::{ResolveValueResult, Resolver, TypeNs}; +use hir_def::type_ref::TypesMap; +use hir_def::TypeOwnerId; + +use crate::db::HirDatabase; +use crate::{ + InferenceDiagnostic, InferenceTyDiagnosticSource, Ty, TyLoweringContext, TyLoweringDiagnostic, +}; + +// Unfortunately, this struct needs to use interior mutability (but we encapsulate it) +// because when lowering types and paths we hold a `TyLoweringContext` that holds a reference +// to our resolver and so we cannot have mutable reference, but we really want to have +// ability to dispatch diagnostics during this work otherwise the code becomes a complete mess. +#[derive(Debug, Default, Clone)] +pub(super) struct Diagnostics(RefCell<Vec<InferenceDiagnostic>>); + +impl Diagnostics { + pub(super) fn push(&self, diagnostic: InferenceDiagnostic) { + self.0.borrow_mut().push(diagnostic); + } + + fn push_ty_diagnostics( + &self, + source: InferenceTyDiagnosticSource, + diagnostics: Vec<TyLoweringDiagnostic>, + ) { + self.0.borrow_mut().extend( + diagnostics.into_iter().map(|diag| InferenceDiagnostic::TyDiagnostic { source, diag }), + ); + } + + pub(super) fn finish(self) -> Vec<InferenceDiagnostic> { + self.0.into_inner() + } +} + +pub(super) struct InferenceTyLoweringContext<'a> { + ctx: TyLoweringContext<'a>, + diagnostics: &'a Diagnostics, + source: InferenceTyDiagnosticSource, +} + +impl<'a> InferenceTyLoweringContext<'a> { + pub(super) fn new( + db: &'a dyn HirDatabase, + resolver: &'a Resolver, + types_map: &'a TypesMap, + owner: TypeOwnerId, + diagnostics: &'a Diagnostics, + source: InferenceTyDiagnosticSource, + ) -> Self { + Self { ctx: TyLoweringContext::new(db, resolver, types_map, owner), diagnostics, source } + } + + pub(super) fn resolve_path_in_type_ns( + &mut self, + path: &Path, + node: ExprOrPatId, + ) -> Option<(TypeNs, Option<usize>)> { + let diagnostics = self.diagnostics; + self.ctx.resolve_path_in_type_ns(path, &mut |_, diag| { + diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag }) + }) + } + + pub(super) fn resolve_path_in_value_ns( + &mut self, + path: &Path, + node: ExprOrPatId, + hygiene_id: HygieneId, + ) -> Option<ResolveValueResult> { + let diagnostics = self.diagnostics; + self.ctx.resolve_path_in_value_ns(path, hygiene_id, &mut |_, diag| { + diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag }) + }) + } + + pub(super) fn lower_partly_resolved_path( + &mut self, + node: ExprOrPatId, + resolution: TypeNs, + resolved_segment: PathSegment<'_>, + remaining_segments: PathSegments<'_>, + resolved_segment_idx: u32, + infer_args: bool, + ) -> (Ty, Option<TypeNs>) { + let diagnostics = self.diagnostics; + self.ctx.lower_partly_resolved_path( + resolution, + resolved_segment, + remaining_segments, + resolved_segment_idx, + infer_args, + &mut |_, diag| diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag }), + ) + } +} + +impl<'a> Deref for InferenceTyLoweringContext<'a> { + type Target = TyLoweringContext<'a>; + + fn deref(&self) -> &Self::Target { + &self.ctx + } +} + +impl DerefMut for InferenceTyLoweringContext<'_> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.ctx + } +} + +impl Drop for InferenceTyLoweringContext<'_> { + fn drop(&mut self) { + self.diagnostics + .push_ty_diagnostics(self.source, std::mem::take(&mut self.ctx.diagnostics)); + } +} |