1use alloc::borrow::Cow;
14
15use crate::{
16 schema::{Schema, Schemas},
17 type_::{ArgType, BaseType, FullType},
18 ArgumentKey, Type, TypeOptions,
19};
20use alloc::sync::Arc;
21use alloc::vec::Vec;
22use alloc::{collections::BTreeMap, format};
23use sql_parse::{
24 Identifier, IssueHandle, Issues, OptSpanned, QualifiedName, SQLDialect, Span, Spanned,
25};
26
27#[derive(Clone, Debug)]
28pub(crate) struct ReferenceType<'a> {
29 pub(crate) name: Option<Identifier<'a>>,
30 pub(crate) span: Span,
31 pub(crate) columns: Vec<(Identifier<'a>, FullType<'a>)>,
32}
33
34pub(crate) struct Typer<'a, 'b> {
35 pub(crate) issues: &'b mut Issues<'a>,
36 pub(crate) schemas: &'b Schemas<'a>,
37 pub(crate) with_schemas: BTreeMap<&'a str, &'b Schema<'a>>,
38 pub(crate) reference_types: Vec<ReferenceType<'a>>,
39 pub(crate) arg_types: Vec<(ArgumentKey<'a>, FullType<'a>)>,
40 pub(crate) options: &'b TypeOptions,
41}
42
43impl<'a, 'b> Typer<'a, 'b> {
44 pub(crate) fn with_schemas<'c>(
45 &'c mut self,
46 schemas: BTreeMap<&'a str, &'c Schema<'a>>,
47 ) -> Typer<'a, 'c>
48 where
49 'b: 'c,
50 {
51 Typer::<'a, 'c> {
52 issues: self.issues,
53 schemas: self.schemas,
54 with_schemas: schemas,
55 reference_types: self.reference_types.clone(),
56 arg_types: self.arg_types.clone(),
57 options: self.options,
58 }
59 }
60
61 pub(crate) fn dialect(&self) -> SQLDialect {
62 self.options.parse_options.get_dialect()
63 }
64
65 pub(crate) fn constrain_arg(&mut self, idx: usize, arg_type: &ArgType, t: &FullType<'a>) {
66 let ot = match self
68 .arg_types
69 .iter_mut()
70 .find(|(k, _)| k == &ArgumentKey::Index(idx))
71 {
72 Some((_, v)) => v,
73 None => {
74 self.arg_types
75 .push((ArgumentKey::Index(idx), FullType::new(BaseType::Any, false)));
76 &mut self.arg_types.last_mut().unwrap().1
77 }
78 };
79 if t.base() != BaseType::Any || ot.base() == BaseType::Any {
80 *ot = t.clone();
81 }
82 if matches!(arg_type, ArgType::ListHack) {
83 ot.list_hack = true;
84 }
85 }
86
87 pub(crate) fn matched_type(&mut self, t1: &Type<'a>, t2: &Type<'a>) -> Option<Type<'a>> {
88 if t1 == &Type::Invalid && t2 == &Type::Invalid {
89 return Some(t1.clone());
90 }
91 if t1 == &Type::Null {
92 return Some(t2.clone());
93 }
94 if t2 == &Type::Null {
95 return Some(t1.clone());
96 }
97
98 let mut t1b = t1.base();
99 let mut t2b = t2.base();
100 if t1b == BaseType::Any {
101 t1b = t2b;
102 }
103 if t2b == BaseType::Any {
104 t2b = t1b;
105 }
106 if t1b != t2b {
107 return None;
108 }
109
110 for t in &[t1, t2] {
111 if let Type::Args(_, a) = t {
112 for (idx, arg_type, _) in a.iter() {
113 self.constrain_arg(*idx, arg_type, &FullType::new(t1b, false));
114 }
115 }
116 }
117 if t1b == BaseType::Any {
118 let mut args = Vec::new();
119 for t in &[t1, t2] {
120 if let Type::Args(_, a) = t {
121 args.extend_from_slice(a);
122 }
123 }
124 if !args.is_empty() {
125 return Some(Type::Args(t1b, Arc::new(args)));
126 }
127 }
128 Some(t1b.into())
129 }
130
131 pub(crate) fn ensure_type(
132 &mut self,
133 span: &impl Spanned,
134 given: &FullType<'a>,
135 expected: &FullType<'a>,
136 ) {
137 if self.matched_type(given, expected).is_none() {
138 self.issues.err(
139 format!("Expected type {} got {}", expected.t, given.t),
140 span,
141 );
142 }
143 }
144
145 pub(crate) fn ensure_base(
146 &mut self,
147 span: &impl Spanned,
148 given: &FullType<'a>,
149 expected: BaseType,
150 ) {
151 self.ensure_type(span, given, &FullType::new(expected, false));
152 }
153
154 pub(crate) fn get_schema(&self, name: &str) -> Option<&'b Schema<'a>> {
155 if let Some(schema) = self.with_schemas.get(name) {
156 Some(schema)
157 } else {
158 self.schemas.schemas.get(name)
159 }
160 }
161
162 pub(crate) fn err(
163 &mut self,
164 message: impl Into<Cow<'static, str>>,
165 span: &impl Spanned,
166 ) -> IssueHandle<'a, '_> {
167 self.issues.err(message, span)
168 }
169
170 pub(crate) fn warn(
171 &mut self,
172 message: impl Into<Cow<'static, str>>,
173 span: &impl Spanned,
174 ) -> IssueHandle<'a, '_> {
175 self.issues.warn(message, span)
176 }
177}
178
179pub(crate) struct TyperStack<'a, 'b, 'c, V, D: FnOnce(&mut Typer<'a, 'b>, V)> {
180 pub(crate) typer: &'c mut Typer<'a, 'b>,
181 value_drop: Option<(V, D)>,
182}
183
184impl<'a, 'b, 'c, V, D: FnOnce(&mut Typer<'a, 'b>, V)> Drop for TyperStack<'a, 'b, 'c, V, D> {
185 fn drop(&mut self) {
186 if let Some((v, d)) = self.value_drop.take() {
187 (d)(self.typer, v)
188 }
189 }
190}
191
192pub(crate) fn typer_stack<
193 'a,
194 'b,
195 'c,
196 V,
197 C: FnOnce(&mut Typer<'a, 'b>) -> V,
198 D: FnOnce(&mut Typer<'a, 'b>, V),
199>(
200 typer: &'c mut Typer<'a, 'b>,
201 c: C,
202 d: D,
203) -> TyperStack<'a, 'b, 'c, V, D> {
204 let v = c(typer);
205 TyperStack {
206 typer,
207 value_drop: Some((v, d)),
208 }
209}
210
211pub(crate) fn unqualified_name<'b, 'c>(
212 issues: &mut Issues<'_>,
213 name: &'c QualifiedName<'b>,
214) -> &'c Identifier<'b> {
215 if !name.prefix.is_empty() {
216 issues.err(
217 "Expected unqualified name",
218 &name.prefix.opt_span().unwrap(),
219 );
220 }
221 &name.identifier
222}