Skip to main content

dada_ir_sym/ir/
populate.rs

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
14/// Iterate over the items in a signature (function, class, impl, etc)
15/// and create the symbols for generic types and/or parameters declared within.
16/// It is used to support Dada's "inline" declarations, e.g.
17///
18/// ```dada
19/// fn foo(v: Vec[type T]) {}
20/// ```
21///
22/// This method is only concerned with explicit declarations, not defaulted ones,
23/// which are handled by [`PopulateDefaultSymbols`].
24pub(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            // See `PopulateDefaultSymbols` below.
155        }
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            // See `PopulateDefaultSymbols` below.
169        }
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
206/// In a few specific places, we add in *default* permissions.
207/// These are always an anonymous symbol, so they don't impact
208/// name resolution (this is important to avoid cycles, see the note below).
209///
210/// This method pushes those default permissions, if any,
211/// into `symbols`.
212///
213/// # Examples
214///
215/// * Given `class C { fn foo(self) }`, the `self` has a default permission
216/// * Given `fn foo(x: String)`, the variable `x` has a default permission
217///
218/// Default permissions are only needed for classes and when explicit permissions are not provided
219///
220/// * Given `struct C { fn foo(self) }`, the `self` does NOT have a default permission
221/// * Given `fn foo(x: u32)`, the variable `x` does NOT have a default permission
222/// * Given `fn foo(x: my String)`, the variable `x` does NOT have a default permission
223/// * Given `fn foo(x: type T)`, the variable `x` does NOT have a default permission
224///
225/// # Note on cycles
226///
227/// Given `x: Foo`, we need to determine if `Foo` is a struct or a class
228/// to decide whether to give it a default symbol. This requires a name
229/// resolution scope. But creating name resolution scopes required knowing
230/// the symbols in scope, and default permissions would be in scope.
231/// This is a "false cycle" because default permissions are anonymous.
232/// Nonetheless, this is why we separate out populating default symbols
233/// from the primary [`PopulateSignatureSymbols`] function.
234pub(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
258/// Returns true if a self arg requires a default permission.
259/// See [`PopulateDefaultSymbols`] trait for examples.
260pub(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            // Methods on structs don't need a default permission.
272            false
273        }
274
275        Some(SymAggregateStyle::Class) => {
276            // Methods on classes will default to any permission.
277            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
297/// Returns true if a variable declaration requires a default permission.
298/// See [`PopulateDefaultSymbols`] trait for examples.
299pub(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            // No default symbol in this case.
324            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}