midenc_hir/pass/
specialization.rs

1use crate::{
2    traits::BranchOpInterface, Context, EntityMut, EntityRef, Op, Operation, OperationName,
3    OperationRef, Symbol, SymbolTable,
4};
5
6pub trait PassTarget {
7    fn target_name(context: &Context) -> Option<OperationName>;
8    fn into_target(op: &OperationRef) -> EntityRef<'_, Self>;
9    fn into_target_mut(op: &mut OperationRef) -> EntityMut<'_, Self>;
10}
11
12impl<T: 'static> PassTarget for T {
13    default fn target_name(_context: &Context) -> Option<OperationName> {
14        None
15    }
16
17    #[inline]
18    #[track_caller]
19    default fn into_target(op: &OperationRef) -> EntityRef<'_, T> {
20        EntityRef::map(op.borrow(), |t| {
21            t.downcast_ref::<T>().unwrap_or_else(|| expected_type::<T>(op))
22        })
23    }
24
25    #[inline]
26    #[track_caller]
27    default fn into_target_mut(op: &mut OperationRef) -> EntityMut<'_, T> {
28        EntityMut::map(op.borrow_mut(), |t| {
29            t.downcast_mut::<T>().unwrap_or_else(|| expected_type::<T>(op))
30        })
31    }
32}
33impl PassTarget for Operation {
34    #[inline(always)]
35    fn target_name(_context: &Context) -> Option<OperationName> {
36        None
37    }
38
39    #[inline]
40    #[track_caller]
41    fn into_target(op: &OperationRef) -> EntityRef<'_, Operation> {
42        op.borrow()
43    }
44
45    #[inline]
46    #[track_caller]
47    fn into_target_mut(op: &mut OperationRef) -> EntityMut<'_, Operation> {
48        op.borrow_mut()
49    }
50}
51impl PassTarget for dyn Op {
52    #[inline(always)]
53    fn target_name(_context: &Context) -> Option<OperationName> {
54        None
55    }
56
57    fn into_target(op: &OperationRef) -> EntityRef<'_, dyn Op> {
58        EntityRef::map(op.borrow(), |op| op.as_trait::<dyn Op>().unwrap())
59    }
60
61    fn into_target_mut(op: &mut OperationRef) -> EntityMut<'_, dyn Op> {
62        EntityMut::map(op.borrow_mut(), |op| op.as_trait_mut::<dyn Op>().unwrap())
63    }
64}
65impl PassTarget for dyn BranchOpInterface {
66    #[inline(always)]
67    fn target_name(_context: &Context) -> Option<OperationName> {
68        None
69    }
70
71    #[track_caller]
72    fn into_target(op: &OperationRef) -> EntityRef<'_, dyn BranchOpInterface> {
73        EntityRef::map(op.borrow(), |t| {
74            t.as_trait::<dyn BranchOpInterface>()
75                .unwrap_or_else(|| expected_implementation::<dyn BranchOpInterface>(op))
76        })
77    }
78
79    #[track_caller]
80    fn into_target_mut(op: &mut OperationRef) -> EntityMut<'_, dyn BranchOpInterface> {
81        EntityMut::map(op.borrow_mut(), |t| {
82            t.as_trait_mut::<dyn BranchOpInterface>()
83                .unwrap_or_else(|| expected_implementation::<dyn BranchOpInterface>(op))
84        })
85    }
86}
87impl PassTarget for dyn Symbol {
88    #[inline(always)]
89    fn target_name(_context: &Context) -> Option<OperationName> {
90        None
91    }
92
93    #[track_caller]
94    fn into_target(op: &OperationRef) -> EntityRef<'_, dyn Symbol> {
95        EntityRef::map(op.borrow(), |t| {
96            t.as_trait::<dyn Symbol>()
97                .unwrap_or_else(|| expected_implementation::<dyn Symbol>(op))
98        })
99    }
100
101    #[track_caller]
102    fn into_target_mut(op: &mut OperationRef) -> EntityMut<'_, dyn Symbol> {
103        EntityMut::map(op.borrow_mut(), |t| {
104            t.as_trait_mut::<dyn Symbol>()
105                .unwrap_or_else(|| expected_implementation::<dyn Symbol>(op))
106        })
107    }
108}
109impl PassTarget for dyn SymbolTable + 'static {
110    #[inline(always)]
111    fn target_name(_context: &Context) -> Option<OperationName> {
112        None
113    }
114
115    #[track_caller]
116    fn into_target(op: &OperationRef) -> EntityRef<'_, dyn SymbolTable + 'static> {
117        EntityRef::map(op.borrow(), |t| {
118            t.as_trait::<dyn SymbolTable>()
119                .unwrap_or_else(|| expected_implementation::<dyn SymbolTable>(op))
120        })
121    }
122
123    #[track_caller]
124    fn into_target_mut(op: &mut OperationRef) -> EntityMut<'_, dyn SymbolTable + 'static> {
125        EntityMut::map(op.borrow_mut(), |t| {
126            t.as_trait_mut::<dyn SymbolTable>()
127                .unwrap_or_else(|| expected_implementation::<dyn SymbolTable>(op))
128        })
129    }
130}
131
132#[cold]
133#[inline(never)]
134#[track_caller]
135fn expected_type<T: 'static>(op: &OperationRef) -> ! {
136    panic!(
137        "expected operation '{}' to be a `{}`",
138        op.borrow().name(),
139        core::any::type_name::<T>(),
140    )
141}
142
143#[cold]
144#[inline(never)]
145#[track_caller]
146fn expected_implementation<Trait: ?Sized + 'static>(op: &OperationRef) -> ! {
147    panic!(
148        "expected '{}' to implement `{}`, but no vtable was found",
149        op.borrow().name(),
150        core::any::type_name::<Trait>()
151    )
152}