1#![doc = include_str!("../../docs/type_inference.md")]
3
4use dada_ir_ast::span::Span;
5use salsa::Update;
6use serde::Serialize;
7
8use crate::ir::{indices::InferVarIndex, types::SymGenericKind};
9
10use super::{
11 red::{RedPerm, RedTy},
12 report::{ArcOrElse, InferenceFallback, OrElse},
13};
14
15mod serialize;
16
17#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize)]
18pub enum Direction {
19 FromBelow,
20 FromAbove,
21}
22
23pub(crate) struct InferenceVarData<'db> {
24 span: Span<'db>,
25
26 bounds: InferenceVarBounds<'db>,
28}
29
30impl<'db> InferenceVarData<'db> {
31 fn new(span: Span<'db>, bounds: InferenceVarBounds<'db>) -> Self {
32 Self { span, bounds }
33 }
34
35 pub fn new_perm(span: Span<'db>) -> Self {
37 Self::new(
38 span,
39 InferenceVarBounds::Perm {
40 lower: Default::default(),
41 upper: Default::default(),
42 },
43 )
44 }
45
46 pub fn new_ty(span: Span<'db>, perm: InferVarIndex) -> Self {
49 Self::new(
50 span,
51 InferenceVarBounds::Ty {
52 perm,
53 lower: Default::default(),
54 upper: Default::default(),
55 },
56 )
57 }
58
59 pub fn span(&self) -> Span<'db> {
61 self.span
62 }
63
64 pub fn kind(&self) -> InferVarKind {
66 match self.bounds {
67 InferenceVarBounds::Perm { .. } => InferVarKind::Perm,
68 InferenceVarBounds::Ty { .. } => InferVarKind::Type,
69 }
70 }
71
72 #[track_caller]
78 pub fn red_perm_bound(&self, direction: Direction) -> Option<(RedPerm<'db>, ArcOrElse<'db>)> {
79 match &self.bounds {
80 InferenceVarBounds::Perm { lower, upper, .. } => match direction {
81 Direction::FromBelow => lower.clone(),
82 Direction::FromAbove => upper.clone(),
83 },
84 _ => panic!("lower_chains invoked on a var of kind `{:?}`", self.kind()),
85 }
86 }
87
88 #[track_caller]
91 pub fn perm(&self) -> Option<InferVarIndex> {
92 match &self.bounds {
93 InferenceVarBounds::Ty { perm, .. } => Some(*perm),
94 InferenceVarBounds::Perm { .. } => None,
95 }
96 }
97
98 #[track_caller]
104 pub fn red_ty_bound(&self, direction: Direction) -> Option<(RedTy<'db>, ArcOrElse<'db>)> {
105 match &self.bounds {
106 InferenceVarBounds::Ty { lower, upper, .. } => match direction {
107 Direction::FromBelow => lower.clone(),
108 Direction::FromAbove => upper.clone(),
109 },
110 _ => panic!("red_ty_bound invoked on a var of kind `{:?}`", self.kind()),
111 }
112 }
113
114 pub fn set_red_perm_bound(
117 &mut self,
118 direction: Direction,
119 red_perm: RedPerm<'db>,
120 or_else: &dyn OrElse<'db>,
121 ) {
122 let perm_bound = match &mut self.bounds {
123 InferenceVarBounds::Perm { lower, upper, .. } => match direction {
124 Direction::FromBelow => lower,
125 Direction::FromAbove => upper,
126 },
127 _ => panic!(
128 "insert_lower_chain invoked on a var of kind `{:?}`",
129 self.kind()
130 ),
131 };
132 *perm_bound = Some((red_perm, or_else.to_arc()));
133 }
134
135 pub fn set_red_ty_bound(
138 &mut self,
139 direction: Direction,
140 red_ty: RedTy<'db>,
141 or_else: &dyn OrElse<'db>,
142 ) {
143 let red_ty_bound = match &mut self.bounds {
144 InferenceVarBounds::Ty { lower, upper, .. } => match direction {
145 Direction::FromBelow => lower,
146 Direction::FromAbove => upper,
147 },
148 _ => panic!(
149 "set_lower_red_ty invoked on a var of kind `{:?}`",
150 self.kind()
151 ),
152 };
153 *red_ty_bound = Some((red_ty, or_else.to_arc()));
154 }
155
156 pub fn fallback(&mut self, db: &'db dyn crate::Db) {
159 match &mut self.bounds {
160 InferenceVarBounds::Perm { lower, upper } => {
161 if lower.is_none() && upper.is_none() {
162 let fallback = RedPerm::fallback(db);
163 let fallback_term = fallback.to_sym_perm(db);
164 *lower = Some((
165 fallback,
166 InferenceFallback::new(self.span, InferVarKind::Perm, fallback_term)
167 .to_arc(),
168 ));
169 }
170 }
171 InferenceVarBounds::Ty {
172 perm: _,
173 lower,
174 upper,
175 } => {
176 if lower.is_none() && upper.is_none() {
177 let fallback = RedTy::fallback(db);
178 let fallback_term = fallback.clone().into_sym_ty(db);
179 *lower = Some((
180 fallback,
181 InferenceFallback::new(self.span, InferVarKind::Perm, fallback_term)
182 .to_arc(),
183 ));
184 }
185 }
186 }
187 }
188}
189
190#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Update, Debug, Serialize)]
191pub enum InferVarKind {
192 Type,
193 Perm,
194}
195
196impl std::fmt::Display for InferVarKind {
197 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 match self {
199 InferVarKind::Type => write!(f, "type"),
200 InferVarKind::Perm => write!(f, "perm"),
201 }
202 }
203}
204
205impl From<InferVarKind> for SymGenericKind {
206 fn from(value: InferVarKind) -> Self {
207 match value {
208 InferVarKind::Type => SymGenericKind::Type,
209 InferVarKind::Perm => SymGenericKind::Perm,
210 }
211 }
212}
213
214pub enum InferenceVarBounds<'db> {
215 Perm {
225 lower: Option<(RedPerm<'db>, ArcOrElse<'db>)>,
226 upper: Option<(RedPerm<'db>, ArcOrElse<'db>)>,
227 },
228
229 Ty {
239 perm: InferVarIndex,
240 lower: Option<(RedTy<'db>, ArcOrElse<'db>)>,
241 upper: Option<(RedTy<'db>, ArcOrElse<'db>)>,
242 },
243}
244
245pub trait InferenceVarDataChanged {
251 fn did_change(&self) -> bool;
252}
253
254impl InferenceVarDataChanged for bool {
255 fn did_change(&self) -> bool {
256 *self
257 }
258}
259
260impl InferenceVarDataChanged for Option<ArcOrElse<'_>> {
261 fn did_change(&self) -> bool {
262 self.is_some()
263 }
264}
265
266impl InferenceVarDataChanged for () {
267 fn did_change(&self) -> bool {
268 true
269 }
270}