1use super::arrays::{ArrayShape, array_shape, const_i64};
34use super::real::{real_kind, state_ty, strip_conversions};
35use super::*;
36use crate::constraints::ir::{ArrayNode, Assignment, eval};
37use crate::constraints::real_domain::{FloatKind as Fk, RealExpr};
38use crate::state::storage::{field_slice, storage_width};
39
40#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
42pub enum Step {
43 Index(i64),
45 Field(u32),
47}
48
49#[derive(Clone, Copy, Debug, PartialEq, Eq)]
51pub enum Declared {
52 Int(u32),
54 Real(u32),
56 Array(u32),
60}
61
62#[derive(Clone, Copy)]
64pub(super) enum RawStep<'d> {
65 Index(Expression<'d>),
67 Const(i64),
69 Field(u32),
71}
72
73#[derive(Clone)]
75pub(super) struct Chain<'d> {
76 pub root: Symbol<'d>,
78 pub steps: Vec<RawStep<'d>>,
81}
82
83pub(super) fn aggregate_chain<'d>(
87 e: Expression<'d>,
88 forced: &HashSet<SymbolId>,
89) -> Option<Chain<'d>> {
90 let e = strip_conversions(e);
91 let kind = e.kind();
92 if kind == ExpressionKind::NamedValue {
94 let sym = e.referenced_symbol()?;
95 return (sym.kind() == SymbolKind::ClassProperty || forced.contains(&sym.uid())).then(
96 || Chain {
97 root: sym,
98 steps: Vec::new(),
99 },
100 );
101 }
102 if kind == ExpressionKind::MemberAccess {
103 let base = e.left()?;
104 let member = e.member_symbol()?;
105 let is_this = strip_conversions(base).kind() == ExpressionKind::NamedValue
106 && strip_conversions(base)
107 .referenced_symbol()
108 .is_some_and(|s| s.name() == "this");
109 if is_this {
110 return (member.kind() == SymbolKind::ClassProperty).then(|| Chain {
111 root: member,
112 steps: Vec::new(),
113 });
114 }
115 let bt = base.expr_type()?.canonical();
116 if !bt.is_unpacked_struct() {
117 return None;
118 }
119 let index = bt.fields().position(|f| f.name() == member.name())?;
120 let mut chain = aggregate_chain(base, forced)?;
121 chain.steps.push(RawStep::Field(u32::try_from(index).ok()?));
122 return Some(chain);
123 }
124 if kind == ExpressionKind::ElementSelect {
125 let base = e.select_value()?;
126 if array_shape(base.expr_type()?) != Some(ArrayShape::Fixed) {
127 return None;
128 }
129 let mut chain = aggregate_chain(base, forced)?;
130 chain.steps.push(RawStep::Index(e.selector()?));
131 return Some(chain);
132 }
133 None
134}
135
136pub fn is_aggregate_type(t: Type<'_>) -> bool {
139 let c = t.canonical();
140 c.is_unpacked_struct() || array_shape(c) == Some(ArrayShape::Fixed)
141}
142
143pub fn property_is_random(sym: Symbol<'_>) -> bool {
149 if sym.rand_mode() != RandMode::None {
150 return true;
151 }
152 sym.value_type().is_some_and(has_random_member)
153}
154
155fn has_random_member(t: Type<'_>) -> bool {
156 let c = t.canonical();
157 if c.is_unpacked_struct() {
158 return c.fields().any(|f| {
159 f.field_rand_mode() != RandMode::None || f.value_type().is_some_and(has_random_member)
160 });
161 }
162 array_shape(c) == Some(ArrayShape::Fixed) && c.element_type().is_some_and(has_random_member)
163}
164
165#[derive(Clone, Copy, Debug)]
167pub(super) enum LeafKind {
168 Int(Ty),
170 Real(Fk),
172 Vif,
174 Skipped,
176 Collection,
178 Other,
180}
181
182#[derive(Clone)]
184pub(super) struct LeafRef<'d> {
185 pub root: SymbolId,
187 pub name: String,
189 pub path: Vec<Step>,
191 pub window: Window,
193 pub mode: RandMode,
195 pub kind: LeafKind,
197 pub vt: Type<'d>,
199}
200
201impl LeafRef<'_> {
202 pub(super) fn randc(&self) -> bool {
203 self.mode == RandMode::RandC
204 }
205}
206
207pub(super) enum Sel<'d> {
209 Leaf(LeafRef<'d>),
210 Pick {
211 index: Expr,
212 low: i64,
213 elems: Vec<Sel<'d>>,
214 },
215}
216
217#[derive(Clone)]
219struct Cursor<'d> {
220 root: SymbolId,
221 whole: u64,
223 ty: Type<'d>,
224 mode: RandMode,
225 path: Vec<Step>,
226 name: String,
227 bit: u64,
229}
230
231fn missing(what: impl Into<String>) -> BuildError {
232 BuildError::Missing { what: what.into() }
233}
234
235impl<'d> Cursor<'d> {
236 fn of(root: Symbol<'d>) -> Result<Cursor<'d>, BuildError> {
237 let ty = root
238 .value_type()
239 .ok_or_else(|| missing(format!("value type for `{}`", root.name())))?;
240 let whole = storage_width(&ty).ok_or_else(|| {
241 missing(format!(
242 "stored width of `{}` of type `{}`",
243 root.name(),
244 ty.to_sv_string()
245 ))
246 })?;
247 Ok(Cursor {
248 root: root.uid(),
249 whole,
250 ty,
251 mode: root.rand_mode(),
252 path: Vec::new(),
253 name: root.name().to_string(),
254 bit: 0,
255 })
256 }
257
258 fn field(&self, i: u32) -> Result<Cursor<'d>, BuildError> {
260 let t = self.ty.canonical();
261 if !t.is_unpacked_struct() {
262 return Err(missing(format!(
263 "`{}` is not an unpacked struct",
264 self.name
265 )));
266 }
267 let f = t
268 .fields()
269 .nth(i as usize)
270 .ok_or_else(|| missing(format!("member {i} of `{}`", self.name)))?;
271 let (lsb, _) = field_slice(&t, i)
272 .ok_or_else(|| missing(format!("stored position of member {i} of `{}`", self.name)))?;
273 let ty = f
274 .value_type()
275 .ok_or_else(|| missing(format!("type of `{}.{}`", self.name, f.name())))?;
276 let mut path = self.path.clone();
277 path.push(Step::Field(i));
278 Ok(Cursor {
279 root: self.root.clone(),
280 whole: self.whole,
281 ty,
282 mode: match f.field_rand_mode() {
284 RandMode::None => self.mode,
285 own => own,
286 },
287 path,
288 name: format!("{}.{}", self.name, f.name()),
289 bit: self.bit + lsb,
290 })
291 }
292
293 fn dim(&self) -> Result<(i64, i64, Type<'d>), BuildError> {
296 let t = self.ty.canonical();
297 match array_shape(t) {
298 Some(ArrayShape::Fixed) => {}
299 Some(ArrayShape::Collection | ArrayShape::Assoc) => {
300 return Err(unsupported(
301 format!(
302 "`{}`, whose size is only known at run time (a dynamic array, queue or \
303 associative array), as an element of an aggregate",
304 self.name
305 ),
306 "C14",
307 ));
308 }
309 None => {
310 return Err(BuildError::OutOfRangeSelect {
311 what: format!("`{}` is not an array, so it has no elements", self.name),
312 });
313 }
314 }
315 let r = t.fixed_unpacked_array_range();
316 let elem = t
317 .element_type()
318 .ok_or_else(|| missing(format!("element type of the array `{}`", self.name)))?;
319 Ok((
320 i64::from(r.left).min(i64::from(r.right)),
321 i64::from(r.left).max(i64::from(r.right)),
322 elem,
323 ))
324 }
325
326 fn index(&self, i: i64) -> Result<Cursor<'d>, BuildError> {
328 let (lo, hi, elem) = self.dim()?;
329 if !(lo..=hi).contains(&i) {
330 let r = self.ty.canonical().fixed_unpacked_array_range();
331 return Err(BuildError::OutOfRangeSelect {
332 what: format!("`{}` index {i} outside [{}:{}]", self.name, r.left, r.right),
333 });
334 }
335 let ew = storage_width(&elem)
336 .ok_or_else(|| missing(format!("stored width of an element of `{}`", self.name)))?;
337 let mut path = self.path.clone();
338 path.push(Step::Index(i));
339 Ok(Cursor {
340 root: self.root.clone(),
341 whole: self.whole,
342 ty: elem,
343 mode: self.mode,
344 path,
345 name: format!("{}[{i}]", self.name),
346 bit: self.bit + (i - lo) as u64 * ew,
347 })
348 }
349
350 fn leaf(self) -> Result<LeafRef<'d>, BuildError> {
351 let width = storage_width(&self.ty)
352 .ok_or_else(|| missing(format!("stored width of `{}`", self.name)))?;
353 let narrow = |v: u64| {
354 u32::try_from(v).map_err(|_| {
355 missing(format!(
356 "a window of `{}` within 32-bit offsets (the property is {} bits)",
357 self.name, self.whole
358 ))
359 })
360 };
361 let window = Window {
362 bit: narrow(self.bit)?,
363 width: narrow(width)?,
364 field_width: narrow(self.whole)?,
365 };
366 let c = self.ty.canonical();
367 let kind = if let Some(k) = real_kind(Some(self.ty)) {
368 LeafKind::Real(k)
369 } else if c.is_virtual_interface() {
370 LeafKind::Vif
371 } else if c.is_integral() {
372 LeafKind::Int(ty_of(Some(self.ty), &format!("`{}`", self.name))?)
373 } else if c.is_string() || c.is_chandle() {
374 LeafKind::Skipped
375 } else if array_shape(c) == Some(ArrayShape::Collection) {
376 LeafKind::Collection
377 } else {
378 LeafKind::Other
379 };
380 Ok(LeafRef {
381 root: self.root,
382 name: self.name,
383 path: self.path,
384 window,
385 mode: self.mode,
386 kind,
387 vt: self.ty,
388 })
389 }
390
391 fn random_leaves(self, out: &mut Vec<LeafRef<'d>>) -> Result<(), BuildError> {
393 let t = self.ty.canonical();
394 if t.is_unpacked_struct() {
395 for i in 0..t.fields().count() {
396 self.field(i as u32)?.random_leaves(out)?;
397 }
398 return Ok(());
399 }
400 if array_shape(t) == Some(ArrayShape::Fixed) {
401 let (lo, hi, _) = self.dim()?;
402 for i in lo..=hi {
403 self.index(i)?.random_leaves(out)?;
404 }
405 return Ok(());
406 }
407 if self.mode == RandMode::None || t.is_unpacked_union() {
408 return Ok(());
409 }
410 let leaf = self.leaf()?;
411 match leaf.kind {
412 LeafKind::Int(_) | LeafKind::Real(_) | LeafKind::Collection => out.push(leaf),
413 LeafKind::Skipped => {}
414 LeafKind::Vif => return Err(BuildError::VirtualInterfaceRand { name: leaf.name }),
415 LeafKind::Other => {
416 return Err(unsupported(
417 format!(
418 "the random member `{}` of type `{}` inside an unpacked struct or array \
419 (a class handle or associative array nested in a flat aggregate cannot \
420 be randomized)",
421 leaf.name,
422 leaf.vt.to_sv_string()
423 ),
424 "C14",
425 ));
426 }
427 }
428 Ok(())
429 }
430}
431
432impl Builder<'_> {
433 fn cursor_of<'d>(&self, sym: Symbol<'d>) -> Result<Cursor<'d>, BuildError> {
436 let mut cur = Cursor::of(sym)?;
437 if self.forced_roots.contains(&cur.root) {
438 cur.mode = RandMode::Rand;
439 }
440 Ok(cur)
441 }
442
443 pub fn declare_aggregate_forced(
451 &mut self,
452 sym: Symbol<'_>,
453 ) -> Result<Vec<Declared>, BuildError> {
454 self.forced_roots.insert(sym.uid());
455 self.declare_rand_aggregate(sym)
456 }
457
458 pub fn declare_rand_aggregate(&mut self, sym: Symbol<'_>) -> Result<Vec<Declared>, BuildError> {
463 let cur = self.cursor_of(sym)?;
464 if !is_aggregate_type(cur.ty) {
465 return Err(missing(format!(
466 "an unpacked struct or fixed-size array type for `{}` (use `declare_rand`)",
467 sym.name()
468 )));
469 }
470 let mut leaves = Vec::new();
471 cur.random_leaves(&mut leaves)?;
472 leaves.iter().map(|l| self.declare_leaf(l)).collect()
473 }
474
475 pub fn declare_rand_element(
479 &mut self,
480 array: Symbol<'_>,
481 idx: &[i64],
482 ) -> Result<u32, BuildError> {
483 let mut cur = Cursor::of(array)?;
484 for &i in idx {
485 cur = cur.index(i)?;
486 }
487 if is_aggregate_type(cur.ty) {
488 return Err(BuildError::OutOfRangeSelect {
489 what: format!(
490 "`{}` is still an aggregate: name one index per unpacked dimension",
491 cur.name
492 ),
493 });
494 }
495 if cur.mode == RandMode::None {
496 return Err(BuildError::NotRand { name: cur.name });
497 }
498 if idx.is_empty() {
499 return Err(BuildError::OutOfRangeSelect {
500 what: format!(
501 "`{}` is not an array element (use `declare_rand`)",
502 cur.name
503 ),
504 });
505 }
506 let leaf = cur.leaf()?;
507 match self.declare_leaf(&leaf)? {
508 Declared::Int(id) => Ok(id),
509 Declared::Real(_) => Err(BuildError::RealConstraint {
510 what: format!(
511 "`{}` is real: it is a real random variable, not an integral element",
512 leaf.name
513 ),
514 }),
515 Declared::Array(_) => Err(BuildError::NonIntegral {
516 what: format!("`{}` is an array, not an integral element", leaf.name),
517 }),
518 }
519 }
520
521 pub(super) fn leaf_tag(path: &[Step]) -> String {
523 let mut t = String::from("leaf");
524 for st in path {
525 match st {
526 Step::Index(i) => t.push_str(&format!("[{i}]")),
527 Step::Field(f) => t.push_str(&format!(".{f}")),
528 }
529 }
530 t
531 }
532
533 pub(super) fn new_leaf_array(
536 &mut self,
537 leaf: &LeafRef<'_>,
538 rand: bool,
539 ) -> Result<u32, BuildError> {
540 let mut info = self.array_info(leaf.root.clone(), leaf.name.clone(), leaf.vt, rand)?;
541 if info.nested {
542 return Err(unsupported(
543 format!(
544 "`{}`: an array of arrays as an element or member of an aggregate",
545 leaf.name
546 ),
547 "C14",
548 ));
549 }
550 info.window = Some(leaf.window);
551 let id = self.arrays.len() as u32;
552 self.arrays.push(info);
553 Ok(id)
554 }
555
556 fn declare_leaf(&mut self, leaf: &LeafRef<'_>) -> Result<Declared, BuildError> {
558 let key = (leaf.root.clone(), leaf.path.clone());
559 match leaf.kind {
560 LeafKind::Int(_) => {
561 if let Some(&id) = self.elem_ix.get(&key) {
562 return Ok(Declared::Int(id));
563 }
564 let id = self.new_rand_var(
565 leaf.root.clone(),
566 leaf.name.clone(),
567 leaf.vt,
568 leaf.randc(),
569 leaf.path.clone(),
570 Some(leaf.window),
571 )?;
572 self.elem_ix.insert(key, id);
573 Ok(Declared::Int(id))
574 }
575 LeafKind::Real(kind) => {
576 if let Some(&id) = self.real_leaf_ix.get(&key) {
577 return Ok(Declared::Real(id));
578 }
579 if leaf.randc() {
580 return Err(BuildError::RealConstraint {
581 what: format!(
582 "`randc` variable `{}` is real; `randc` is for integral types only \
583 (IEEE 1800-2023 18.4.2)",
584 leaf.name
585 ),
586 });
587 }
588 let id = self.real_vars.len() as u32;
589 self.real_vars.push(RealVarInfo {
590 symbol: leaf.root.clone(),
591 name: leaf.name.clone(),
592 kind,
593 window: Some(leaf.window),
594 });
595 self.real_leaf_ix.insert(key, id);
596 Ok(Declared::Real(id))
597 }
598 LeafKind::Collection => {
599 let key = leaf.root.derive(&Self::leaf_tag(&leaf.path));
600 if let Some(&id) = self.array_ix.get(&key) {
601 return Ok(Declared::Array(id));
602 }
603 if leaf.randc() {
604 return Err(unsupported(
605 format!("the `randc` array `{}`: per-element cycling", leaf.name),
606 "C14",
607 ));
608 }
609 let id = self.new_leaf_array(leaf, true)?;
610 self.array_ix.insert(key, id);
611 Ok(Declared::Array(id))
612 }
613 LeafKind::Vif | LeafKind::Skipped | LeafKind::Other => Err(missing(format!(
614 "a randomizable value for `{}` of type `{}`",
615 leaf.name,
616 leaf.vt.to_sv_string()
617 ))),
618 }
619 }
620
621 pub(super) fn resolve_chain<'d>(&mut self, chain: &Chain<'d>) -> Result<Sel<'d>, BuildError> {
624 let cur = self.cursor_of(chain.root)?;
625 self.walk(cur, &chain.steps)
626 }
627
628 fn walk<'d>(&mut self, cur: Cursor<'d>, steps: &[RawStep<'d>]) -> Result<Sel<'d>, BuildError> {
629 let Some((first, rest)) = steps.split_first() else {
630 return Ok(Sel::Leaf(cur.leaf()?));
631 };
632 match *first {
633 RawStep::Field(i) => self.walk(cur.field(i)?, rest),
634 RawStep::Const(i) => self.walk(cur.index(i)?, rest),
635 RawStep::Index(e) => {
636 let ix = self.expr(e)?;
637 if let Some(i) = Self::constant_index(&ix) {
638 let (lo, hi, _) = cur.dim()?;
639 if (lo..=hi).contains(&i) {
640 return self.walk(cur.index(i)?, rest);
641 }
642 }
643 self.not_in_function(
644 "an element of an unpacked array property at a computed index",
645 )?;
646 self.arrays_allowed("an element of an unpacked array property")?;
647 let mut has_var = false;
648 ix.for_each_var(&mut |_, _| has_var = true);
649 if has_var {
650 return Err(BuildError::BadArray {
651 what: format!(
652 "a random variable in the index of the array `{}`: an index is a \
653 constant, a state variable, a loop variable or the size (IEEE \
654 1800-2023 18.5.7.1)",
655 cur.name
656 ),
657 });
658 }
659 let (lo, hi, _) = cur.dim()?;
663 let mut elems = Vec::new();
664 for i in lo..=hi {
665 elems.push(self.walk(cur.index(i)?, rest)?);
666 }
667 Ok(Sel::Pick {
668 index: ix,
669 low: lo,
670 elems,
671 })
672 }
673 }
674 }
675
676 pub(super) fn constant_index(ix: &Expr) -> Option<i64> {
678 if ix.any_node(&mut |n| matches!(n, Expr::Var(..) | Expr::State(..) | Expr::Array(_))) {
679 return None;
680 }
681 let v = eval(ix, &Assignment::default()).ok()?;
682 const_i64(ix.ty(), &v)
683 }
684
685 pub(super) fn declared_leaf<'d>(
688 &mut self,
689 chain: Chain<'d>,
690 what: &str,
691 ) -> Result<(LeafRef<'d>, Option<Declared>), BuildError> {
692 let Sel::Leaf(leaf) = self.resolve_chain(&chain)? else {
693 return Err(unsupported(
694 format!("{what} that selects an element at a computed index"),
695 "C14",
696 ));
697 };
698 let key = (leaf.root.clone(), leaf.path.clone());
699 let declared = match leaf.kind {
700 LeafKind::Int(_) => self.elem_ix.get(&key).map(|&id| Declared::Int(id)),
701 LeafKind::Real(_) => self.real_leaf_ix.get(&key).map(|&id| Declared::Real(id)),
702 LeafKind::Vif | LeafKind::Skipped | LeafKind::Collection | LeafKind::Other => {
703 return Err(BuildError::NonIntegral {
704 what: format!("`{}` of type `{}`", leaf.name, leaf.vt.to_sv_string()),
705 });
706 }
707 };
708 Ok((leaf, declared))
709 }
710
711 fn undeclared(leaf: &LeafRef<'_>) -> BuildError {
713 unsupported(
714 format!(
715 "the random variable `{}`, a leaf of an aggregate property that was not declared \
716 random (`declare_rand_aggregate`)",
717 leaf.name
718 ),
719 "C14",
720 )
721 }
722
723 fn leaf_state(&mut self, leaf: &LeafRef<'_>, ty: Ty) -> Expr {
725 let key = (leaf.root.clone(), leaf.path.clone());
726 if let Some(&id) = self.leaf_state_ix.get(&key) {
727 return Expr::State(id, self.states[id as usize].ty);
728 }
729 let id = self.states.len() as u32;
730 self.states.push(StateInfo {
731 root_bit: 0,
732 symbol: leaf.root.clone(),
733 name: leaf.name.clone(),
734 ty,
735 via: Vec::new(),
736 window: Some(leaf.window),
737 class_of: false,
738 });
739 self.leaf_state_ix.insert(key, id);
740 Expr::State(id, ty)
741 }
742
743 fn leaf_expr(&mut self, leaf: &LeafRef<'_>) -> Result<Expr, BuildError> {
745 let LeafKind::Int(ty) = leaf.kind else {
746 return Err(BuildError::NonIntegral {
747 what: format!("`{}` of type `{}`", leaf.name, leaf.vt.to_sv_string()),
748 });
749 };
750 if leaf.mode == RandMode::None {
751 return Ok(self.leaf_state(leaf, ty));
752 }
753 let key = (leaf.root.clone(), leaf.path.clone());
754 let &id = self
755 .elem_ix
756 .get(&key)
757 .ok_or_else(|| Self::undeclared(leaf))?;
758 if self.frame.is_some() {
759 return Err(self.rand_read_in_function(&leaf.name));
760 }
761 Ok(Expr::Var(id, self.vars[id as usize].ty))
762 }
763
764 fn sel_expr(&mut self, sel: Sel<'_>, ty: Ty) -> Result<Expr, BuildError> {
765 match sel {
766 Sel::Leaf(leaf) => {
767 let x = self.leaf_expr(&leaf)?;
768 Ok(if x.ty() == ty {
769 x
770 } else {
771 Expr::Resize(Box::new(x), ty)
772 })
773 }
774 Sel::Pick { index, low, elems } => {
775 let elems = elems
776 .into_iter()
777 .map(|s| self.sel_expr(s, ty))
778 .collect::<Result<Vec<_>, _>>()?;
779 Ok(Expr::Array(ArrayNode::Pick {
780 index: Box::new(index),
781 low,
782 elems,
783 ty,
784 }))
785 }
786 }
787 }
788
789 pub(super) fn aggregate_value(&mut self, chain: Chain<'_>, ty: Ty) -> Result<Expr, BuildError> {
791 let sel = self.resolve_chain(&chain)?;
792 self.sel_expr(sel, ty)
793 }
794
795 pub(super) fn aggregate_bitstream(&mut self, chain: Chain<'_>) -> Result<Expr, BuildError> {
800 let mut parts = Vec::new();
801 let mut cur = self.cursor_of(chain.root)?;
802 let mut rest: &[RawStep<'_>] = &chain.steps;
805 while let Some((first, tail)) = rest.split_first() {
806 cur = match *first {
807 RawStep::Field(i) => cur.field(i)?,
808 RawStep::Const(i) => cur.index(i)?,
809 RawStep::Index(e) => {
810 let ix = self.expr(e)?;
811 let i = Self::constant_index(&ix).ok_or_else(|| {
812 unsupported("a bit-stream cast of an element at a computed index", "C2")
813 })?;
814 cur.index(i)?
815 }
816 };
817 rest = tail;
818 }
819 self.stream_leaves(cur, &mut parts)?;
820 let w = parts.iter().map(|p| p.ty().width).sum();
821 Ok(Expr::Concat(parts, Ty::unsigned(w)))
822 }
823
824 fn stream_leaves(&mut self, cur: Cursor<'_>, out: &mut Vec<Expr>) -> Result<(), BuildError> {
825 let t = cur.ty.canonical();
826 if t.is_unpacked_struct() {
827 for i in 0..t.fields().count() {
828 self.stream_leaves(cur.field(i as u32)?, out)?;
829 }
830 } else if array_shape(t) == Some(ArrayShape::Fixed) {
831 let r = t.fixed_unpacked_array_range();
832 let (l, h) = (i64::from(r.left), i64::from(r.right));
833 let idx: Vec<i64> = if l <= h {
834 (l..=h).collect()
835 } else {
836 (h..=l).rev().collect()
837 };
838 for i in idx {
839 self.stream_leaves(cur.index(i)?, out)?;
840 }
841 } else {
842 let leaf = cur.leaf()?;
843 let LeafKind::Int(ty) = leaf.kind else {
844 return Err(BuildError::NonIntegral {
845 what: format!(
846 "`{}` of type `{}` in a bit-stream cast",
847 leaf.name,
848 leaf.vt.to_sv_string()
849 ),
850 });
851 };
852 let x = self.leaf_expr(&leaf)?;
853 out.push(Expr::Resize(Box::new(x), Ty::unsigned(ty.width)));
854 }
855 Ok(())
856 }
857
858 pub(super) fn aggregate_element(
861 &mut self,
862 arr: Expression<'_>,
863 i: i64,
864 ty: Ty,
865 ) -> Result<Expr, BuildError> {
866 let mut chain = aggregate_chain(arr, &self.forced_roots).ok_or_else(|| {
867 unsupported(
868 "a method over an unpacked array that is not a property (or a member of a struct \
869 property) of this class",
870 "C14",
871 )
872 })?;
873 chain.steps.push(RawStep::Const(i));
874 self.aggregate_value(chain, ty)
875 }
876
877 pub(super) fn real_aggregate(
879 &mut self,
880 chain: Chain<'_>,
881 kind: Fk,
882 ) -> Result<RealExpr, BuildError> {
883 let leaf = match self.resolve_chain(&chain)? {
884 Sel::Leaf(leaf) => leaf,
885 Sel::Pick { .. } => {
886 return Err(BuildError::RealConstraint {
887 what: "a real element of an array at a computed index (only an integral \
888 element can be chosen by a state or loop variable)"
889 .into(),
890 });
891 }
892 };
893 if !matches!(leaf.kind, LeafKind::Real(_)) {
894 return Err(missing(format!("a real value for `{}`", leaf.name)));
895 }
896 if leaf.mode == RandMode::None {
897 let st = self.leaf_state(&leaf, state_ty(kind));
898 return self.real_state(st, kind);
899 }
900 let key = (leaf.root.clone(), leaf.path.clone());
901 let &id = self
902 .real_leaf_ix
903 .get(&key)
904 .ok_or_else(|| Self::undeclared(&leaf))?;
905 Ok(RealExpr::Var(id))
906 }
907}