hir_ty/infer/
diagnostics.rs1use std::cell::RefCell;
6use std::ops::{Deref, DerefMut};
7
8use either::Either;
9use hir_def::GenericDefId;
10use hir_def::expr_store::ExpressionStore;
11use hir_def::expr_store::path::Path;
12use hir_def::{hir::ExprOrPatId, resolver::Resolver};
13use la_arena::{Idx, RawIdx};
14use thin_vec::ThinVec;
15
16use crate::{
17 InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic,
18 db::HirDatabase,
19 lower::path::{PathDiagnosticCallback, PathLoweringContext},
20 lower::{LifetimeElisionKind, TyLoweringContext},
21};
22
23#[derive(Debug, Default, Clone)]
28pub(super) struct Diagnostics<'db>(RefCell<ThinVec<InferenceDiagnostic<'db>>>);
29
30impl<'db> Diagnostics<'db> {
31 pub(super) fn push(&self, diagnostic: InferenceDiagnostic<'db>) {
32 self.0.borrow_mut().push(diagnostic);
33 }
34
35 fn push_ty_diagnostics(
36 &self,
37 source: InferenceTyDiagnosticSource,
38 diagnostics: Vec<TyLoweringDiagnostic>,
39 ) {
40 self.0.borrow_mut().extend(
41 diagnostics.into_iter().map(|diag| InferenceDiagnostic::TyDiagnostic { source, diag }),
42 );
43 }
44
45 pub(super) fn finish(self) -> ThinVec<InferenceDiagnostic<'db>> {
46 self.0.into_inner()
47 }
48}
49
50pub(crate) struct PathDiagnosticCallbackData<'a, 'db> {
51 node: ExprOrPatId,
52 diagnostics: &'a Diagnostics<'db>,
53}
54
55pub(super) struct InferenceTyLoweringContext<'db, 'a> {
56 ctx: TyLoweringContext<'db, 'a>,
57 diagnostics: &'a Diagnostics<'db>,
58 source: InferenceTyDiagnosticSource,
59}
60
61impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> {
62 #[inline]
63 pub(super) fn new(
64 db: &'db dyn HirDatabase,
65 resolver: &'a Resolver<'db>,
66 store: &'a ExpressionStore,
67 diagnostics: &'a Diagnostics<'db>,
68 source: InferenceTyDiagnosticSource,
69 generic_def: GenericDefId,
70 lifetime_elision: LifetimeElisionKind<'db>,
71 ) -> Self {
72 Self {
73 ctx: TyLoweringContext::new(db, resolver, store, generic_def, lifetime_elision),
74 diagnostics,
75 source,
76 }
77 }
78
79 #[inline]
80 pub(super) fn at_path<'b>(
81 &'b mut self,
82 path: &'b Path,
83 node: ExprOrPatId,
84 ) -> PathLoweringContext<'b, 'a, 'db> {
85 let on_diagnostic = PathDiagnosticCallback {
86 data: Either::Right(PathDiagnosticCallbackData { diagnostics: self.diagnostics, node }),
87 callback: |data, _, diag| {
88 let data = data.as_ref().right().unwrap();
89 data.diagnostics
90 .push(InferenceDiagnostic::PathDiagnostic { node: data.node, diag });
91 },
92 };
93 PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
94 }
95
96 #[inline]
97 pub(super) fn at_path_forget_diagnostics<'b>(
98 &'b mut self,
99 path: &'b Path,
100 ) -> PathLoweringContext<'b, 'a, 'db> {
101 let on_diagnostic = PathDiagnosticCallback {
102 data: Either::Right(PathDiagnosticCallbackData {
103 diagnostics: self.diagnostics,
104 node: ExprOrPatId::ExprId(Idx::from_raw(RawIdx::from_u32(0))),
105 }),
106 callback: |_data, _, _diag| {},
107 };
108 PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
109 }
110
111 #[inline]
112 pub(super) fn forget_diagnostics(&mut self) {
113 self.ctx.diagnostics.clear();
114 }
115}
116
117impl<'db, 'a> Deref for InferenceTyLoweringContext<'db, 'a> {
118 type Target = TyLoweringContext<'db, 'a>;
119
120 #[inline]
121 fn deref(&self) -> &Self::Target {
122 &self.ctx
123 }
124}
125
126impl DerefMut for InferenceTyLoweringContext<'_, '_> {
127 #[inline]
128 fn deref_mut(&mut self) -> &mut Self::Target {
129 &mut self.ctx
130 }
131}
132
133impl Drop for InferenceTyLoweringContext<'_, '_> {
134 #[inline]
135 fn drop(&mut self) {
136 self.diagnostics
137 .push_ty_diagnostics(self.source, std::mem::take(&mut self.ctx.diagnostics));
138 }
139}