1#![doc = include_str!("../docs/overview.md")]
3
4use dada_ir_ast::{
5 ast::Identifier,
6 diagnostic::{Diagnostic, Level},
7 inputs::SourceFile,
8 span::Spanned,
9};
10use dada_ir_sym::{
11 ir::{
12 binder::{Binder, BoundTerm},
13 classes::{SymAggregate, SymClassMember, SymField},
14 functions::{SignatureSymbols, SymFunction, SymFunctionSignature, SymInputOutput},
15 generics::{SymWhereClause, SymWhereClauseKind},
16 module::{SymItem, SymModule},
17 types::{SymGenericKind, SymGenericTerm, SymPerm, SymPlace, SymTy},
18 variables::SymVariable,
19 },
20 prelude::*,
21};
22
23pub use dada_ir_sym::Db;
24use dada_util::Map;
25
26pub mod prelude {
27 pub use crate::Check;
28}
29
30pub trait Check<'db> {
32 fn check(&self, db: &'db dyn crate::Db);
33}
34
35impl<'db, T: Check<'db>> Check<'db> for Option<T> {
36 fn check(&self, db: &'db dyn crate::Db) {
37 if let Some(t) = self {
38 t.check(db);
39 }
40 }
41}
42
43impl<'db> Check<'db> for SourceFile {
44 fn check(&self, db: &'db dyn crate::Db) {
45 self.symbol(db).check(db);
46 }
47}
48
49impl<'db> Check<'db> for SymModule<'db> {
50 fn check(&self, db: &'db dyn crate::Db) {
51 self.items(db).for_each(|item| item.check(db));
52 self.check_use_items(db);
53 }
54}
55
56impl<'db> Check<'db> for SymItem<'db> {
57 fn check(&self, db: &'db dyn crate::Db) {
58 match self {
59 SymItem::SymClass(sym_class) => sym_class.check(db),
60 SymItem::SymFunction(sym_function) => sym_function.check(db),
61 SymItem::SymPrimitive(_sym_primtive) => (),
62 }
63 }
64}
65
66impl<'db> Check<'db> for SymAggregate<'db> {
67 fn check(&self, db: &'db dyn crate::Db) {
68 self.members(db).iter().for_each(|member| member.check(db));
69 }
70}
71
72impl<'db> Check<'db> for SymClassMember<'db> {
73 fn check(&self, db: &'db dyn crate::Db) {
74 match self {
75 SymClassMember::SymField(sym_field) => sym_field.check(db),
76 SymClassMember::SymFunction(sym_function) => sym_function.check(db),
77 }
78 }
79}
80
81impl<'db> Check<'db> for SymField<'db> {
82 fn check(&self, db: &'db dyn crate::Db) {
83 self.checked_field_ty(db);
84 }
85}
86
87impl<'db> Check<'db> for SymFunction<'db> {
88 fn check(&self, db: &'db dyn crate::Db) {
89 let _ = self.checked_signature(db);
90 self.checked_body(db);
91 }
92}
93
94impl<'db> Check<'db> for SymFunctionSignature<'db> {
95 fn check(&self, db: &'db dyn crate::Db) {
96 self.symbols(db).check(db);
97
98 self.input_output(db).check(db);
99 }
100}
101
102impl<'db> Check<'db> for SignatureSymbols<'db> {
103 fn check(&self, db: &'db dyn crate::Db) {
104 let mut variable_names = Map::default();
105 for &variable in self.generic_variables.iter().chain(&self.input_variables) {
106 variable.check(db);
107
108 if let Some(id) = variable.name(db) {
109 check_for_duplicates(db, &mut variable_names, id, variable);
110 }
111 }
112 }
113}
114
115fn check_for_duplicates<'db, S: Spanned<'db>>(
116 db: &'db dyn crate::Db,
117 map: &mut Map<Identifier<'db>, S>,
118 id: Identifier<'db>,
119 value: S,
120) {
121 if let Some(other_input) = map.get(&id) {
122 Diagnostic::error(
123 db,
124 value.span(db),
125 format!("duplicate parameter name `{id}`"),
126 )
127 .label(
128 db,
129 Level::Error,
130 value.span(db),
131 "all parameters must have unique names, but this parameter has the same name as another parameter",
132 )
133 .label(
134 db,
135 Level::Info,
136 other_input.span(db),
137 "the previous parameter is here",
138 )
139 .report(db);
140 }
141
142 map.insert(id, value);
143}
144
145impl<'db> Check<'db> for SymInputOutput<'db> {
146 fn check(&self, db: &'db dyn crate::Db) {
147 let SymInputOutput {
148 input_tys,
149 output_ty,
150 where_clauses,
151 } = self;
152 input_tys.check(db);
153 output_ty.check(db);
154 where_clauses.check(db);
155 }
156}
157
158impl<'db, C: Check<'db>> Check<'db> for Vec<C> {
159 fn check(&self, db: &'db dyn crate::Db) {
160 for item in self {
161 item.check(db);
162 }
163 }
164}
165
166impl<'db> Check<'db> for SymTy<'db> {
167 fn check(&self, _db: &'db dyn crate::Db) {
168 }
172}
173
174impl<'db, C: Check<'db> + BoundTerm<'db>> Check<'db> for Binder<'db, C> {
175 fn check(&self, db: &'db dyn crate::Db) {
176 for sym in &self.variables {
177 sym.check(db);
178 }
179 self.bound_value.check(db);
180 }
181}
182
183impl<'db> Check<'db> for SymGenericKind {
184 fn check(&self, _db: &'db dyn crate::Db) {}
185}
186
187impl<'db> Check<'db> for SymVariable<'db> {
188 fn check(&self, _db: &'db dyn crate::Db) {
189 }
193}
194
195impl<'db> Check<'db> for SymWhereClause<'db> {
196 fn check(&self, db: &'db dyn crate::Db) {
197 self.subject(db).check(db);
198 self.kind(db).check(db);
199 }
200}
201
202impl<'db> Check<'db> for SymWhereClauseKind {
203 fn check(&self, _db: &'db dyn crate::Db) {
204 match self {
205 SymWhereClauseKind::Unique => (),
206 SymWhereClauseKind::Shared => (),
207 SymWhereClauseKind::Owned => (),
208 SymWhereClauseKind::Lent => (),
209 }
210 }
211}
212
213impl<'db> Check<'db> for SymGenericTerm<'db> {
214 fn check(&self, db: &'db dyn crate::Db) {
215 match self {
216 SymGenericTerm::Type(sym_ty) => sym_ty.check(db),
217 SymGenericTerm::Perm(sym_perm) => sym_perm.check(db),
218 SymGenericTerm::Place(sym_place) => sym_place.check(db),
219 SymGenericTerm::Error(_) => (),
220 }
221 }
222}
223
224impl<'db> Check<'db> for SymPerm<'db> {
225 fn check(&self, _db: &'db dyn crate::Db) {
226 }
230}
231
232impl<'db> Check<'db> for SymPlace<'db> {
233 fn check(&self, _db: &'db dyn crate::Db) {
234 }
238}