1use dada_ir_ast::ast::{
2 AstAggregate, AstFunction, AstFunctionInput, AstGenericDecl, AstGenericTerm, AstPerm,
3 AstPermKind, AstSelfArg, AstTy, AstTyKind, VariableDecl,
4};
5
6use crate::{
7 check::scope::{ResolveToSym, Scope},
8 ir::{functions::SignatureSymbols, types::AnonymousPermSymbol},
9 prelude::Symbol,
10};
11
12use super::{classes::SymAggregateStyle, functions::SymFunctionSource};
13
14pub(crate) trait PopulateSignatureSymbols<'db> {
25 fn populate_signature_symbols(
26 &self,
27 db: &'db dyn crate::Db,
28 symbols: &mut SignatureSymbols<'db>,
29 );
30}
31
32impl<'db> PopulateSignatureSymbols<'db> for AstTy<'db> {
33 fn populate_signature_symbols(
34 &self,
35 db: &'db dyn crate::Db,
36 symbols: &mut crate::ir::functions::SignatureSymbols<'db>,
37 ) {
38 match self.kind(db) {
39 AstTyKind::Perm(ast_perm, ast_ty) => {
40 ast_perm.populate_signature_symbols(db, symbols);
41 ast_ty.populate_signature_symbols(db, symbols);
42 }
43 AstTyKind::Named(_ast_path, arguments) => {
44 arguments
45 .iter()
46 .flatten()
47 .for_each(|e| e.populate_signature_symbols(db, symbols));
48 }
49 AstTyKind::GenericDecl(ast_generic_decl) => {
50 ast_generic_decl.populate_signature_symbols(db, symbols)
51 }
52 }
53 }
54}
55
56impl<'db> PopulateSignatureSymbols<'db> for AstPerm<'db> {
57 fn populate_signature_symbols(
58 &self,
59 db: &'db dyn crate::Db,
60 symbols: &mut crate::ir::functions::SignatureSymbols<'db>,
61 ) {
62 match self.kind(db) {
63 AstPermKind::Referenced(Some(_))
64 | AstPermKind::Mutable(Some(_))
65 | AstPermKind::Given(Some(_)) => (),
66
67 AstPermKind::Referenced(None)
68 | AstPermKind::Mutable(None)
69 | AstPermKind::Given(None) => {
70 symbols
71 .generic_variables
72 .push(self.anonymous_perm_symbol(db));
73 }
74
75 AstPermKind::My => (),
76 AstPermKind::Our => (),
77 AstPermKind::Variable(_) => (),
78 AstPermKind::GenericDecl(ast_generic_decl) => {
79 ast_generic_decl.populate_signature_symbols(db, symbols)
80 }
81 }
82 }
83}
84
85impl<'db> PopulateSignatureSymbols<'db> for AstGenericTerm<'db> {
86 fn populate_signature_symbols(
87 &self,
88 db: &'db dyn crate::Db,
89 symbols: &mut crate::ir::functions::SignatureSymbols<'db>,
90 ) {
91 match self {
92 AstGenericTerm::Ty(ast_ty) => ast_ty.populate_signature_symbols(db, symbols),
93 AstGenericTerm::Perm(ast_perm) => ast_perm.populate_signature_symbols(db, symbols),
94 AstGenericTerm::Id(_) => {}
95 }
96 }
97}
98
99impl<'db> PopulateSignatureSymbols<'db> for AstGenericDecl<'db> {
100 fn populate_signature_symbols(
101 &self,
102 db: &'db dyn crate::Db,
103 symbols: &mut SignatureSymbols<'db>,
104 ) {
105 symbols.generic_variables.push(self.symbol(db));
106 }
107}
108
109impl<'db> PopulateSignatureSymbols<'db> for AstFunction<'db> {
110 fn populate_signature_symbols(
111 &self,
112 db: &'db dyn crate::Db,
113 symbols: &mut SignatureSymbols<'db>,
114 ) {
115 self.generics(db)
116 .iter()
117 .flatten()
118 .for_each(|g| g.populate_signature_symbols(db, symbols));
119
120 self.inputs(db)
121 .iter()
122 .for_each(|i| i.populate_signature_symbols(db, symbols));
123 }
124}
125
126impl<'db> PopulateSignatureSymbols<'db> for AstFunctionInput<'db> {
127 fn populate_signature_symbols(
128 &self,
129 db: &'db dyn crate::Db,
130 symbols: &mut SignatureSymbols<'db>,
131 ) {
132 match self {
133 AstFunctionInput::SelfArg(ast_self_arg) => {
134 ast_self_arg.populate_signature_symbols(db, symbols);
135 symbols.input_variables.push(ast_self_arg.symbol(db));
136 }
137 AstFunctionInput::Variable(variable_decl) => {
138 variable_decl.populate_signature_symbols(db, symbols);
139 symbols.input_variables.push(variable_decl.symbol(db));
140 }
141 }
142 }
143}
144
145impl<'db> PopulateSignatureSymbols<'db> for AstSelfArg<'db> {
146 fn populate_signature_symbols(
147 &self,
148 db: &'db dyn crate::Db,
149 symbols: &mut SignatureSymbols<'db>,
150 ) {
151 if let Some(perm) = self.perm(db) {
152 perm.populate_signature_symbols(db, symbols);
153 } else {
154 }
156 }
157}
158
159impl<'db> PopulateSignatureSymbols<'db> for VariableDecl<'db> {
160 fn populate_signature_symbols(
161 &self,
162 db: &'db dyn crate::Db,
163 symbols: &mut SignatureSymbols<'db>,
164 ) {
165 if let Some(perm) = self.perm(db) {
166 perm.populate_signature_symbols(db, symbols);
167 } else {
168 }
170
171 self.base_ty(db).populate_signature_symbols(db, symbols);
172 }
173}
174
175impl<'db> PopulateSignatureSymbols<'db> for AstAggregate<'db> {
176 fn populate_signature_symbols(
177 &self,
178 db: &'db dyn crate::Db,
179 symbols: &mut SignatureSymbols<'db>,
180 ) {
181 self.generics(db)
182 .iter()
183 .flatten()
184 .for_each(|g| g.populate_signature_symbols(db, symbols));
185 }
186}
187
188impl<'db> PopulateSignatureSymbols<'db> for SymFunctionSource<'db> {
189 fn populate_signature_symbols(
190 &self,
191 db: &'db dyn crate::Db,
192 symbols: &mut SignatureSymbols<'db>,
193 ) {
194 match self {
195 Self::Function(ast_function) => ast_function.populate_signature_symbols(db, symbols),
196 Self::Constructor(..) => {
197 self.inputs(db)
198 .iter()
199 .for_each(|i| i.populate_signature_symbols(db, symbols));
200 }
201 Self::MainFunction(_) => {}
202 }
203 }
204}
205
206pub(crate) trait PopulateDefaultSymbols<'db> {
235 fn populate_default_symbols(
236 &self,
237 db: &'db dyn crate::Db,
238 scope: &Scope<'_, 'db>,
239 symbols: &mut SignatureSymbols<'db>,
240 );
241}
242
243impl<'db> PopulateDefaultSymbols<'db> for AstSelfArg<'db> {
244 fn populate_default_symbols(
245 &self,
246 db: &'db dyn crate::Db,
247 scope: &Scope<'_, 'db>,
248 symbols: &mut SignatureSymbols<'db>,
249 ) {
250 if self_arg_requires_default_perm(db, *self, scope) {
251 symbols
252 .generic_variables
253 .push(self.anonymous_perm_symbol(db));
254 }
255 }
256}
257
258pub(crate) fn self_arg_requires_default_perm<'db>(
261 db: &'db dyn crate::Db,
262 decl: AstSelfArg<'db>,
263 scope: &Scope<'_, 'db>,
264) -> bool {
265 if decl.perm(db).is_some() {
266 return false;
267 }
268
269 match scope.aggregate().map(|a| a.style(db)) {
270 None | Some(SymAggregateStyle::Struct) => {
271 false
273 }
274
275 Some(SymAggregateStyle::Class) => {
276 true
278 }
279 }
280}
281
282impl<'db> PopulateDefaultSymbols<'db> for VariableDecl<'db> {
283 fn populate_default_symbols(
284 &self,
285 db: &'db dyn crate::Db,
286 scope: &Scope<'_, 'db>,
287 symbols: &mut SignatureSymbols<'db>,
288 ) {
289 if variable_decl_requires_default_perm(db, *self, scope) {
290 symbols
291 .generic_variables
292 .push(self.anonymous_perm_symbol(db));
293 }
294 }
295}
296
297pub(crate) fn variable_decl_requires_default_perm<'db>(
300 db: &'db dyn crate::Db,
301 decl: VariableDecl<'db>,
302 scope: &Scope<'_, 'db>,
303) -> bool {
304 if decl.perm(db).is_some() {
305 return false;
306 }
307
308 match decl.base_ty(db).kind(db) {
309 AstTyKind::Perm(..) => {
310 panic!("should not have an explicit permission if VariableDecl's `perm` field is None")
311 }
312 AstTyKind::Named(path, _) => {
313 if let Ok(sym) = path.resolve_to_sym(db, scope) {
314 match sym.style(db) {
315 Some(SymAggregateStyle::Struct) | None => false,
316 Some(SymAggregateStyle::Class) => true,
317 }
318 } else {
319 false
320 }
321 }
322 AstTyKind::GenericDecl(..) => {
323 false
325 }
326 }
327}
328
329impl<'db> PopulateDefaultSymbols<'db> for SymFunctionSource<'db> {
330 fn populate_default_symbols(
331 &self,
332 db: &'db dyn crate::Db,
333 scope: &Scope<'_, 'db>,
334 symbols: &mut SignatureSymbols<'db>,
335 ) {
336 match self {
337 Self::Function(ast_function) => {
338 ast_function.populate_default_symbols(db, scope, symbols)
339 }
340 Self::Constructor(..) => {
341 self.inputs(db)
342 .iter()
343 .for_each(|i| i.populate_default_symbols(db, scope, symbols));
344 }
345 Self::MainFunction(_) => {}
346 }
347 }
348}
349
350impl<'db> PopulateDefaultSymbols<'db> for AstFunction<'db> {
351 fn populate_default_symbols(
352 &self,
353 db: &'db dyn crate::Db,
354 scope: &Scope<'_, 'db>,
355 symbols: &mut SignatureSymbols<'db>,
356 ) {
357 for input in self.inputs(db) {
358 input.populate_default_symbols(db, scope, symbols);
359 }
360 }
361}
362
363impl<'db> PopulateDefaultSymbols<'db> for AstFunctionInput<'db> {
364 fn populate_default_symbols(
365 &self,
366 db: &'db dyn crate::Db,
367 scope: &Scope<'_, 'db>,
368 symbols: &mut SignatureSymbols<'db>,
369 ) {
370 match self {
371 AstFunctionInput::SelfArg(ast_self_arg) => {
372 ast_self_arg.populate_default_symbols(db, scope, symbols)
373 }
374 AstFunctionInput::Variable(variable_decl) => {
375 variable_decl.populate_default_symbols(db, scope, symbols)
376 }
377 }
378 }
379}