1use std::sync::Arc;
7
8use crate::{
9 extension::{ExtensionId, ExtensionRegistry, SignatureError},
10 hugr::{HugrMut, NodeMetadata},
11 ops::{
12 constant::{CustomConst, CustomSerialized, OpaqueValue},
13 AliasDecl, AliasDefn, Call, CallIndirect, Case, Conditional, Const, DataflowBlock,
14 ExitBlock, FuncDecl, FuncDefn, Input, LoadConstant, LoadFunction, OpType, OpaqueOp, Output,
15 Tag, TailLoop, Value, CFG, DFG,
16 },
17 package::Package,
18 std_extensions::{
19 arithmetic::{float_types::ConstF64, int_types::ConstInt},
20 collections::array::ArrayValue,
21 },
22 types::{
23 type_param::TypeParam, type_row::TypeRowBase, CustomType, FuncTypeBase, MaybeRV,
24 PolyFuncType, PolyFuncTypeBase, RowVariable, Signature, Type, TypeArg, TypeBase, TypeBound,
25 TypeEnum, TypeName, TypeRow,
26 },
27 Direction, Hugr, HugrView, Node, Port,
28};
29use fxhash::FxHashMap;
30use hugr_model::v0 as model;
31use hugr_model::v0::table;
32use itertools::Either;
33use smol_str::{SmolStr, ToSmolStr};
34use thiserror::Error;
35
36#[derive(Debug, Clone, Error)]
38#[non_exhaustive]
39pub enum ImportError {
40 #[error("currently unsupported: {0}")]
44 Unsupported(String),
45 #[error("uninferred implicit: {0}")]
48 Uninferred(String),
49 #[error("signature error: {0}")]
51 Signature(#[from] SignatureError),
52 #[error("Importing the hugr requires extension {missing_ext}, which was not found in the registry. The available extensions are: [{}]",
54 available.iter().map(|ext| ext.to_string()).collect::<Vec<_>>().join(", "))]
55 Extension {
56 missing_ext: ExtensionId,
58 available: Vec<ExtensionId>,
60 },
61 #[error("Importing the hugr requires extension {ext} to have a type named {name}, but it was not found.")]
63 ExtensionType {
64 ext: ExtensionId,
66 name: TypeName,
68 },
69 #[error("validate error: {0}")]
71 Model(#[from] table::ModelError),
72 #[error("incorrect order hint: {0}")]
74 OrderHint(#[from] OrderHintError),
75}
76
77#[derive(Debug, Clone, Error)]
79#[non_exhaustive]
80pub enum OrderHintError {
81 #[error("duplicate order hint key {0}")]
83 DuplicateKey(table::NodeId, u64),
84 #[error("order hint with unknown key {0}")]
86 UnknownKey(u64),
87 #[error("order hint on node with no order port: {0}")]
89 NoOrderPort(table::NodeId),
90}
91
92macro_rules! error_unsupported {
94 ($($e:expr),*) => { ImportError::Unsupported(format!($($e),*)) }
95}
96
97macro_rules! error_uninferred {
99 ($($e:expr),*) => { ImportError::Uninferred(format!($($e),*)) }
100}
101
102pub fn import_package(
104 package: &table::Package,
105 extensions: &ExtensionRegistry,
106) -> Result<Package, ImportError> {
107 let modules = package
108 .modules
109 .iter()
110 .map(|module| import_hugr(module, extensions))
111 .collect::<Result<Vec<_>, _>>()?;
112
113 let package = Package::new(modules);
115 Ok(package)
116}
117
118pub fn import_hugr(
120 module: &table::Module,
121 extensions: &ExtensionRegistry,
122) -> Result<Hugr, ImportError> {
123 let mut ctx = Context {
126 module,
127 hugr: Hugr::new(),
128 link_ports: FxHashMap::default(),
129 static_edges: Vec::new(),
130 extensions,
131 nodes: FxHashMap::default(),
132 local_vars: FxHashMap::default(),
133 custom_name_cache: FxHashMap::default(),
134 region_scope: table::RegionId::default(),
135 };
136
137 ctx.import_root()?;
138 ctx.link_ports()?;
139 ctx.link_static_ports()?;
140
141 Ok(ctx.hugr)
142}
143
144struct Context<'a> {
145 module: &'a table::Module<'a>,
147
148 hugr: Hugr,
150
151 link_ports: FxHashMap<(table::RegionId, table::LinkIndex), Vec<(Node, Port)>>,
154
155 static_edges: Vec<(table::NodeId, table::NodeId)>,
158
159 extensions: &'a ExtensionRegistry,
161
162 nodes: FxHashMap<table::NodeId, Node>,
164
165 local_vars: FxHashMap<table::VarId, LocalVar>,
166
167 custom_name_cache: FxHashMap<&'a str, (ExtensionId, SmolStr)>,
168
169 region_scope: table::RegionId,
170}
171
172impl<'a> Context<'a> {
173 fn get_node_signature(&mut self, node: table::NodeId) -> Result<Signature, ImportError> {
175 let node_data = self.get_node(node)?;
176 let signature = node_data
177 .signature
178 .ok_or_else(|| error_uninferred!("node signature"))?;
179 self.import_func_type(signature)
180 }
181
182 #[inline]
184 fn get_node(&self, node_id: table::NodeId) -> Result<&'a table::Node<'a>, ImportError> {
185 self.module
186 .get_node(node_id)
187 .ok_or_else(|| table::ModelError::NodeNotFound(node_id).into())
188 }
189
190 #[inline]
192 fn get_term(&self, term_id: table::TermId) -> Result<&'a table::Term<'a>, ImportError> {
193 self.module
194 .get_term(term_id)
195 .ok_or_else(|| table::ModelError::TermNotFound(term_id).into())
196 }
197
198 #[inline]
200 fn get_region(&self, region_id: table::RegionId) -> Result<&'a table::Region<'a>, ImportError> {
201 self.module
202 .get_region(region_id)
203 .ok_or_else(|| table::ModelError::RegionNotFound(region_id).into())
204 }
205
206 fn make_node(
207 &mut self,
208 node_id: table::NodeId,
209 op: OpType,
210 parent: Node,
211 ) -> Result<Node, ImportError> {
212 let node = self.hugr.add_node_with_parent(parent, op);
213 self.nodes.insert(node_id, node);
214
215 let node_data = self.get_node(node_id)?;
216 self.record_links(node, Direction::Incoming, node_data.inputs);
217 self.record_links(node, Direction::Outgoing, node_data.outputs);
218
219 for meta_item in node_data.meta {
220 self.import_node_metadata(node, *meta_item)?;
221 }
222
223 Ok(node)
224 }
225
226 fn import_node_metadata(
227 &mut self,
228 node: Node,
229 meta_item: table::TermId,
230 ) -> Result<(), ImportError> {
231 if let Some([name_arg, json_arg]) = self.match_symbol(meta_item, model::COMPAT_META_JSON)? {
233 let table::Term::Literal(model::Literal::Str(name)) = self.get_term(name_arg)? else {
234 return Err(table::ModelError::TypeError(meta_item).into());
235 };
236
237 let table::Term::Literal(model::Literal::Str(json_str)) = self.get_term(json_arg)?
238 else {
239 return Err(table::ModelError::TypeError(meta_item).into());
240 };
241
242 let json_value: NodeMetadata = serde_json::from_str(json_str)
243 .map_err(|_| table::ModelError::TypeError(meta_item))?;
244
245 self.hugr.set_metadata(node, name, json_value);
246 }
247
248 if let Some([]) = self.match_symbol(meta_item, model::CORE_ENTRYPOINT)? {
250 self.hugr.set_entrypoint(node);
251 }
252
253 Ok(())
254 }
255
256 fn record_links(&mut self, node: Node, direction: Direction, links: &'a [table::LinkIndex]) {
258 let optype = self.hugr.get_optype(node);
259 debug_assert!(links.len() <= optype.port_count(direction));
261
262 for (link, port) in links.iter().zip(self.hugr.node_ports(node, direction)) {
263 self.link_ports
264 .entry((self.region_scope, *link))
265 .or_default()
266 .push((node, port));
267 }
268 }
269
270 fn link_ports(&mut self) -> Result<(), ImportError> {
273 let mut inputs = Vec::new();
276 let mut outputs = Vec::new();
277
278 for (link_id, link_ports) in std::mem::take(&mut self.link_ports) {
279 if link_ports.is_empty() {
281 continue;
282 }
283
284 for (node, port) in link_ports {
285 match port.as_directed() {
286 Either::Left(input) => inputs.push((node, input)),
287 Either::Right(output) => outputs.push((node, output)),
288 }
289 }
290
291 match (inputs.as_slice(), outputs.as_slice()) {
292 ([], []) => {
293 unreachable!();
294 }
295 (_, [output]) => {
296 for (node, port) in inputs.iter() {
297 self.hugr.connect(output.0, output.1, *node, *port);
298 }
299 }
300 ([input], _) => {
301 for (node, port) in outputs.iter() {
302 self.hugr.connect(*node, *port, input.0, input.1);
303 }
304 }
305 _ => {
306 return Err(error_unsupported!(
307 "link {:?} would require hyperedge",
308 link_id
309 ));
310 }
311 }
312
313 inputs.clear();
314 outputs.clear();
315 }
316
317 Ok(())
318 }
319
320 fn link_static_ports(&mut self) -> Result<(), ImportError> {
321 for (src_id, dst_id) in std::mem::take(&mut self.static_edges) {
322 let src = self.nodes[&src_id];
324 let dst = self.nodes[&dst_id];
325 let src_port = self.hugr.get_optype(src).static_output_port().unwrap();
326 let dst_port = self.hugr.get_optype(dst).static_input_port().unwrap();
327 self.hugr.connect(src, src_port, dst, dst_port);
328 }
329
330 Ok(())
331 }
332
333 fn get_symbol_name(&self, node_id: table::NodeId) -> Result<&'a str, ImportError> {
334 let node_data = self.get_node(node_id)?;
335 let name = node_data
336 .operation
337 .symbol()
338 .ok_or(table::ModelError::InvalidSymbol(node_id))?;
339 Ok(name)
340 }
341
342 fn get_func_signature(
343 &mut self,
344 func_node: table::NodeId,
345 ) -> Result<PolyFuncType, ImportError> {
346 let symbol = match self.get_node(func_node)?.operation {
347 table::Operation::DefineFunc(symbol) => symbol,
348 table::Operation::DeclareFunc(symbol) => symbol,
349 _ => return Err(table::ModelError::UnexpectedOperation(func_node).into()),
350 };
351
352 self.import_poly_func_type(func_node, *symbol, |_, signature| Ok(signature))
353 }
354
355 fn import_root(&mut self) -> Result<(), ImportError> {
357 self.region_scope = self.module.root;
358 let region_data = self.get_region(self.module.root)?;
359
360 for node in region_data.children {
361 self.import_node(*node, self.hugr.entrypoint())?;
362 }
363
364 Ok(())
365 }
366
367 fn import_node(
368 &mut self,
369 node_id: table::NodeId,
370 parent: Node,
371 ) -> Result<Option<Node>, ImportError> {
372 let node_data = self.get_node(node_id)?;
373
374 match node_data.operation {
375 table::Operation::Invalid => Err(table::ModelError::InvalidOperation(node_id).into()),
376 table::Operation::Dfg => {
377 let signature = self.get_node_signature(node_id)?;
378 let optype = OpType::DFG(DFG { signature });
379 let node = self.make_node(node_id, optype, parent)?;
380
381 let [region] = node_data.regions else {
382 return Err(table::ModelError::InvalidRegions(node_id).into());
383 };
384
385 self.import_dfg_region(node_id, *region, node)?;
386 Ok(Some(node))
387 }
388
389 table::Operation::Cfg => {
390 let signature = self.get_node_signature(node_id)?;
391 let optype = OpType::CFG(CFG { signature });
392 let node = self.make_node(node_id, optype, parent)?;
393
394 let [region] = node_data.regions else {
395 return Err(table::ModelError::InvalidRegions(node_id).into());
396 };
397
398 self.import_cfg_region(node_id, *region, node)?;
399 Ok(Some(node))
400 }
401
402 table::Operation::Block => {
403 let node = self.import_cfg_block(node_id, parent)?;
404 Ok(Some(node))
405 }
406
407 table::Operation::DefineFunc(symbol) => {
408 self.import_poly_func_type(node_id, *symbol, |ctx, signature| {
409 let optype = OpType::FuncDefn(FuncDefn {
410 name: symbol.name.to_string(),
411 signature,
412 });
413
414 let node = ctx.make_node(node_id, optype, parent)?;
415
416 let [region] = node_data.regions else {
417 return Err(table::ModelError::InvalidRegions(node_id).into());
418 };
419
420 ctx.import_dfg_region(node_id, *region, node)?;
421
422 Ok(Some(node))
423 })
424 }
425
426 table::Operation::DeclareFunc(symbol) => {
427 self.import_poly_func_type(node_id, *symbol, |ctx, signature| {
428 let optype = OpType::FuncDecl(FuncDecl {
429 name: symbol.name.to_string(),
430 signature,
431 });
432
433 let node = ctx.make_node(node_id, optype, parent)?;
434
435 Ok(Some(node))
436 })
437 }
438
439 table::Operation::TailLoop => {
440 let node = self.import_tail_loop(node_id, parent)?;
441 Ok(Some(node))
442 }
443 table::Operation::Conditional => {
444 let node = self.import_conditional(node_id, parent)?;
445 Ok(Some(node))
446 }
447
448 table::Operation::Custom(operation) => {
449 if let Some([_, _]) = self.match_symbol(operation, model::CORE_CALL_INDIRECT)? {
450 let signature = self.get_node_signature(node_id)?;
451 let optype = OpType::CallIndirect(CallIndirect { signature });
452 let node = self.make_node(node_id, optype, parent)?;
453 return Ok(Some(node));
454 }
455
456 if let Some([_, _, func]) = self.match_symbol(operation, model::CORE_CALL)? {
457 let table::Term::Apply(symbol, args) = self.get_term(func)? else {
458 return Err(table::ModelError::TypeError(func).into());
459 };
460
461 let func_sig = self.get_func_signature(*symbol)?;
462
463 let type_args = args
464 .iter()
465 .map(|term| self.import_type_arg(*term))
466 .collect::<Result<Vec<TypeArg>, _>>()?;
467
468 self.static_edges.push((*symbol, node_id));
469 let optype = OpType::Call(Call::try_new(func_sig, type_args)?);
470
471 let node = self.make_node(node_id, optype, parent)?;
472 return Ok(Some(node));
473 }
474
475 if let Some([_, value]) = self.match_symbol(operation, model::CORE_LOAD_CONST)? {
476 if let table::Term::Apply(symbol, args) = self.get_term(value)? {
478 let func_node_data = self
479 .module
480 .get_node(*symbol)
481 .ok_or(table::ModelError::NodeNotFound(*symbol))?;
482
483 if let table::Operation::DefineFunc(_) | table::Operation::DeclareFunc(_) =
484 func_node_data.operation
485 {
486 let func_sig = self.get_func_signature(*symbol)?;
487 let type_args = args
488 .iter()
489 .map(|term| self.import_type_arg(*term))
490 .collect::<Result<Vec<TypeArg>, _>>()?;
491
492 self.static_edges.push((*symbol, node_id));
493
494 let optype =
495 OpType::LoadFunction(LoadFunction::try_new(func_sig, type_args)?);
496
497 let node = self.make_node(node_id, optype, parent)?;
498 return Ok(Some(node));
499 }
500 }
501
502 let signature = node_data
504 .signature
505 .ok_or_else(|| error_uninferred!("node signature"))?;
506 let [_, outputs] = self.get_func_type(signature)?;
507 let outputs = self.import_closed_list(outputs)?;
508 let output = outputs
509 .first()
510 .ok_or(table::ModelError::TypeError(signature))?;
511 let datatype = self.import_type(*output)?;
512
513 let imported_value = self.import_value(value, *output)?;
514
515 let load_const_node = self.make_node(
516 node_id,
517 OpType::LoadConstant(LoadConstant {
518 datatype: datatype.clone(),
519 }),
520 parent,
521 )?;
522
523 let const_node = self
524 .hugr
525 .add_node_with_parent(parent, OpType::Const(Const::new(imported_value)));
526
527 self.hugr.connect(const_node, 0, load_const_node, 0);
528
529 return Ok(Some(load_const_node));
530 }
531
532 if let Some([_, _, tag]) = self.match_symbol(operation, model::CORE_MAKE_ADT)? {
533 let table::Term::Literal(model::Literal::Nat(tag)) = self.get_term(tag)? else {
534 return Err(table::ModelError::TypeError(tag).into());
535 };
536
537 let signature = node_data
538 .signature
539 .ok_or_else(|| error_uninferred!("node signature"))?;
540 let [_, outputs] = self.get_func_type(signature)?;
541 let (variants, _) = self.import_adt_and_rest(node_id, outputs)?;
542 let node = self.make_node(
543 node_id,
544 OpType::Tag(Tag {
545 variants,
546 tag: *tag as usize,
547 }),
548 parent,
549 )?;
550 return Ok(Some(node));
551 }
552
553 let table::Term::Apply(node, params) = self.get_term(operation)? else {
554 return Err(table::ModelError::TypeError(operation).into());
555 };
556 let name = self.get_symbol_name(*node)?;
557 let args = params
558 .iter()
559 .map(|param| self.import_type_arg(*param))
560 .collect::<Result<Vec<_>, _>>()?;
561 let (extension, name) = self.import_custom_name(name)?;
562 let signature = self.get_node_signature(node_id)?;
563
564 let optype = OpType::OpaqueOp(OpaqueOp::new(
570 extension,
571 name,
572 String::default(),
573 args,
574 signature,
575 ));
576
577 let node = self.make_node(node_id, optype, parent)?;
578
579 Ok(Some(node))
580 }
581
582 table::Operation::DefineAlias(symbol, value) => {
583 if !symbol.params.is_empty() {
584 return Err(error_unsupported!(
585 "parameters or constraints in alias definition"
586 ));
587 }
588
589 let optype = OpType::AliasDefn(AliasDefn {
590 name: symbol.name.to_smolstr(),
591 definition: self.import_type(value)?,
592 });
593
594 let node = self.make_node(node_id, optype, parent)?;
595 Ok(Some(node))
596 }
597
598 table::Operation::DeclareAlias(symbol) => {
599 if !symbol.params.is_empty() {
600 return Err(error_unsupported!(
601 "parameters or constraints in alias declaration"
602 ));
603 }
604
605 let optype = OpType::AliasDecl(AliasDecl {
606 name: symbol.name.to_smolstr(),
607 bound: TypeBound::Copyable,
608 });
609
610 let node = self.make_node(node_id, optype, parent)?;
611 Ok(Some(node))
612 }
613
614 table::Operation::Import { .. } => Ok(None),
615
616 table::Operation::DeclareConstructor { .. } => Ok(None),
617 table::Operation::DeclareOperation { .. } => Ok(None),
618 }
619 }
620
621 fn import_dfg_region(
622 &mut self,
623 node_id: table::NodeId,
624 region: table::RegionId,
625 node: Node,
626 ) -> Result<(), ImportError> {
627 let region_data = self.get_region(region)?;
628
629 let prev_region = self.region_scope;
630 if region_data.scope.is_some() {
631 self.region_scope = region;
632 }
633
634 if region_data.kind != model::RegionKind::DataFlow {
635 return Err(table::ModelError::InvalidRegions(node_id).into());
636 }
637
638 let signature = self.import_func_type(
639 region_data
640 .signature
641 .ok_or_else(|| error_uninferred!("region signature"))?,
642 )?;
643
644 let input = self.hugr.add_node_with_parent(
646 node,
647 OpType::Input(Input {
648 types: signature.input,
649 }),
650 );
651 let output = self.hugr.add_node_with_parent(
652 node,
653 OpType::Output(Output {
654 types: signature.output,
655 }),
656 );
657
658 self.record_links(input, Direction::Outgoing, region_data.sources);
660 self.record_links(output, Direction::Incoming, region_data.targets);
661
662 for child in region_data.children {
663 self.import_node(*child, node)?;
664 }
665
666 self.create_order_edges(region)?;
667
668 for meta_item in region_data.meta {
669 self.import_node_metadata(node, *meta_item)?;
670 }
671
672 self.region_scope = prev_region;
673
674 Ok(())
675 }
676
677 fn create_order_edges(&mut self, region_id: table::RegionId) -> Result<(), ImportError> {
681 let region_data = self.get_region(region_id)?;
682 debug_assert_eq!(region_data.kind, model::RegionKind::DataFlow);
683
684 let mut order_keys = FxHashMap::<u64, table::NodeId>::default();
687
688 for child_id in region_data.children {
689 let child_data = self.get_node(*child_id)?;
690
691 for meta_id in child_data.meta {
692 let Some([key]) = self.match_symbol(*meta_id, model::ORDER_HINT_KEY)? else {
693 continue;
694 };
695
696 let table::Term::Literal(model::Literal::Nat(key)) = self.get_term(key)? else {
697 continue;
698 };
699
700 if order_keys.insert(*key, *child_id).is_some() {
701 return Err(OrderHintError::DuplicateKey(*child_id, *key).into());
702 }
703 }
704 }
705
706 for meta_id in region_data.meta {
708 let Some([a, b]) = self.match_symbol(*meta_id, model::ORDER_HINT_ORDER)? else {
709 continue;
710 };
711
712 let table::Term::Literal(model::Literal::Nat(a)) = self.get_term(a)? else {
713 continue;
714 };
715
716 let table::Term::Literal(model::Literal::Nat(b)) = self.get_term(b)? else {
717 continue;
718 };
719
720 let a = order_keys.get(a).ok_or(OrderHintError::UnknownKey(*a))?;
721 let b = order_keys.get(b).ok_or(OrderHintError::UnknownKey(*b))?;
722
723 let a_node = self.nodes[a];
726 let b_node = self.nodes[b];
727
728 let a_port = self
729 .hugr
730 .get_optype(a_node)
731 .other_output_port()
732 .ok_or(OrderHintError::NoOrderPort(*a))?;
733
734 let b_port = self
735 .hugr
736 .get_optype(b_node)
737 .other_input_port()
738 .ok_or(OrderHintError::NoOrderPort(*b))?;
739
740 self.hugr.connect(a_node, a_port, b_node, b_port);
741 }
742
743 Ok(())
744 }
745
746 fn import_adt_and_rest(
747 &mut self,
748 node_id: table::NodeId,
749 list: table::TermId,
750 ) -> Result<(Vec<TypeRow>, TypeRow), ImportError> {
751 let items = self.import_closed_list(list)?;
752
753 let Some((first, rest)) = items.split_first() else {
754 return Err(table::ModelError::InvalidRegions(node_id).into());
755 };
756
757 let sum_rows: Vec<_> = {
758 let [variants] = self.expect_symbol(*first, model::CORE_ADT)?;
759 self.import_type_rows(variants)?
760 };
761
762 let rest = rest
763 .iter()
764 .map(|term| self.import_type(*term))
765 .collect::<Result<Vec<_>, _>>()?
766 .into();
767
768 Ok((sum_rows, rest))
769 }
770
771 fn import_tail_loop(
772 &mut self,
773 node_id: table::NodeId,
774 parent: Node,
775 ) -> Result<Node, ImportError> {
776 let node_data = self.get_node(node_id)?;
777 debug_assert_eq!(node_data.operation, table::Operation::TailLoop);
778
779 let [region] = node_data.regions else {
780 return Err(table::ModelError::InvalidRegions(node_id).into());
781 };
782 let region_data = self.get_region(*region)?;
783
784 let [_, region_outputs] = self.get_func_type(
785 region_data
786 .signature
787 .ok_or_else(|| error_uninferred!("region signature"))?,
788 )?;
789 let (sum_rows, rest) = self.import_adt_and_rest(node_id, region_outputs)?;
790
791 let (just_inputs, just_outputs) = {
792 let mut sum_rows = sum_rows.into_iter();
793
794 let Some(just_inputs) = sum_rows.next() else {
795 return Err(table::ModelError::TypeError(region_outputs).into());
796 };
797
798 let Some(just_outputs) = sum_rows.next() else {
799 return Err(table::ModelError::TypeError(region_outputs).into());
800 };
801
802 (just_inputs, just_outputs)
803 };
804
805 let optype = OpType::TailLoop(TailLoop {
806 just_inputs,
807 just_outputs,
808 rest,
809 });
810
811 let node = self.make_node(node_id, optype, parent)?;
812
813 self.import_dfg_region(node_id, *region, node)?;
814 Ok(node)
815 }
816
817 fn import_conditional(
818 &mut self,
819 node_id: table::NodeId,
820 parent: Node,
821 ) -> Result<Node, ImportError> {
822 let node_data = self.get_node(node_id)?;
823 debug_assert_eq!(node_data.operation, table::Operation::Conditional);
824 let [inputs, outputs] = self.get_func_type(
825 node_data
826 .signature
827 .ok_or_else(|| error_uninferred!("node signature"))?,
828 )?;
829 let (sum_rows, other_inputs) = self.import_adt_and_rest(node_id, inputs)?;
830 let outputs = self.import_type_row(outputs)?;
831
832 let optype = OpType::Conditional(Conditional {
833 sum_rows,
834 other_inputs,
835 outputs,
836 });
837
838 let node = self.make_node(node_id, optype, parent)?;
839
840 for region in node_data.regions {
841 let region_data = self.get_region(*region)?;
842 let signature = self.import_func_type(
843 region_data
844 .signature
845 .ok_or_else(|| error_uninferred!("region signature"))?,
846 )?;
847
848 let case_node = self
849 .hugr
850 .add_node_with_parent(node, OpType::Case(Case { signature }));
851
852 self.import_dfg_region(node_id, *region, case_node)?;
853 }
854
855 Ok(node)
856 }
857
858 fn import_cfg_region(
859 &mut self,
860 node_id: table::NodeId,
861 region: table::RegionId,
862 node: Node,
863 ) -> Result<(), ImportError> {
864 let region_data = self.get_region(region)?;
865
866 if region_data.kind != model::RegionKind::ControlFlow {
867 return Err(table::ModelError::InvalidRegions(node_id).into());
868 }
869
870 let prev_region = self.region_scope;
871 if region_data.scope.is_some() {
872 self.region_scope = region;
873 }
874
875 let [region_source, region_targets] = self.get_func_type(
876 region_data
877 .signature
878 .ok_or_else(|| error_uninferred!("region signature"))?,
879 )?;
880
881 let region_source_types = self.import_closed_list(region_source)?;
882 let region_target_types = self.import_closed_list(region_targets)?;
883
884 {
888 let types = {
889 let [ctrl_type] = region_source_types.as_slice() else {
890 return Err(table::ModelError::TypeError(region_source).into());
891 };
892
893 let [types] = self.expect_symbol(*ctrl_type, model::CORE_CTRL)?;
894 self.import_type_row(types)?
895 };
896
897 let entry = self.hugr.add_node_with_parent(
898 node,
899 OpType::DataflowBlock(DataflowBlock {
900 inputs: types.clone(),
901 other_outputs: TypeRow::default(),
902 sum_rows: vec![types.clone()],
903 }),
904 );
905
906 self.record_links(entry, Direction::Outgoing, region_data.sources);
907
908 let node_input = self.hugr.add_node_with_parent(
909 entry,
910 OpType::Input(Input {
911 types: types.clone(),
912 }),
913 );
914
915 let node_output = self.hugr.add_node_with_parent(
916 entry,
917 OpType::Output(Output {
918 types: vec![Type::new_sum([types.clone()])].into(),
919 }),
920 );
921
922 let node_tag = self.hugr.add_node_with_parent(
923 entry,
924 OpType::Tag(Tag {
925 tag: 0,
926 variants: vec![types],
927 }),
928 );
929
930 let input_outputs = self.hugr.node_outputs(node_input);
932 let tag_inputs = self.hugr.node_inputs(node_tag);
933 let mut connections =
934 Vec::with_capacity(input_outputs.size_hint().0 + tag_inputs.size_hint().0);
935
936 for (a, b) in input_outputs.zip(tag_inputs) {
937 connections.push((node_input, a, node_tag, b));
938 }
939
940 let tag_outputs = self.hugr.node_outputs(node_tag);
942 let output_inputs = self.hugr.node_inputs(node_output);
943
944 for (a, b) in tag_outputs.zip(output_inputs) {
945 connections.push((node_tag, a, node_output, b));
946 }
947
948 for (src, src_port, dst, dst_port) in connections {
949 self.hugr.connect(src, src_port, dst, dst_port);
950 }
951 }
952
953 for child in region_data.children {
954 self.import_node(*child, node)?;
955 }
956
957 {
959 let cfg_outputs = {
960 let [ctrl_type] = region_target_types.as_slice() else {
961 return Err(table::ModelError::TypeError(region_targets).into());
962 };
963
964 let [types] = self.expect_symbol(*ctrl_type, model::CORE_CTRL)?;
965 self.import_type_row(types)?
966 };
967
968 let exit = self
969 .hugr
970 .add_node_with_parent(node, OpType::ExitBlock(ExitBlock { cfg_outputs }));
971 self.record_links(exit, Direction::Incoming, region_data.targets);
972 }
973
974 for meta_item in region_data.meta {
975 self.import_node_metadata(node, *meta_item)?;
976 }
977
978 self.region_scope = prev_region;
979
980 Ok(())
981 }
982
983 fn import_cfg_block(
984 &mut self,
985 node_id: table::NodeId,
986 parent: Node,
987 ) -> Result<Node, ImportError> {
988 let node_data = self.get_node(node_id)?;
989 debug_assert_eq!(node_data.operation, table::Operation::Block);
990
991 let [region] = node_data.regions else {
992 return Err(table::ModelError::InvalidRegions(node_id).into());
993 };
994 let region_data = self.get_region(*region)?;
995 let [inputs, outputs] = self.get_func_type(
996 region_data
997 .signature
998 .ok_or_else(|| error_uninferred!("region signature"))?,
999 )?;
1000 let inputs = self.import_type_row(inputs)?;
1001 let (sum_rows, other_outputs) = self.import_adt_and_rest(node_id, outputs)?;
1002
1003 let optype = OpType::DataflowBlock(DataflowBlock {
1004 inputs,
1005 other_outputs,
1006 sum_rows,
1007 });
1008 let node = self.make_node(node_id, optype, parent)?;
1009
1010 self.import_dfg_region(node_id, *region, node)?;
1011 Ok(node)
1012 }
1013
1014 fn import_poly_func_type<RV: MaybeRV, T>(
1015 &mut self,
1016 node: table::NodeId,
1017 symbol: table::Symbol<'a>,
1018 in_scope: impl FnOnce(&mut Self, PolyFuncTypeBase<RV>) -> Result<T, ImportError>,
1019 ) -> Result<T, ImportError> {
1020 let mut imported_params = Vec::with_capacity(symbol.params.len());
1021
1022 for (index, param) in symbol.params.iter().enumerate() {
1023 self.local_vars
1024 .insert(table::VarId(node, index as _), LocalVar::new(param.r#type));
1025 }
1026
1027 for constraint in symbol.constraints {
1028 if let Some([term]) = self.match_symbol(*constraint, model::CORE_NON_LINEAR)? {
1029 let table::Term::Var(var) = self.get_term(term)? else {
1030 return Err(error_unsupported!(
1031 "constraint on term that is not a variable"
1032 ));
1033 };
1034
1035 self.local_vars
1036 .get_mut(var)
1037 .ok_or(table::ModelError::InvalidVar(*var))?
1038 .bound = TypeBound::Copyable;
1039 } else {
1040 return Err(error_unsupported!("constraint other than copy or discard"));
1041 }
1042 }
1043
1044 for (index, param) in symbol.params.iter().enumerate() {
1045 let bound = self.local_vars[&table::VarId(node, index as _)].bound;
1047 imported_params.push(self.import_type_param(param.r#type, bound)?);
1048 }
1049
1050 let body = self.import_func_type::<RV>(symbol.signature)?;
1051 in_scope(self, PolyFuncTypeBase::new(imported_params, body))
1052 }
1053
1054 fn import_type_param(
1056 &mut self,
1057 term_id: table::TermId,
1058 bound: TypeBound,
1059 ) -> Result<TypeParam, ImportError> {
1060 if let Some([]) = self.match_symbol(term_id, model::CORE_STR_TYPE)? {
1061 return Ok(TypeParam::String);
1062 }
1063
1064 if let Some([]) = self.match_symbol(term_id, model::CORE_NAT_TYPE)? {
1065 return Ok(TypeParam::max_nat());
1066 }
1067
1068 if let Some([]) = self.match_symbol(term_id, model::CORE_BYTES_TYPE)? {
1069 return Err(error_unsupported!(
1070 "`{}` as `TypeParam`",
1071 model::CORE_BYTES_TYPE
1072 ));
1073 }
1074
1075 if let Some([]) = self.match_symbol(term_id, model::CORE_FLOAT_TYPE)? {
1076 return Err(error_unsupported!(
1077 "`{}` as `TypeParam`",
1078 model::CORE_FLOAT_TYPE
1079 ));
1080 }
1081
1082 if let Some([]) = self.match_symbol(term_id, model::CORE_TYPE)? {
1083 return Ok(TypeParam::Type { b: bound });
1084 }
1085
1086 if let Some([]) = self.match_symbol(term_id, model::CORE_STATIC)? {
1087 return Err(error_unsupported!(
1088 "`{}` as `TypeParam`",
1089 model::CORE_STATIC
1090 ));
1091 }
1092
1093 if let Some([]) = self.match_symbol(term_id, model::CORE_CONSTRAINT)? {
1094 return Err(error_unsupported!(
1095 "`{}` as `TypeParam`",
1096 model::CORE_CONSTRAINT
1097 ));
1098 }
1099
1100 if let Some([]) = self.match_symbol(term_id, model::CORE_CONST)? {
1101 return Err(error_unsupported!("`{}` as `TypeParam`", model::CORE_CONST));
1102 }
1103
1104 if let Some([]) = self.match_symbol(term_id, model::CORE_CTRL_TYPE)? {
1105 return Err(error_unsupported!(
1106 "`{}` as `TypeParam`",
1107 model::CORE_CTRL_TYPE
1108 ));
1109 }
1110
1111 if let Some([item_type]) = self.match_symbol(term_id, model::CORE_LIST_TYPE)? {
1112 let param = Box::new(self.import_type_param(item_type, TypeBound::Any)?);
1115 return Ok(TypeParam::List { param });
1116 }
1117
1118 if let Some([_]) = self.match_symbol(term_id, model::CORE_TUPLE_TYPE)? {
1119 todo!("import tuple type");
1122 }
1123
1124 match self.get_term(term_id)? {
1125 table::Term::Wildcard => Err(error_uninferred!("wildcard")),
1126
1127 table::Term::Var { .. } => Err(error_unsupported!("type variable as `TypeParam`")),
1128 table::Term::Apply(symbol, _) => {
1129 let name = self.get_symbol_name(*symbol)?;
1130 Err(error_unsupported!("custom type `{}` as `TypeParam`", name))
1131 }
1132
1133 table::Term::Tuple(_)
1134 | table::Term::List { .. }
1135 | table::Term::Func { .. }
1136 | table::Term::Literal(_) => Err(table::ModelError::TypeError(term_id).into()),
1137 }
1138 }
1139
1140 fn import_type_arg(&mut self, term_id: table::TermId) -> Result<TypeArg, ImportError> {
1142 if let Some([]) = self.match_symbol(term_id, model::CORE_STR_TYPE)? {
1143 return Err(error_unsupported!(
1144 "`{}` as `TypeArg`",
1145 model::CORE_STR_TYPE
1146 ));
1147 }
1148
1149 if let Some([]) = self.match_symbol(term_id, model::CORE_NAT_TYPE)? {
1150 return Err(error_unsupported!(
1151 "`{}` as `TypeArg`",
1152 model::CORE_NAT_TYPE
1153 ));
1154 }
1155
1156 if let Some([]) = self.match_symbol(term_id, model::CORE_BYTES_TYPE)? {
1157 return Err(error_unsupported!(
1158 "`{}` as `TypeArg`",
1159 model::CORE_BYTES_TYPE
1160 ));
1161 }
1162
1163 if let Some([]) = self.match_symbol(term_id, model::CORE_FLOAT_TYPE)? {
1164 return Err(error_unsupported!(
1165 "`{}` as `TypeArg`",
1166 model::CORE_FLOAT_TYPE
1167 ));
1168 }
1169
1170 if let Some([]) = self.match_symbol(term_id, model::CORE_TYPE)? {
1171 return Err(error_unsupported!("`{}` as `TypeArg`", model::CORE_TYPE));
1172 }
1173
1174 if let Some([]) = self.match_symbol(term_id, model::CORE_CONSTRAINT)? {
1175 return Err(error_unsupported!(
1176 "`{}` as `TypeArg`",
1177 model::CORE_CONSTRAINT
1178 ));
1179 }
1180
1181 if let Some([]) = self.match_symbol(term_id, model::CORE_STATIC)? {
1182 return Err(error_unsupported!("`{}` as `TypeArg`", model::CORE_STATIC));
1183 }
1184
1185 if let Some([]) = self.match_symbol(term_id, model::CORE_CTRL_TYPE)? {
1186 return Err(error_unsupported!(
1187 "`{}` as `TypeArg`",
1188 model::CORE_CTRL_TYPE
1189 ));
1190 }
1191
1192 if let Some([]) = self.match_symbol(term_id, model::CORE_CONST)? {
1193 return Err(error_unsupported!("`{}` as `TypeArg`", model::CORE_CONST));
1194 }
1195
1196 if let Some([]) = self.match_symbol(term_id, model::CORE_LIST_TYPE)? {
1197 return Err(error_unsupported!(
1198 "`{}` as `TypeArg`",
1199 model::CORE_LIST_TYPE
1200 ));
1201 }
1202
1203 match self.get_term(term_id)? {
1204 table::Term::Wildcard => Err(error_uninferred!("wildcard")),
1205
1206 table::Term::Var(var) => {
1207 let var_info = self
1208 .local_vars
1209 .get(var)
1210 .ok_or(table::ModelError::InvalidVar(*var))?;
1211 let decl = self.import_type_param(var_info.r#type, var_info.bound)?;
1212 Ok(TypeArg::new_var_use(var.1 as _, decl))
1213 }
1214
1215 table::Term::List { .. } => {
1216 let elems = self
1217 .import_closed_list(term_id)?
1218 .iter()
1219 .map(|item| self.import_type_arg(*item))
1220 .collect::<Result<_, _>>()?;
1221
1222 Ok(TypeArg::Sequence { elems })
1223 }
1224
1225 table::Term::Tuple { .. } => {
1226 Err(error_unsupported!("tuples as `TypeArg`"))
1230 }
1231
1232 table::Term::Literal(model::Literal::Str(value)) => Ok(TypeArg::String {
1233 arg: value.to_string(),
1234 }),
1235
1236 table::Term::Literal(model::Literal::Nat(value)) => {
1237 Ok(TypeArg::BoundedNat { n: *value })
1238 }
1239
1240 table::Term::Literal(model::Literal::Bytes(_)) => {
1241 Err(error_unsupported!("`(bytes ..)` as `TypeArg`"))
1242 }
1243 table::Term::Literal(model::Literal::Float(_)) => {
1244 Err(error_unsupported!("float literal as `TypeArg`"))
1245 }
1246 table::Term::Func { .. } => Err(error_unsupported!("function constant as `TypeArg`")),
1247
1248 table::Term::Apply { .. } => {
1249 let ty = self.import_type(term_id)?;
1250 Ok(TypeArg::Type { ty })
1251 }
1252 }
1253 }
1254
1255 fn import_type<RV: MaybeRV>(
1257 &mut self,
1258 term_id: table::TermId,
1259 ) -> Result<TypeBase<RV>, ImportError> {
1260 if let Some([_, _]) = self.match_symbol(term_id, model::CORE_FN)? {
1261 let func_type = self.import_func_type::<RowVariable>(term_id)?;
1262 return Ok(TypeBase::new_function(func_type));
1263 }
1264
1265 if let Some([variants]) = self.match_symbol(term_id, model::CORE_ADT)? {
1266 let variants = self.import_closed_list(variants)?;
1267 let variants = variants
1268 .iter()
1269 .map(|variant| self.import_type_row::<RowVariable>(*variant))
1270 .collect::<Result<Vec<_>, _>>()?;
1271 return Ok(TypeBase::new_sum(variants));
1272 }
1273
1274 match self.get_term(term_id)? {
1275 table::Term::Wildcard => Err(error_uninferred!("wildcard")),
1276
1277 table::Term::Apply(symbol, args) => {
1278 let args = args
1279 .iter()
1280 .map(|arg| self.import_type_arg(*arg))
1281 .collect::<Result<Vec<_>, _>>()?;
1282
1283 let name = self.get_symbol_name(*symbol)?;
1284 let (extension, id) = self.import_custom_name(name)?;
1285
1286 let extension_ref =
1287 self.extensions
1288 .get(&extension)
1289 .ok_or_else(|| ImportError::Extension {
1290 missing_ext: extension.clone(),
1291 available: self.extensions.ids().cloned().collect(),
1292 })?;
1293
1294 let ext_type =
1295 extension_ref
1296 .get_type(&id)
1297 .ok_or_else(|| ImportError::ExtensionType {
1298 ext: extension.clone(),
1299 name: id.clone(),
1300 })?;
1301
1302 let bound = ext_type.bound(&args);
1303
1304 Ok(TypeBase::new_extension(CustomType::new(
1305 id,
1306 args,
1307 extension,
1308 bound,
1309 &Arc::downgrade(extension_ref),
1310 )))
1311 }
1312
1313 table::Term::Var(table::VarId(_, index)) => {
1314 Ok(TypeBase::new_var_use(*index as _, TypeBound::Copyable))
1315 }
1316
1317 table::Term::List { .. }
1320 | table::Term::Tuple { .. }
1321 | table::Term::Literal(_)
1322 | table::Term::Func { .. } => Err(table::ModelError::TypeError(term_id).into()),
1323 }
1324 }
1325
1326 fn get_func_type(&mut self, term_id: table::TermId) -> Result<[table::TermId; 2], ImportError> {
1327 self.match_symbol(term_id, model::CORE_FN)?
1328 .ok_or(table::ModelError::TypeError(term_id).into())
1329 }
1330
1331 fn import_func_type<RV: MaybeRV>(
1332 &mut self,
1333 term_id: table::TermId,
1334 ) -> Result<FuncTypeBase<RV>, ImportError> {
1335 let [inputs, outputs] = self.get_func_type(term_id)?;
1336 let inputs = self.import_type_row(inputs)?;
1337 let outputs = self.import_type_row(outputs)?;
1338 Ok(FuncTypeBase::new(inputs, outputs))
1339 }
1340
1341 fn import_closed_list(
1342 &mut self,
1343 term_id: table::TermId,
1344 ) -> Result<Vec<table::TermId>, ImportError> {
1345 fn import_into(
1346 ctx: &mut Context,
1347 term_id: table::TermId,
1348 types: &mut Vec<table::TermId>,
1349 ) -> Result<(), ImportError> {
1350 match ctx.get_term(term_id)? {
1351 table::Term::List(parts) => {
1352 types.reserve(parts.len());
1353
1354 for part in *parts {
1355 match part {
1356 table::SeqPart::Item(term_id) => {
1357 types.push(*term_id);
1358 }
1359 table::SeqPart::Splice(term_id) => {
1360 import_into(ctx, *term_id, types)?;
1361 }
1362 }
1363 }
1364 }
1365 _ => return Err(table::ModelError::TypeError(term_id).into()),
1366 }
1367
1368 Ok(())
1369 }
1370
1371 let mut types = Vec::new();
1372 import_into(self, term_id, &mut types)?;
1373 Ok(types)
1374 }
1375
1376 fn import_closed_tuple(
1377 &mut self,
1378 term_id: table::TermId,
1379 ) -> Result<Vec<table::TermId>, ImportError> {
1380 fn import_into(
1381 ctx: &mut Context,
1382 term_id: table::TermId,
1383 types: &mut Vec<table::TermId>,
1384 ) -> Result<(), ImportError> {
1385 match ctx.get_term(term_id)? {
1386 table::Term::Tuple(parts) => {
1387 types.reserve(parts.len());
1388
1389 for part in *parts {
1390 match part {
1391 table::SeqPart::Item(term_id) => {
1392 types.push(*term_id);
1393 }
1394 table::SeqPart::Splice(term_id) => {
1395 import_into(ctx, *term_id, types)?;
1396 }
1397 }
1398 }
1399 }
1400 _ => return Err(table::ModelError::TypeError(term_id).into()),
1401 }
1402
1403 Ok(())
1404 }
1405
1406 let mut types = Vec::new();
1407 import_into(self, term_id, &mut types)?;
1408 Ok(types)
1409 }
1410
1411 fn import_type_rows<RV: MaybeRV>(
1412 &mut self,
1413 term_id: table::TermId,
1414 ) -> Result<Vec<TypeRowBase<RV>>, ImportError> {
1415 self.import_closed_list(term_id)?
1416 .into_iter()
1417 .map(|term_id| self.import_type_row::<RV>(term_id))
1418 .collect()
1419 }
1420
1421 fn import_type_row<RV: MaybeRV>(
1422 &mut self,
1423 term_id: table::TermId,
1424 ) -> Result<TypeRowBase<RV>, ImportError> {
1425 fn import_into<RV: MaybeRV>(
1426 ctx: &mut Context,
1427 term_id: table::TermId,
1428 types: &mut Vec<TypeBase<RV>>,
1429 ) -> Result<(), ImportError> {
1430 match ctx.get_term(term_id)? {
1431 table::Term::List(parts) => {
1432 types.reserve(parts.len());
1433
1434 for item in *parts {
1435 match item {
1436 table::SeqPart::Item(term_id) => {
1437 types.push(ctx.import_type::<RV>(*term_id)?);
1438 }
1439 table::SeqPart::Splice(term_id) => {
1440 import_into(ctx, *term_id, types)?;
1441 }
1442 }
1443 }
1444 }
1445 table::Term::Var(table::VarId(_, index)) => {
1446 let var = RV::try_from_rv(RowVariable(*index as _, TypeBound::Any))
1447 .map_err(|_| table::ModelError::TypeError(term_id))?;
1448 types.push(TypeBase::new(TypeEnum::RowVar(var)));
1449 }
1450 _ => return Err(table::ModelError::TypeError(term_id).into()),
1451 }
1452
1453 Ok(())
1454 }
1455
1456 let mut types = Vec::new();
1457 import_into(self, term_id, &mut types)?;
1458 Ok(types.into())
1459 }
1460
1461 fn import_custom_name(
1462 &mut self,
1463 symbol: &'a str,
1464 ) -> Result<(ExtensionId, SmolStr), ImportError> {
1465 use std::collections::hash_map::Entry;
1466 match self.custom_name_cache.entry(symbol) {
1467 Entry::Occupied(occupied_entry) => Ok(occupied_entry.get().clone()),
1468 Entry::Vacant(vacant_entry) => {
1469 let qualified_name = ExtensionId::new(symbol)
1470 .map_err(|_| table::ModelError::MalformedName(symbol.to_smolstr()))?;
1471
1472 let (extension, id) = qualified_name
1473 .split_last()
1474 .ok_or_else(|| table::ModelError::MalformedName(symbol.to_smolstr()))?;
1475
1476 vacant_entry.insert((extension.clone(), id.clone()));
1477 Ok((extension, id))
1478 }
1479 }
1480 }
1481
1482 fn import_value(
1483 &mut self,
1484 term_id: table::TermId,
1485 type_id: table::TermId,
1486 ) -> Result<Value, ImportError> {
1487 let term_data = self.get_term(term_id)?;
1488
1489 if let Some([runtime_type, json]) = self.match_symbol(term_id, model::COMPAT_CONST_JSON)? {
1493 let table::Term::Literal(model::Literal::Str(json)) = self.get_term(json)? else {
1494 return Err(table::ModelError::TypeError(term_id).into());
1495 };
1496
1497 let value: Option<Box<dyn CustomConst>> = serde_json::from_str(json).ok();
1501
1502 if let Some(value) = value {
1503 let opaque_value = OpaqueValue::from(value);
1504 return Ok(Value::Extension { e: opaque_value });
1505 } else {
1506 let runtime_type = self.import_type(runtime_type)?;
1507 let value: serde_json::Value = serde_json::from_str(json)
1508 .map_err(|_| table::ModelError::TypeError(term_id))?;
1509 let custom_const = CustomSerialized::new(runtime_type, value);
1510 let opaque_value = OpaqueValue::new(custom_const);
1511 return Ok(Value::Extension { e: opaque_value });
1512 }
1513 }
1514
1515 if let Some([_, element_type_term, contents]) =
1516 self.match_symbol(term_id, ArrayValue::CTR_NAME)?
1517 {
1518 let element_type = self.import_type(element_type_term)?;
1519 let contents = self.import_closed_list(contents)?;
1520 let contents = contents
1521 .iter()
1522 .map(|item| self.import_value(*item, element_type_term))
1523 .collect::<Result<Vec<_>, _>>()?;
1524 return Ok(ArrayValue::new(element_type, contents).into());
1525 }
1526
1527 if let Some([bitwidth, value]) = self.match_symbol(term_id, ConstInt::CTR_NAME)? {
1528 let bitwidth = {
1529 let table::Term::Literal(model::Literal::Nat(bitwidth)) =
1530 self.get_term(bitwidth)?
1531 else {
1532 return Err(table::ModelError::TypeError(term_id).into());
1533 };
1534 if *bitwidth > 6 {
1535 return Err(table::ModelError::TypeError(term_id).into());
1536 }
1537 *bitwidth as u8
1538 };
1539
1540 let value = {
1541 let table::Term::Literal(model::Literal::Nat(value)) = self.get_term(value)? else {
1542 return Err(table::ModelError::TypeError(term_id).into());
1543 };
1544 *value
1545 };
1546
1547 return Ok(ConstInt::new_u(bitwidth, value)
1548 .map_err(|_| table::ModelError::TypeError(term_id))?
1549 .into());
1550 }
1551
1552 if let Some([value]) = self.match_symbol(term_id, ConstF64::CTR_NAME)? {
1553 let table::Term::Literal(model::Literal::Float(value)) = self.get_term(value)? else {
1554 return Err(table::ModelError::TypeError(term_id).into());
1555 };
1556
1557 return Ok(ConstF64::new(value.into_inner()).into());
1558 }
1559
1560 if let Some([_, _, tag, values]) = self.match_symbol(term_id, model::CORE_CONST_ADT)? {
1561 let [variants] = self.expect_symbol(type_id, model::CORE_ADT)?;
1562 let values = self.import_closed_tuple(values)?;
1563 let variants = self.import_closed_list(variants)?;
1564
1565 let table::Term::Literal(model::Literal::Nat(tag)) = self.get_term(tag)? else {
1566 return Err(table::ModelError::TypeError(term_id).into());
1567 };
1568
1569 let variant = variants
1570 .get(*tag as usize)
1571 .ok_or(table::ModelError::TypeError(term_id))?;
1572
1573 let variant = self.import_closed_list(*variant)?;
1574
1575 let items = values
1576 .iter()
1577 .zip(variant.iter())
1578 .map(|(value, typ)| self.import_value(*value, *typ))
1579 .collect::<Result<Vec<_>, _>>()?;
1580
1581 let typ = {
1582 let typ: Type = self.import_type(type_id)?;
1584 match typ.as_type_enum() {
1585 TypeEnum::Sum(sum) => sum.clone(),
1586 _ => unreachable!(),
1587 }
1588 };
1589
1590 return Ok(Value::sum(*tag as _, items, typ).unwrap());
1591 }
1592
1593 match term_data {
1594 table::Term::Wildcard => Err(error_uninferred!("wildcard")),
1595 table::Term::Var(_) => Err(error_unsupported!("constant value containing a variable")),
1596
1597 table::Term::Apply(symbol, _) => {
1598 let symbol_name = self.get_symbol_name(*symbol)?;
1599 Err(error_unsupported!(
1600 "unknown custom constant value `{}`",
1601 symbol_name
1602 ))
1603 }
1607
1608 table::Term::List { .. } | table::Term::Tuple(_) | table::Term::Literal(_) => {
1609 Err(table::ModelError::TypeError(term_id).into())
1610 }
1611
1612 table::Term::Func { .. } => Err(error_unsupported!("constant function value")),
1613 }
1614 }
1615
1616 fn match_symbol<const N: usize>(
1617 &self,
1618 term_id: table::TermId,
1619 name: &str,
1620 ) -> Result<Option<[table::TermId; N]>, ImportError> {
1621 let term = self.get_term(term_id)?;
1622
1623 let table::Term::Apply(symbol, args) = term else {
1626 return Ok(None);
1627 };
1628
1629 if name != self.get_symbol_name(*symbol)? {
1630 return Ok(None);
1631 }
1632
1633 Ok((*args).try_into().ok())
1634 }
1635
1636 fn expect_symbol<const N: usize>(
1637 &self,
1638 term_id: table::TermId,
1639 name: &str,
1640 ) -> Result<[table::TermId; N], ImportError> {
1641 self.match_symbol(term_id, name)?
1642 .ok_or(table::ModelError::TypeError(term_id).into())
1643 }
1644}
1645
1646#[derive(Debug, Clone, Copy)]
1648struct LocalVar {
1649 r#type: table::TermId,
1651 bound: TypeBound,
1653}
1654
1655impl LocalVar {
1656 pub fn new(r#type: table::TermId) -> Self {
1657 Self {
1658 r#type,
1659 bound: TypeBound::Any,
1660 }
1661 }
1662}