Skip to main content

dada_ir_sym/check/
scope_tree.rs

1use dada_ir_ast::ast::{AstModule, AstWhereClause};
2use dada_util::FromImpls;
3use salsa::Update;
4use serde::Serialize;
5
6use crate::{
7    check::scope::Scope, ir::classes::SymAggregate, ir::functions::SymFunction,
8    ir::module::SymModule, ir::variables::SymVariable,
9};
10
11/// A `ScopeItem` defines a name resolution scope.
12#[derive(
13    Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Update, FromImpls, Serialize,
14)]
15pub enum ScopeItem<'db> {
16    /// A module; for phasing reasons, we sometimes add this to the scope tree as the ast node.
17    AstModule(AstModule<'db>),
18
19    /// A module
20    SymModule(SymModule<'db>),
21
22    /// A class or other aggregate
23    Class(SymAggregate<'db>),
24
25    /// A function or method
26    SymFunction(SymFunction<'db>),
27}
28
29pub trait ScopeTreeNode<'db>: Sized + Into<ScopeItem<'db>> {
30    /// Convert this scope item into a scope for the items declared within it.
31    fn into_scope(self, db: &'db dyn crate::Db) -> Scope<'db, 'db>;
32
33    fn direct_super_scope(self, db: &'db dyn crate::Db) -> Option<ScopeItem<'db>>;
34
35    /// Iterator that starts from self and traverses up to all super scope items.
36    fn iter_super_scopes(self, db: &'db dyn crate::Db) -> impl Iterator<Item = ScopeItem<'db>> {
37        let mut cursor: Option<ScopeItem<'db>> = Some(self.into());
38        std::iter::from_fn(move || {
39            let p = cursor?;
40            cursor = p.direct_super_scope(db);
41            Some(p)
42        })
43    }
44
45    fn direct_generic_parameters(self, db: &'db dyn crate::Db) -> &'db Vec<SymVariable<'db>>;
46
47    /// Compute the set of transitive generic parameters.
48    /// The returned vector begins with the parameters from the outermost vector.
49    fn transitive_generic_parameters(self, db: &'db dyn crate::Db) -> Vec<SymVariable<'db>> {
50        let mut generic_parameters = self
51            .iter_super_scopes(db)
52            .flat_map(|s| s.direct_generic_parameters(db).iter().rev())
53            .copied()
54            .collect::<Vec<_>>();
55        generic_parameters.reverse();
56        generic_parameters
57    }
58
59    /// Compute the set of transitive generic parameters.
60    /// The returned vector begins with the parameters from the outermost vector.
61    fn expected_generic_parameters(self, db: &'db dyn crate::Db) -> usize {
62        self.iter_super_scopes(db)
63            .flat_map(|s| s.direct_generic_parameters(db).iter().rev())
64            .copied()
65            .count()
66    }
67
68    fn push_direct_ast_where_clauses(
69        self,
70        db: &'db dyn crate::Db,
71        out: &mut Vec<AstWhereClause<'db>>,
72    );
73
74    fn push_transitive_where_clauses(
75        self,
76        db: &'db dyn crate::Db,
77        out: &mut Vec<AstWhereClause<'db>>,
78    ) {
79        self.iter_super_scopes(db)
80            .for_each(|s| s.push_direct_ast_where_clauses(db, out));
81    }
82}
83
84impl<'db> ScopeTreeNode<'db> for ScopeItem<'db> {
85    fn direct_super_scope(self, db: &'db dyn crate::Db) -> Option<ScopeItem<'db>> {
86        match self {
87            ScopeItem::AstModule(sym) => sym.direct_super_scope(db),
88            ScopeItem::SymModule(sym) => sym.direct_super_scope(db),
89            ScopeItem::Class(sym) => sym.direct_super_scope(db),
90            ScopeItem::SymFunction(sym) => sym.direct_super_scope(db),
91        }
92    }
93
94    fn direct_generic_parameters(self, db: &'db dyn crate::Db) -> &'db Vec<SymVariable<'db>> {
95        match self {
96            ScopeItem::AstModule(sym) => sym.direct_generic_parameters(db),
97            ScopeItem::SymModule(sym) => sym.direct_generic_parameters(db),
98            ScopeItem::Class(sym) => sym.direct_generic_parameters(db),
99            ScopeItem::SymFunction(sym) => sym.direct_generic_parameters(db),
100        }
101    }
102
103    fn into_scope(self, db: &'db dyn crate::Db) -> Scope<'db, 'db> {
104        match self {
105            ScopeItem::AstModule(sym) => sym.into_scope(db),
106            ScopeItem::SymModule(sym) => sym.into_scope(db),
107            ScopeItem::Class(sym) => sym.into_scope(db),
108            ScopeItem::SymFunction(sym) => sym.into_scope(db),
109        }
110    }
111
112    fn push_direct_ast_where_clauses(
113        self,
114        db: &'db dyn crate::Db,
115        out: &mut Vec<AstWhereClause<'db>>,
116    ) {
117        match self {
118            ScopeItem::AstModule(_) => {}
119            ScopeItem::SymModule(_) => {}
120            ScopeItem::Class(sym) => {
121                sym.push_direct_ast_where_clauses(db, out);
122            }
123            ScopeItem::SymFunction(sym) => {
124                sym.push_direct_ast_where_clauses(db, out);
125            }
126        }
127    }
128}