1use std::collections::HashMap;
2
3use hir::symbol_table::SymbolTable;
4use hir::{Parameter, TypeExpression, TypeSpec};
5use spade_common::id_tracker::ExprID;
6use spade_common::location_info::{Loc, WithLocation};
7use spade_common::name::NameID;
8use spade_diagnostics::Diagnostic;
9use spade_hir::{self as hir, ConstGenericWithId};
10use spade_hir::{TypeDeclaration, TypeList};
11use spade_types::{ConcreteType, KnownType, PrimitiveType};
12
13use crate::equation::{TypeVar, TypeVarID, TypedExpression};
14use crate::TypeState;
15
16pub trait HasConcreteType {
17 fn into_typed_expression(&self) -> Loc<TypedExpression>;
18}
19
20impl<T> HasConcreteType for &mut T
21where
22 T: HasConcreteType,
23{
24 fn into_typed_expression(&self) -> Loc<TypedExpression> {
25 (**self).into_typed_expression()
26 }
27}
28
29impl<T> HasConcreteType for &T
30where
31 T: HasConcreteType,
32{
33 fn into_typed_expression(&self) -> Loc<TypedExpression> {
34 (*self).into_typed_expression()
35 }
36}
37
38impl<T> HasConcreteType for Box<T>
39where
40 T: HasConcreteType,
41{
42 fn into_typed_expression(&self) -> Loc<TypedExpression> {
43 self.as_ref().into_typed_expression()
44 }
45}
46
47impl HasConcreteType for Loc<ExprID> {
48 fn into_typed_expression(&self) -> Loc<TypedExpression> {
49 TypedExpression::Id(self.inner).at_loc(self)
50 }
51}
52
53impl HasConcreteType for Loc<&ExprID> {
54 fn into_typed_expression(&self) -> Loc<TypedExpression> {
55 TypedExpression::Id(*self.inner).at_loc(self)
56 }
57}
58
59impl HasConcreteType for Loc<hir::Expression> {
60 fn into_typed_expression(&self) -> Loc<TypedExpression> {
61 TypedExpression::Id(self.id).at_loc(self)
62 }
63}
64
65impl HasConcreteType for Loc<hir::Pattern> {
66 fn into_typed_expression(&self) -> Loc<TypedExpression> {
67 TypedExpression::Id(self.id).at_loc(self)
68 }
69}
70impl HasConcreteType for Loc<ConstGenericWithId> {
71 fn into_typed_expression(&self) -> Loc<TypedExpression> {
72 TypedExpression::Id(self.id).at_loc(self)
73 }
74}
75
76impl HasConcreteType for Loc<NameID> {
77 fn into_typed_expression(&self) -> Loc<TypedExpression> {
78 TypedExpression::Name(self.inner.clone()).at_loc(self)
79 }
80}
81
82impl TypeState {
83 pub fn type_decl_to_concrete(
84 decl: &TypeDeclaration,
85 type_list: &TypeList,
86 params: Vec<ConcreteType>,
87 invert: bool,
88 ) -> ConcreteType {
89 assert!(
92 params.len() == decl.generic_args.len(),
93 "Too few type decl params in {:?}\n\n params: {:?}\n decl: {:?}",
94 decl,
95 params,
96 decl.generic_args
97 );
98
99 let generic_subs = decl
100 .generic_args
101 .iter()
102 .zip(params.iter())
103 .map(|(lhs, rhs)| (lhs.name_id(), rhs))
104 .collect::<HashMap<_, _>>();
105
106 match &decl.kind {
107 hir::TypeDeclKind::Enum(e) => {
108 let options = e
109 .options
110 .iter()
111 .map(|(name, args)| {
112 let args = args
113 .0
114 .iter()
115 .map(|arg| {
116 (
117 arg.name.inner.clone(),
118 Self::type_spec_to_concrete(
119 &arg.ty.inner,
120 type_list,
121 &generic_subs,
122 false,
123 ),
124 )
125 })
126 .collect();
127 (name.inner.clone(), args)
128 })
129 .collect();
130 ConcreteType::Enum { options }
131 }
132 hir::TypeDeclKind::Struct(s) => {
133 let members = s
134 .members
135 .0
136 .iter()
137 .map(
138 |Parameter {
139 name: ident,
140 ty: t,
141 no_mangle: _,
142 field_translator: _,
143 }| {
144 (
145 ident.inner.clone(),
146 Self::type_spec_to_concrete(t, type_list, &generic_subs, invert),
147 )
148 },
149 )
150 .collect();
151
152 let translators = s.members.0.iter().filter_map(
153 |Parameter {
154 name,
155 field_translator,
156 ..
157 }| {
158 field_translator
159 .as_ref()
160 .map(|t| (name.inner.clone(), t.clone()))
161 },
162 );
163
164 ConcreteType::Struct {
165 name: decl.name.inner.clone(),
166 is_port: s.is_port,
167 members,
168 field_translators: translators.collect(),
169 }
170 }
171 hir::TypeDeclKind::Primitive(PrimitiveType::Clock) => {
172 let concrete_type = ConcreteType::Single {
173 base: PrimitiveType::Clock,
174 params,
175 };
176
177 if invert {
178 ConcreteType::Backward(Box::new(concrete_type))
179 } else {
180 concrete_type
181 }
182 }
183 hir::TypeDeclKind::Primitive(primitive) => ConcreteType::Single {
184 base: primitive.clone(),
185 params,
186 },
187 }
188 }
189
190 pub fn type_expr_to_concrete(
191 expr: &TypeExpression,
192 type_list: &TypeList,
193 generic_substitutions: &HashMap<NameID, &ConcreteType>,
194 invert: bool,
195 ) -> ConcreteType {
196 match &expr {
197 hir::TypeExpression::Integer(val) => ConcreteType::Integer(val.clone()),
198 hir::TypeExpression::String(val) => ConcreteType::String(val.clone()),
199 hir::TypeExpression::TypeSpec(inner) => {
200 Self::type_spec_to_concrete(inner, type_list, generic_substitutions, invert)
201 }
202 hir::TypeExpression::ConstGeneric(_) => {
203 unreachable!("Const generic in type_expr_to_concrete")
204 }
205 }
206 }
207
208 pub fn type_spec_to_concrete(
209 spec: &TypeSpec,
210 type_list: &TypeList,
211 generic_substitutions: &HashMap<NameID, &ConcreteType>,
212 invert: bool,
213 ) -> ConcreteType {
214 match spec {
215 TypeSpec::Declared(name, params) => {
216 let params = params
217 .iter()
218 .map(|p| {
219 Self::type_expr_to_concrete(p, type_list, generic_substitutions, invert)
220 })
221 .collect();
222
223 let actual = type_list
224 .get(name)
225 .unwrap_or_else(|| panic!("Expected {:?} to be in type list", name));
226
227 Self::type_decl_to_concrete(actual, type_list, params, invert)
228 }
229 TypeSpec::Generic(name) => {
230 (*generic_substitutions
232 .get(name)
233 .unwrap_or_else(|| panic!("Expected a substitution for {}", name)))
234 .clone()
235 }
236 TypeSpec::Tuple(t) => {
237 let inner = t
238 .iter()
239 .map(|v| {
240 Self::type_spec_to_concrete(
241 &v.inner,
242 type_list,
243 generic_substitutions,
244 invert,
245 )
246 })
247 .collect::<Vec<_>>();
248 ConcreteType::Tuple(inner)
249 }
250 TypeSpec::Array { inner, size } => {
251 let size_type = Box::new(Self::type_expr_to_concrete(
252 size,
253 type_list,
254 generic_substitutions,
255 invert,
256 ));
257
258 let size = if let ConcreteType::Integer(size) = size_type.as_ref() {
259 size.clone()
260 } else {
261 panic!("Array size must be an integer")
262 };
263
264 ConcreteType::Array {
265 inner: Box::new(Self::type_spec_to_concrete(
266 inner,
267 type_list,
268 generic_substitutions,
269 invert,
270 )),
271 size,
272 }
273 }
274 TypeSpec::Wire(inner) => {
275 let inner = Box::new(Self::type_spec_to_concrete(
276 inner,
277 type_list,
278 generic_substitutions,
279 invert,
280 ));
281 if invert {
282 ConcreteType::Backward(inner)
283 } else {
284 ConcreteType::Wire(inner)
285 }
286 }
287 TypeSpec::Inverted(inner) => Self::type_spec_to_concrete(
288 inner,
289 type_list,
290 generic_substitutions,
291 !invert,
294 ),
295 TypeSpec::TraitSelf(_) => panic!("Trying to concretize HIR TraitSelf type"),
296 TypeSpec::Wildcard(_) => panic!("Trying to concretize HIR Wildcard type"),
297 }
298 }
299
300 pub fn inner_ungenerify_type(
301 &self,
302 var: &TypeVarID,
303 symtab: &SymbolTable,
304 type_list: &TypeList,
305 invert: bool,
306 ) -> Option<ConcreteType> {
307 match var.resolve(self) {
308 TypeVar::Known(_, KnownType::Error, _) => Some(ConcreteType::Error),
309 TypeVar::Known(_, KnownType::Named(t), params) => {
310 let params = params
311 .iter()
312 .map(|v| self.inner_ungenerify_type(v, symtab, type_list, invert))
313 .collect::<Option<Vec<_>>>()?;
314
315 type_list
316 .get(t)
317 .map(|t| Self::type_decl_to_concrete(&t.inner, type_list, params, invert))
318 }
319 TypeVar::Known(_, KnownType::Integer(val), params) => {
320 assert!(params.is_empty(), "integers cannot have type parameters");
321
322 Some(ConcreteType::Integer(val.clone()))
323 }
324 TypeVar::Known(_, KnownType::Bool(val), params) => {
325 assert!(
326 params.is_empty(),
327 "type level bools cannot have type parameters"
328 );
329
330 Some(ConcreteType::Bool(*val))
331 }
332 TypeVar::Known(_, KnownType::String(val), params) => {
333 assert!(
334 params.is_empty(),
335 "type level strings cannot have type parameters"
336 );
337
338 Some(ConcreteType::String(val.clone()))
339 }
340 TypeVar::Known(_, KnownType::Array, inner) => {
341 let value = self.inner_ungenerify_type(&inner[0], symtab, type_list, invert);
342 let size = self.ungenerify_type(&inner[1], symtab, type_list).map(|t| {
343 if let ConcreteType::Integer(size) = t {
344 size
345 } else {
346 panic!("Array size must be an integer")
347 }
348 });
349
350 match (value, size) {
351 (Some(value), Some(size)) => Some(ConcreteType::Array {
352 inner: Box::new(value),
353 size,
354 }),
355 _ => None,
356 }
357 }
358 TypeVar::Known(_, KnownType::Tuple, inner) => {
359 let inner = inner
360 .iter()
361 .map(|v| self.inner_ungenerify_type(v, symtab, type_list, invert))
362 .collect::<Option<Vec<_>>>()?;
363 Some(ConcreteType::Tuple(inner))
364 }
365 TypeVar::Known(_, KnownType::Wire, inner) => {
366 if invert {
367 self.inner_ungenerify_type(&inner[0], symtab, type_list, invert)
368 .map(|t| ConcreteType::Backward(Box::new(t)))
369 } else {
370 self.inner_ungenerify_type(&inner[0], symtab, type_list, invert)
371 .map(|t| ConcreteType::Wire(Box::new(t)))
372 }
373 }
374 TypeVar::Known(_, KnownType::Inverted, inner) => {
375 self.inner_ungenerify_type(&inner[0], symtab, type_list, !invert)
376 }
377 TypeVar::Unknown(_, _, _, _) => None,
378 }
379 }
380
381 pub fn ungenerify_type(
384 &self,
385 var: &TypeVarID,
386 symtab: &SymbolTable,
387 type_list: &TypeList,
388 ) -> Option<ConcreteType> {
389 self.inner_ungenerify_type(var, symtab, type_list, false)
390 }
391
392 pub fn concrete_type_of_infallible(
395 &self,
396 id: ExprID,
397 symtab: &SymbolTable,
398 type_list: &TypeList,
399 ) -> ConcreteType {
400 self.concrete_type_of(id.nowhere(), symtab, type_list)
401 .expect("Expr had generic type")
402 }
403
404 pub fn concrete_type_of(
407 &self,
408 id: impl HasConcreteType,
409 symtab: &SymbolTable,
410 types: &TypeList,
411 ) -> Result<ConcreteType, Diagnostic> {
412 let id = id.into_typed_expression();
413 let t = self.type_of(&id.inner);
414
415 if let Some(t) = self.ungenerify_type(&t, symtab, types) {
416 Ok(t)
417 } else {
418 if std::env::var("SPADE_TRACE_TYPEINFERENCE").is_ok() {
419 println!("The incomplete type is {}", t.debug_resolve(self))
420 }
421 Err(
422 Diagnostic::error(id, "Type of expression is not fully known")
423 .primary_label("The type of this expression is not fully known")
424 .note(format!("Found incomplete type: {t}", t = t.display(self))),
425 )
426 }
427 }
428
429 pub fn concrete_type_of_name(
432 &self,
433 name: &Loc<NameID>,
434 symtab: &SymbolTable,
435 types: &TypeList,
436 ) -> Result<ConcreteType, Diagnostic> {
437 let t = self.type_of(&TypedExpression::Name(name.inner.clone()));
438
439 if let Some(t) = self.ungenerify_type(&t, symtab, types) {
440 Ok(t)
441 } else {
442 Err(
443 Diagnostic::error(name, format!("Type of {name} is not fully known"))
444 .primary_label(format!("The type of {name} is not fully known"))
445 .note(format!("Found incomplete type: {t}", t = t.display(self))),
446 )
447 }
448 }
449}