Skip to main content

dada_ir_ast/ast/
function.rs

1use dada_util::{FromImpls, SalsaSerialize};
2use salsa::Update;
3use serde::Serialize;
4
5use super::{AstGenericDecl, AstPerm, AstStatement, AstTy, SpanVec, SpannedIdentifier};
6use crate::{
7    ast::{AstVisibility, AstWhereClauses, DeferredParse},
8    span::{Span, Spanned},
9};
10
11/// `fn foo() { }`
12#[derive(SalsaSerialize)]
13#[salsa::tracked(debug)]
14pub struct AstFunction<'db> {
15    /// Overall span of the function declaration
16    pub span: Span<'db>,
17
18    /// Declared effects (e.g., `async`)
19    pub effects: AstFunctionEffects<'db>,
20
21    /// Span of the `fn` keyword
22    pub fn_span: Span<'db>,
23
24    /// Visibility of the function
25    pub visibility: Option<AstVisibility<'db>>,
26
27    /// Name of the function
28    pub name: SpannedIdentifier<'db>,
29
30    /// Any explicit generics e.g., `[type T]`
31    #[return_ref]
32    pub generics: Option<SpanVec<'db, AstGenericDecl<'db>>>,
33
34    /// Arguments to the function
35    #[return_ref]
36    pub inputs: SpanVec<'db, AstFunctionInput<'db>>,
37
38    /// Return type of the function (if provided)
39    pub output_ty: Option<AstTy<'db>>,
40
41    /// Where clauses (if any)
42    #[return_ref]
43    pub where_clauses: Option<AstWhereClauses<'db>>,
44
45    /// Body (if provided)
46    #[return_ref]
47    pub body: Option<DeferredParse<'db>>,
48}
49
50/// `print("Hello world")` appearing at the top of a module.
51/// This creates an implicit `fn main() { ... }` later on.
52#[derive(SalsaSerialize)]
53#[salsa::tracked(debug)]
54pub struct AstMainFunction<'db> {
55    #[return_ref]
56    pub statements: SpanVec<'db, AstStatement<'db>>,
57}
58
59impl<'db> Spanned<'db> for AstMainFunction<'db> {
60    fn span(&self, db: &'db dyn crate::Db) -> Span<'db> {
61        self.statements(db).span
62    }
63}
64
65#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Update, Debug, Serialize)]
66pub struct AstFunctionEffects<'db> {
67    pub async_effect: Option<Span<'db>>,
68    pub unsafe_effect: Option<Span<'db>>,
69}
70
71impl<'db> Spanned<'db> for AstFunction<'db> {
72    fn span(&self, db: &'db dyn crate::Db) -> Span<'db> {
73        AstFunction::span(*self, db)
74    }
75}
76
77#[derive(
78    Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Update, Debug, FromImpls, Serialize,
79)]
80pub enum AstFunctionInput<'db> {
81    SelfArg(AstSelfArg<'db>),
82    Variable(VariableDecl<'db>),
83}
84
85impl<'db> Spanned<'db> for AstFunctionInput<'db> {
86    fn span(&self, db: &'db dyn crate::Db) -> Span<'db> {
87        match self {
88            AstFunctionInput::SelfArg(arg) => arg.span(db),
89            AstFunctionInput::Variable(var) => var.span(db),
90        }
91    }
92}
93
94#[derive(SalsaSerialize)]
95#[salsa::tracked(debug)]
96pub struct AstSelfArg<'db> {
97    /// Permission written by the user.
98    /// If `None`, we will supply a suitable default.
99    pub perm: Option<AstPerm<'db>>,
100    pub self_span: Span<'db>,
101}
102
103impl<'db> Spanned<'db> for AstSelfArg<'db> {
104    fn span(&self, db: &'db dyn crate::Db) -> Span<'db> {
105        if let Some(perm) = self.perm(db) {
106            self.self_span(db).start_from(perm.span(db))
107        } else {
108            self.self_span(db)
109        }
110    }
111}
112
113/// `[mut] x: T`
114#[derive(SalsaSerialize)]
115#[salsa::tracked(debug)]
116pub struct VariableDecl<'db> {
117    /// Span of the `mut` keyword, if present.
118    pub mutable: Option<Span<'db>>,
119
120    /// Variable name.
121    pub name: SpannedIdentifier<'db>,
122
123    /// Permission written by the user.
124    /// If `None`, we will supply a suitable default.
125    pub perm: Option<AstPerm<'db>>,
126
127    /// Variable type, excluding any permission,
128    /// which can be found in `perm`.
129    pub base_ty: AstTy<'db>,
130}
131
132impl<'db> Spanned<'db> for VariableDecl<'db> {
133    fn span(&self, db: &'db dyn crate::Db) -> Span<'db> {
134        self.name(db).span.to(db, self.base_ty(db).span(db))
135    }
136}