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.rs128
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));
+ }
+}