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 info.window = Some(leaf.window);
542 let id = self.arrays.len() as u32;
543 self.arrays.push(info);
544 Ok(id)
545 }
546
547 fn declare_leaf(&mut self, leaf: &LeafRef<'_>) -> Result<Declared, BuildError> {
549 let key = (leaf.root.clone(), leaf.path.clone());
550 match leaf.kind {
551 LeafKind::Int(_) => {
552 if let Some(&id) = self.elem_ix.get(&key) {
553 return Ok(Declared::Int(id));
554 }
555 let id = self.new_rand_var(
556 leaf.root.clone(),
557 leaf.name.clone(),
558 leaf.vt,
559 leaf.randc(),
560 leaf.path.clone(),
561 Some(leaf.window),
562 )?;
563 self.elem_ix.insert(key, id);
564 Ok(Declared::Int(id))
565 }
566 LeafKind::Real(kind) => {
567 if let Some(&id) = self.real_leaf_ix.get(&key) {
568 return Ok(Declared::Real(id));
569 }
570 if leaf.randc() {
571 return Err(BuildError::RealConstraint {
572 what: format!(
573 "`randc` variable `{}` is real; `randc` is for integral types only \
574 (IEEE 1800-2023 18.4.2)",
575 leaf.name
576 ),
577 });
578 }
579 let id = self.real_vars.len() as u32;
580 self.real_vars.push(RealVarInfo {
581 symbol: leaf.root.clone(),
582 name: leaf.name.clone(),
583 kind,
584 window: Some(leaf.window),
585 });
586 self.real_leaf_ix.insert(key, id);
587 Ok(Declared::Real(id))
588 }
589 LeafKind::Collection => {
590 let key = leaf.root.derive(&Self::leaf_tag(&leaf.path));
591 if let Some(&id) = self.array_ix.get(&key) {
592 return Ok(Declared::Array(id));
593 }
594 if leaf.randc() {
595 return Err(unsupported(
596 format!("the `randc` array `{}`: per-element cycling", leaf.name),
597 "C14",
598 ));
599 }
600 let id = self.new_leaf_array(leaf, true)?;
601 self.array_ix.insert(key, id);
602 Ok(Declared::Array(id))
603 }
604 LeafKind::Vif | LeafKind::Skipped | LeafKind::Other => Err(missing(format!(
605 "a randomizable value for `{}` of type `{}`",
606 leaf.name,
607 leaf.vt.to_sv_string()
608 ))),
609 }
610 }
611
612 pub(super) fn resolve_chain<'d>(&mut self, chain: &Chain<'d>) -> Result<Sel<'d>, BuildError> {
615 let cur = self.cursor_of(chain.root)?;
616 self.walk(cur, &chain.steps)
617 }
618
619 fn walk<'d>(&mut self, cur: Cursor<'d>, steps: &[RawStep<'d>]) -> Result<Sel<'d>, BuildError> {
620 let Some((first, rest)) = steps.split_first() else {
621 return Ok(Sel::Leaf(cur.leaf()?));
622 };
623 match *first {
624 RawStep::Field(i) => self.walk(cur.field(i)?, rest),
625 RawStep::Const(i) => self.walk(cur.index(i)?, rest),
626 RawStep::Index(e) => {
627 let ix = self.expr(e)?;
628 if let Some(i) = Self::constant_index(&ix) {
629 let (lo, hi, _) = cur.dim()?;
630 if (lo..=hi).contains(&i) {
631 return self.walk(cur.index(i)?, rest);
632 }
633 }
634 self.not_in_function(
635 "an element of an unpacked array property at a computed index",
636 )?;
637 self.arrays_allowed("an element of an unpacked array property")?;
638 let mut has_var = false;
639 ix.for_each_var(&mut |_, _| has_var = true);
640 if has_var {
641 return Err(BuildError::BadArray {
642 what: format!(
643 "a random variable in the index of the array `{}`: an index is a \
644 constant, a state variable, a loop variable or the size (IEEE \
645 1800-2023 18.5.7.1)",
646 cur.name
647 ),
648 });
649 }
650 let (lo, hi, _) = cur.dim()?;
654 let mut elems = Vec::new();
655 for i in lo..=hi {
656 elems.push(self.walk(cur.index(i)?, rest)?);
657 }
658 Ok(Sel::Pick {
659 index: ix,
660 low: lo,
661 elems,
662 })
663 }
664 }
665 }
666
667 pub(super) fn constant_index(ix: &Expr) -> Option<i64> {
669 if ix.any_node(&mut |n| matches!(n, Expr::Var(..) | Expr::State(..) | Expr::Array(_))) {
670 return None;
671 }
672 let v = eval(ix, &Assignment::default()).ok()?;
673 const_i64(ix.ty(), &v)
674 }
675
676 pub(super) fn declared_leaf<'d>(
679 &mut self,
680 chain: Chain<'d>,
681 what: &str,
682 ) -> Result<(LeafRef<'d>, Option<Declared>), BuildError> {
683 let Sel::Leaf(leaf) = self.resolve_chain(&chain)? else {
684 return Err(unsupported(
685 format!("{what} that selects an element at a computed index"),
686 "C14",
687 ));
688 };
689 let key = (leaf.root.clone(), leaf.path.clone());
690 let declared = match leaf.kind {
691 LeafKind::Int(_) => self.elem_ix.get(&key).map(|&id| Declared::Int(id)),
692 LeafKind::Real(_) => self.real_leaf_ix.get(&key).map(|&id| Declared::Real(id)),
693 LeafKind::Vif | LeafKind::Skipped | LeafKind::Collection | LeafKind::Other => {
694 return Err(BuildError::NonIntegral {
695 what: format!("`{}` of type `{}`", leaf.name, leaf.vt.to_sv_string()),
696 });
697 }
698 };
699 Ok((leaf, declared))
700 }
701
702 fn undeclared(leaf: &LeafRef<'_>) -> BuildError {
704 unsupported(
705 format!(
706 "the random variable `{}`, a leaf of an aggregate property that was not declared \
707 random (`declare_rand_aggregate`)",
708 leaf.name
709 ),
710 "C14",
711 )
712 }
713
714 fn leaf_state(&mut self, leaf: &LeafRef<'_>, ty: Ty) -> Expr {
716 let key = (leaf.root.clone(), leaf.path.clone());
717 if let Some(&id) = self.leaf_state_ix.get(&key) {
718 return Expr::State(id, self.states[id as usize].ty);
719 }
720 let id = self.states.len() as u32;
721 self.states.push(StateInfo {
722 root_bit: 0,
723 symbol: leaf.root.clone(),
724 name: leaf.name.clone(),
725 ty,
726 via: Vec::new(),
727 window: Some(leaf.window),
728 class_of: false,
729 });
730 self.leaf_state_ix.insert(key, id);
731 Expr::State(id, ty)
732 }
733
734 fn leaf_expr(&mut self, leaf: &LeafRef<'_>) -> Result<Expr, BuildError> {
736 let LeafKind::Int(ty) = leaf.kind else {
737 return Err(BuildError::NonIntegral {
738 what: format!("`{}` of type `{}`", leaf.name, leaf.vt.to_sv_string()),
739 });
740 };
741 if leaf.mode == RandMode::None {
742 return Ok(self.leaf_state(leaf, ty));
743 }
744 let key = (leaf.root.clone(), leaf.path.clone());
745 let &id = self
746 .elem_ix
747 .get(&key)
748 .ok_or_else(|| Self::undeclared(leaf))?;
749 if self.frame.is_some() {
750 return Err(self.rand_read_in_function(&leaf.name));
751 }
752 Ok(Expr::Var(id, self.vars[id as usize].ty))
753 }
754
755 fn sel_expr(&mut self, sel: Sel<'_>, ty: Ty) -> Result<Expr, BuildError> {
756 match sel {
757 Sel::Leaf(leaf) => {
758 let x = self.leaf_expr(&leaf)?;
759 Ok(if x.ty() == ty {
760 x
761 } else {
762 Expr::Resize(Box::new(x), ty)
763 })
764 }
765 Sel::Pick { index, low, elems } => {
766 let elems = elems
767 .into_iter()
768 .map(|s| self.sel_expr(s, ty))
769 .collect::<Result<Vec<_>, _>>()?;
770 Ok(Expr::Array(ArrayNode::Pick {
771 index: Box::new(index),
772 low,
773 elems,
774 ty,
775 }))
776 }
777 }
778 }
779
780 pub(super) fn aggregate_value(&mut self, chain: Chain<'_>, ty: Ty) -> Result<Expr, BuildError> {
782 let sel = self.resolve_chain(&chain)?;
783 self.sel_expr(sel, ty)
784 }
785
786 pub(super) fn aggregate_bitstream(&mut self, chain: Chain<'_>) -> Result<Expr, BuildError> {
791 let mut parts = Vec::new();
792 let mut cur = self.cursor_of(chain.root)?;
793 let mut rest: &[RawStep<'_>] = &chain.steps;
796 while let Some((first, tail)) = rest.split_first() {
797 cur = match *first {
798 RawStep::Field(i) => cur.field(i)?,
799 RawStep::Const(i) => cur.index(i)?,
800 RawStep::Index(e) => {
801 let ix = self.expr(e)?;
802 let i = Self::constant_index(&ix).ok_or_else(|| {
803 unsupported("a bit-stream cast of an element at a computed index", "C2")
804 })?;
805 cur.index(i)?
806 }
807 };
808 rest = tail;
809 }
810 self.stream_leaves(cur, &mut parts)?;
811 let w = parts.iter().map(|p| p.ty().width).sum();
812 Ok(Expr::Concat(parts, Ty::unsigned(w)))
813 }
814
815 fn stream_leaves(&mut self, cur: Cursor<'_>, out: &mut Vec<Expr>) -> Result<(), BuildError> {
816 let t = cur.ty.canonical();
817 if t.is_unpacked_struct() {
818 for i in 0..t.fields().count() {
819 self.stream_leaves(cur.field(i as u32)?, out)?;
820 }
821 } else if array_shape(t) == Some(ArrayShape::Fixed) {
822 let r = t.fixed_unpacked_array_range();
823 let (l, h) = (i64::from(r.left), i64::from(r.right));
824 let idx: Vec<i64> = if l <= h {
825 (l..=h).collect()
826 } else {
827 (h..=l).rev().collect()
828 };
829 for i in idx {
830 self.stream_leaves(cur.index(i)?, out)?;
831 }
832 } else {
833 let leaf = cur.leaf()?;
834 let LeafKind::Int(ty) = leaf.kind else {
835 return Err(BuildError::NonIntegral {
836 what: format!(
837 "`{}` of type `{}` in a bit-stream cast",
838 leaf.name,
839 leaf.vt.to_sv_string()
840 ),
841 });
842 };
843 let x = self.leaf_expr(&leaf)?;
844 out.push(Expr::Resize(Box::new(x), Ty::unsigned(ty.width)));
845 }
846 Ok(())
847 }
848
849 pub(super) fn aggregate_element(
852 &mut self,
853 arr: Expression<'_>,
854 i: i64,
855 ty: Ty,
856 ) -> Result<Expr, BuildError> {
857 let mut chain = aggregate_chain(arr, &self.forced_roots).ok_or_else(|| {
858 unsupported(
859 "a method over an unpacked array that is not a property (or a member of a struct \
860 property) of this class",
861 "C14",
862 )
863 })?;
864 chain.steps.push(RawStep::Const(i));
865 self.aggregate_value(chain, ty)
866 }
867
868 pub(super) fn real_aggregate(
870 &mut self,
871 chain: Chain<'_>,
872 kind: Fk,
873 ) -> Result<RealExpr, BuildError> {
874 let leaf = match self.resolve_chain(&chain)? {
875 Sel::Leaf(leaf) => leaf,
876 Sel::Pick { .. } => {
877 return Err(BuildError::RealConstraint {
878 what: "a real element of an array at a computed index (only an integral \
879 element can be chosen by a state or loop variable)"
880 .into(),
881 });
882 }
883 };
884 if !matches!(leaf.kind, LeafKind::Real(_)) {
885 return Err(missing(format!("a real value for `{}`", leaf.name)));
886 }
887 if leaf.mode == RandMode::None {
888 let st = self.leaf_state(&leaf, state_ty(kind));
889 return self.real_state(st, kind);
890 }
891 let key = (leaf.root.clone(), leaf.path.clone());
892 let &id = self
893 .real_leaf_ix
894 .get(&key)
895 .ok_or_else(|| Self::undeclared(&leaf))?;
896 Ok(RealExpr::Var(id))
897 }
898}