1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use midenc_session::Session;

use super::{AnalysisManager, Chain, PassInfo};
use crate::diagnostics::Report;

/// A convenient type alias for `Result<T, ConversionError>`
pub type ConversionResult<T> = Result<T, Report>;

/// This is a marker trait for [ConversionPass] impls which also implement [PassInfo]
///
/// It is automatically implemented for you.
pub trait ConversionPassInfo: PassInfo + ConversionPass {}
impl<P> ConversionPassInfo for P where P: PassInfo + ConversionPass {}

/// A [ConversionPass] is a pass which applies a change in representation to some compiler entity.
///
/// Specifically, this is used to convert between intermediate representations/dialects in the
/// compiler.
///
/// For example, a conversion pass would be used to lower a `midenc_hir::parser::ast::Module`
/// to a `midenc_hir::Module`. Each conversion between dialects like this can be thought of
/// as delineating compilation phases (e.g. parsing, semantic analysis, elaboration, optimization,
/// etc.).
pub trait ConversionPass {
    type From;
    type To;

    /// Apply this conversion to `entity`
    fn convert(
        &mut self,
        entity: Self::From,
        analyses: &mut AnalysisManager,
        session: &Session,
    ) -> ConversionResult<Self::To>;

    /// Chains two conversions together to form a new, fused conversion
    fn chain<P>(self, next: P) -> Chain<Self, P>
    where
        Self: Sized,
        P: ConversionPass<From = Self::To>,
    {
        Chain::new(self, next)
    }
}
impl<P, T, U> ConversionPass for Box<P>
where
    P: ?Sized + ConversionPass<From = T, To = U>,
{
    type From = T;
    type To = U;

    fn convert(
        &mut self,
        entity: Self::From,
        analyses: &mut AnalysisManager,
        session: &Session,
    ) -> ConversionResult<Self::To> {
        (**self).convert(entity, analyses, session)
    }
}

type ConversionPassCtor<T, U> = fn() -> Box<dyn ConversionPass<From = T, To = U>>;

#[doc(hidden)]
pub struct ConversionPassRegistration<T, U> {
    pub name: &'static str,
    pub summary: &'static str,
    pub description: &'static str,
    ctor: ConversionPassCtor<T, U>,
}
impl<T, U> ConversionPassRegistration<T, U> {
    pub const fn new<P>() -> Self
    where
        P: ConversionPass<From = T, To = U> + PassInfo + Default + 'static,
    {
        Self {
            name: <P as PassInfo>::FLAG,
            summary: <P as PassInfo>::SUMMARY,
            description: <P as PassInfo>::DESCRIPTION,
            ctor: dyn_conversion_pass_ctor::<P, T, U>,
        }
    }

    /// Get the name of the registered pass
    #[inline]
    pub const fn name(&self) -> &'static str {
        self.name
    }

    /// Get a summary of the registered pass
    #[inline]
    pub const fn summary(&self) -> &'static str {
        self.summary
    }

    /// Get a rich description of the registered pass
    #[inline]
    pub const fn description(&self) -> &'static str {
        self.description
    }

    /// Get an instance of the registered pass
    #[inline]
    pub fn get(&self) -> Box<dyn ConversionPass<From = T, To = U>> {
        (self.ctor)()
    }
}

fn dyn_conversion_pass_ctor<P, T, U>() -> Box<dyn ConversionPass<From = T, To = U>>
where
    P: Default + ConversionPass<From = T, To = U> + 'static,
{
    Box::<P>::default()
}