1#![doc= include_str!("problem.md")]
2
3mod name_resolution;
4mod overload_resolution;
5mod sql_highlighter;
6
7use std::collections::HashSet;
8
9use miette::{GraphicalReportHandler, LabeledSpan, NamedSource, Report};
10use sql_fun_core::HighlighterTheme;
11
12use crate::{
13 StringSpan,
14 sem::{
15 AnalysisError, DefElemKey, FullName, OperatorName, SemScalarExpr, TypeDefinition,
16 TypeReference, create_table::ViewName, type_system::ArgumentBindingCollection,
17 },
18};
19
20pub use self::name_resolution::{DomainBaseTypeNameNotFound, NameResolution};
21
22pub(crate) use self::{overload_resolution::OverloadResolution, sql_highlighter::SqlHighlighter};
23
24trait Problem {
25 const CODE: &'static str;
26 const MESSAGE: &'static str;
27 const SEVERITY: miette::Severity;
28 const SPAN_LABEL: &'static str;
29
30 fn get_problem_span(&self) -> StringSpan;
31
32 fn labeled_problem_span(&self) -> LabeledSpan {
33 self.get_problem_span().new_labeled_span(Self::SPAN_LABEL)
34 }
35}
36
37trait RenderProblemReport: Problem {
38 fn generate_report(
39 &self,
40 handler: &GraphicalReportHandler,
41 source: String,
42 ) -> Result<String, AnalysisError> {
43 let diag = miette::MietteDiagnostic::new(Self::MESSAGE)
44 .with_code(Self::CODE)
45 .with_severity(Self::SEVERITY)
46 .with_label(self.labeled_problem_span());
47
48 let report = Report::new(diag).with_source_code(NamedSource::new("SQL", source));
49
50 let mut out = String::new();
51 handler.render_report(&mut out, &*report)?;
52 Ok(out)
53 }
54}
55
56#[allow(clippy::large_enum_variant)]
58#[derive(Debug, Clone)]
59pub enum AnalysisProblem {
60 NameResolution(NameResolution),
62 OverloadResolution(OverloadResolution),
64
65 ExtensionNotFound(String),
67
68 NullabilityUnknown(String),
70
71 ArgumentTypeMissmatch(FullName, usize),
73
74 DuplicateDefElemKey(DefElemKey),
76
77 ExplicitCastNotDefined(TypeReference, TypeReference),
79
80 CoalesceExprTypeUnknown(Vec<SemScalarExpr>),
82
83 ExpressionTypeNotKnown(SemScalarExpr),
85
86 UndefinedOperator(
88 crate::syn::AExprKind,
89 OperatorName,
90 Option<SemScalarExpr>,
91 Option<SemScalarExpr>,
92 ),
93
94 RequireArray(SemScalarExpr, TypeReference),
96
97 SubQueryNotHaveColumnForDerivedColumnName(),
99
100 IncompatibleCaseValues(HashSet<TypeReference>),
102
103 CaseWhenExprTypeUnknown(SemScalarExpr),
105
106 ArrayIndexTypeMissmatch(SemScalarExpr, TypeReference),
108
109 MemberAccessRequiresCompositeType(FullName, String),
111
112 FunctionArgImplicitCastNotFound(FullName, usize, TypeDefinition, SemScalarExpr),
114
115 ImplicitCastNotFound(TypeReference, TypeReference),
117}
118
119impl AnalysisProblem {
120 pub fn render_report(
122 &self,
123 theme: &HighlighterTheme,
124 source: String,
125 ) -> Result<String, AnalysisError> {
126 let report_handler = GraphicalReportHandler::new()
127 .with_syntax_highlighting(SqlHighlighter::from_theme(theme)?);
128
129 let report = match self {
130 Self::NameResolution(nr) => nr.render_report(&report_handler, source)?,
131 _ => todo!(),
132 };
133 Ok(report)
134 }
135
136 #[tracing::instrument()]
138 pub fn extension_not_found(name: &str) -> Self {
139 Self::ExtensionNotFound(String::from(name))
140 }
141
142 #[tracing::instrument()]
144 pub fn nullability_unknown(item_name: &str) -> Self {
145 Self::NullabilityUnknown(String::from(item_name))
146 }
147
148 #[tracing::instrument()]
150 pub fn argument_type_missmatch(func_name: &FullName, index: usize) -> Self {
151 Self::ArgumentTypeMissmatch(func_name.clone(), index)
152 }
153
154 #[tracing::instrument()]
156 pub fn duplicate_def_elem_key(key: &DefElemKey) -> Self {
157 Self::DuplicateDefElemKey(key.clone())
158 }
159
160 #[tracing::instrument()]
162 pub fn explicit_cast_not_defined(source: &TypeReference, target: &TypeReference) -> Self {
163 Self::ExplicitCastNotDefined(source.clone(), target.clone())
164 }
165
166 #[tracing::instrument()]
168 pub fn array_required(expr: &SemScalarExpr, type_inspected: &TypeReference) -> Self {
169 Self::RequireArray(expr.clone(), type_inspected.clone())
170 }
171
172 #[tracing::instrument()]
174 pub fn array_index_type_missmatch(
175 expr: &SemScalarExpr,
176 type_inspected: &TypeReference,
177 ) -> Self {
178 Self::ArrayIndexTypeMissmatch(expr.clone(), type_inspected.clone())
179 }
180
181 #[tracing::instrument()]
183 pub fn member_access_requires_composite_type(type_name: &FullName, member_name: &str) -> Self {
184 Self::MemberAccessRequiresCompositeType(type_name.clone(), member_name.to_string())
185 }
186
187 #[track_caller]
189 #[tracing::instrument()]
190 pub fn undefined_operator(
191 aexpr_op: crate::syn::AExprKind,
192 name: &OperatorName,
193 left_arg: &Option<SemScalarExpr>,
194 right_arg: &Option<SemScalarExpr>,
195 ) -> Self {
196 Self::UndefinedOperator(aexpr_op, name.clone(), left_arg.clone(), right_arg.clone())
197 }
198
199 #[tracing::instrument()]
201 pub fn parameter_type_missmatch_for_table_function(
202 call: &crate::syn::FuncCall,
203 arg_types: ArgumentBindingCollection,
204 ) -> Self {
205 todo!()
206 }
207
208 #[track_caller]
210 #[tracing::instrument()]
211 pub fn function_result_set_type_not_found(ret_type: &super::FullName) -> Self {
212 todo!("{ret_type:?}")
213 }
214
215 #[tracing::instrument()]
217 pub fn unreachable_coalesce_argument(
218 arg_expr: &SemScalarExpr,
219 first_non_null: &SemScalarExpr,
220 ) -> Self {
221 todo!()
222 }
223
224 #[tracing::instrument()]
226 pub fn unknown_type_in_coalesce_expr(arg_expr: &SemScalarExpr) -> Self {
227 todo!()
228 }
229
230 #[tracing::instrument()]
232 pub fn coalesce_expr_type_ambiguous(
233 arg_exprs: &Vec<SemScalarExpr>,
234 candiates: &HashSet<TypeReference>,
235 choose: Option<&TypeReference>,
236 ) -> Self {
237 todo!()
238 }
239
240 #[tracing::instrument()]
242 pub fn coalesce_expr_type_unknown(arg_exprs: &[SemScalarExpr]) -> Self {
243 tracing::warn!("{arg_exprs:#?}");
244 Self::CoalesceExprTypeUnknown(arg_exprs.to_vec())
245 }
246
247 #[tracing::instrument()]
249 pub fn function_arg_implicit_cast_not_found(
250 func_name: &FullName,
251 index: usize,
252 t: &TypeDefinition,
253 arg: &SemScalarExpr,
254 ) -> Self {
255 Self::FunctionArgImplicitCastNotFound(func_name.clone(), index, t.clone(), arg.clone())
256 }
257
258 #[tracing::instrument()]
260 pub fn view_not_matview(view_name: &ViewName) -> Self {
261 todo!()
262 }
263
264 #[tracing::instrument()]
266 pub fn operator_name_syntax(v: &[String]) -> Self {
267 todo!()
268 }
269
270 #[tracing::instrument()]
272 pub fn expression_type_not_known(expr: &SemScalarExpr) -> Self {
273 Self::ExpressionTypeNotKnown(expr.clone())
274 }
275
276 #[tracing::instrument()]
278 pub fn case_when_type_unknown(case_when_expr: SemScalarExpr) -> Self {
279 Self::CaseWhenExprTypeUnknown(case_when_expr)
280 }
281
282 #[tracing::instrument()]
284 pub fn implicit_cast_not_found(ty: &TypeReference, result_type: &TypeReference) -> Self {
285 Self::ImplicitCastNotFound(ty.clone(), result_type.clone())
286 }
287
288 #[tracing::instrument()]
290 pub fn incompatible_case_values(result_types: HashSet<TypeReference>) -> Self {
291 Self::IncompatibleCaseValues(result_types)
292 }
293
294 #[tracing::instrument()]
296 pub fn unexpected_dynamic_type(sem_type: &TypeDefinition) -> Self {
297 todo!()
298 }
299
300 #[tracing::instrument()]
302 pub fn table_not_have_column_for_derived_column_name() -> Self {
303 todo!()
304 }
305
306 #[tracing::instrument()]
308 pub fn cte_not_have_column_for_derived_column_name() -> Self {
309 todo!()
310 }
311
312 #[tracing::instrument()]
314 pub fn subquery_not_have_column_for_derived_column_name() -> Self {
315 Self::SubQueryNotHaveColumnForDerivedColumnName()
316 }
317}