1use crate::declaration::{ConstantInfo, ConstructorVal, InductiveVal, QuotVal, RecursorVal};
6use crate::env::EnvError;
7use crate::Node;
8use crate::{Declaration, Environment, KernelError, TypeChecker};
9#[cfg(test)]
10use crate::{Expr, Name};
11use std::rc::Rc;
12
13use super::types::{
14 BatchCheckResult, CheckConfig, CheckStats, ConfigNode, DecisionNode, DeclKind, DeclSummary,
15 Either2, EnvBuilder, FlatSubstitution, FocusStack, LabelSet, NonEmptyVec, PathBuf, RewriteRule,
16 RewriteRuleSet, SimpleDag, SlidingSum, SmallMap, SparseVec, StackCalc, StatSummary, Stopwatch,
17 StringPool, TempEnvScope, TokenBucket, TransformStat, TransitiveClosure, VersionedRecord,
18 WellFormedResult, WindowIterator, WriteOnce,
19};
20
21#[allow(clippy::result_large_err)]
27pub fn check_declaration(env: &mut Environment, decl: Declaration) -> Result<(), KernelError> {
28 let name = decl.name().clone();
29 check_univ_param_hygiene(&decl)?;
34 match &decl {
35 Declaration::Axiom { ty, .. } => {
36 let mut tc = TypeChecker::new(env);
37 tc.ensure_sort(ty)?;
38 }
39 Declaration::Definition { ty, val, .. } => {
40 let mut tc = TypeChecker::new(env);
41 tc.ensure_sort(ty)?;
42 let val_ty = tc.infer_type(val)?;
43 tc.check_type(val, &val_ty, ty)?;
44 }
45 Declaration::Theorem { ty, val, .. } => {
46 let mut tc = TypeChecker::new(env);
47 check_theorem_type(&mut tc, &name, ty)?;
48 let val_ty = tc.infer_type(val)?;
49 tc.check_type(val, &val_ty, ty)?;
50 }
51 Declaration::Opaque { ty, val, .. } => {
52 let mut tc = TypeChecker::new(env);
53 tc.ensure_sort(ty)?;
54 let val_ty = tc.infer_type(val)?;
55 tc.check_type(val, &val_ty, ty)?;
56 }
57 }
58 env.add(decl).map_err(|e| match e {
59 EnvError::DuplicateDeclaration(_) => {
60 KernelError::Other(format!("duplicate declaration: {}", name))
61 }
62 EnvError::NotFound(_) => KernelError::Other(format!("declaration not found: {}", name)),
63 EnvError::InvalidQuotient(msg) => KernelError::Other(msg),
64 })
65}
66#[allow(clippy::result_large_err)]
76fn check_theorem_type(
77 tc: &mut TypeChecker<'_>,
78 name: &crate::Name,
79 ty: &crate::Expr,
80) -> Result<(), KernelError> {
81 let sort = tc.ensure_sort(ty)?;
82 if !crate::level::is_equivalent(&sort, &crate::Level::zero()) {
83 return Err(KernelError::Other(format!(
84 "type of theorem '{name}' is not a proposition: it is a type in Sort {sort}, not in \
85 Prop"
86 )));
87 }
88 Ok(())
89}
90#[allow(clippy::result_large_err)]
102pub(super) fn check_univ_param_hygiene(decl: &Declaration) -> Result<(), KernelError> {
103 check_univ_param_hygiene_parts(
104 decl.name(),
105 decl.univ_params(),
106 std::iter::once(decl.ty()).chain(decl.value()),
107 )
108}
109#[allow(clippy::result_large_err)]
119pub(super) fn check_univ_param_hygiene_ci(ci: &ConstantInfo) -> Result<(), KernelError> {
120 check_univ_param_hygiene_parts(
121 ci.name(),
122 ci.level_params(),
123 std::iter::once(ci.ty()).chain(ci.value()),
124 )
125}
126#[allow(clippy::result_large_err)]
141fn check_univ_param_hygiene_parts<'a>(
142 name: &crate::Name,
143 params: &[crate::Name],
144 exprs: impl Iterator<Item = &'a crate::Expr>,
145) -> Result<(), KernelError> {
146 use std::collections::HashSet;
147
148 let mut declared: HashSet<&crate::Name> = HashSet::new();
150 for p in params {
151 if !declared.insert(p) {
152 return Err(KernelError::Other(format!(
153 "declaration {}: duplicate universe parameter `{}`",
154 name, p
155 )));
156 }
157 }
158
159 for expr in exprs {
161 check_term_depth(name, expr)?;
164 check_closed_term(name, expr)?;
165 if crate::expr_util::has_level_mvar(expr) {
167 return Err(KernelError::Other(format!(
168 "declaration {}: universe metavariable in kernel-checked declaration",
169 name
170 )));
171 }
172 let mut used = Vec::new();
174 collect_expr_level_params(expr, &mut used);
175 for u in &used {
176 if !declared.contains(u) {
177 return Err(KernelError::Other(format!(
178 "declaration {}: undeclared universe parameter `{}`",
179 name, u
180 )));
181 }
182 }
183 }
184 Ok(())
185}
186#[allow(clippy::result_large_err)]
206pub(crate) fn check_closed_term(name: &crate::Name, expr: &crate::Expr) -> Result<(), KernelError> {
207 if crate::expr_util::has_any_fvar(expr) {
208 return Err(KernelError::Other(format!(
209 "declaration {}: free variable in kernel-checked declaration",
210 name
211 )));
212 }
213 if crate::expr_util::has_loose_bvars(expr) {
214 return Err(KernelError::Other(format!(
215 "declaration {}: loose bound variable in kernel-checked declaration",
216 name
217 )));
218 }
219 Ok(())
220}
221#[allow(clippy::result_large_err)]
235pub(crate) fn check_term_depth(name: &crate::Name, expr: &crate::Expr) -> Result<(), KernelError> {
236 #[cfg(feature = "term-depth")]
237 {
238 let depth = expr.depth();
239 if crate::fuel::term_depth_limit().is_some_and(|limit| depth > limit) {
240 crate::fuel::note_term_depth(depth);
241 return Err(KernelError::Other(format!(
242 "declaration {name}: a term {depth} deep is over the term-depth limit"
243 )));
244 }
245 }
246 #[cfg(not(feature = "term-depth"))]
247 let _ = (name, expr);
248 Ok(())
249}
250pub(super) fn collect_expr_level_params(expr: &crate::Expr, out: &mut Vec<crate::Name>) {
261 use crate::{Expr, Node};
262 let mut seen: std::collections::HashSet<*const Expr, crate::node_memo::WordBuildHasher> =
263 std::collections::HashSet::default();
264 let mut pending: Vec<&Node> = Vec::new();
265 let mut current: Option<&Expr> = Some(expr);
266 loop {
267 let cur = match current.take() {
268 Some(cur) => cur,
269 None => match pending.pop() {
270 Some(node) => {
271 if !node.has_level_param() || !seen.insert(node.as_ptr()) {
272 continue;
273 }
274 node
275 }
276 None => break,
277 },
278 };
279 match cur {
280 Expr::Sort(l) => collect_level_params_in_level(l, out),
281 Expr::Const(_, levels) => {
282 for l in levels {
283 collect_level_params_in_level(l, out);
284 }
285 }
286 Expr::App(f, a) => {
287 pending.push(a);
288 pending.push(f);
289 }
290 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
291 pending.push(body);
292 pending.push(ty);
293 }
294 Expr::Let(_, ty, val, body) => {
295 pending.push(body);
296 pending.push(val);
297 pending.push(ty);
298 }
299 Expr::Proj(_, _, e) => pending.push(e),
300 Expr::BVar(_) | Expr::FVar(_) | Expr::Lit(_) => {}
301 }
302 }
303}
304fn collect_level_params_in_level(l: &crate::Level, out: &mut Vec<crate::Name>) {
305 use crate::LevelView;
306 match l.view() {
307 LevelView::Param(n) => {
308 if !out.contains(n) {
309 out.push(n.clone());
310 }
311 }
312 LevelView::Succ(inner) => collect_level_params_in_level(inner, out),
313 LevelView::Max(a, b) | LevelView::IMax(a, b) => {
314 collect_level_params_in_level(a, out);
315 collect_level_params_in_level(b, out);
316 }
317 LevelView::Zero | LevelView::MVar(_) => {}
318 }
319}
320#[allow(clippy::result_large_err)]
326pub fn check_declarations(
327 env: &mut Environment,
328 decls: Vec<Declaration>,
329) -> Result<(), KernelError> {
330 for decl in decls {
331 check_declaration(env, decl)?;
332 }
333 Ok(())
334}
335#[allow(clippy::result_large_err)]
348pub fn check_constant_info(env: &mut Environment, ci: ConstantInfo) -> Result<(), KernelError> {
349 let name = ci.name().clone();
350 check_univ_param_hygiene_ci(&ci)?;
354 let mut derived_recursor: Option<RecursorVal> = None;
355 match &ci {
356 ConstantInfo::Axiom(av) => {
357 let mut tc = TypeChecker::new(env);
358 tc.ensure_sort(&av.common.ty)?;
359 }
360 ConstantInfo::Definition(dv) => {
361 let mut tc = TypeChecker::new(env);
362 tc.ensure_sort(&dv.common.ty)?;
363 let val_ty = tc.infer_type(&dv.value)?;
364 tc.check_type(&dv.value, &val_ty, &dv.common.ty)?;
365 }
366 ConstantInfo::Theorem(tv) => {
367 let mut tc = TypeChecker::new(env);
368 check_theorem_type(&mut tc, &name, &tv.common.ty)?;
369 let val_ty = tc.infer_type(&tv.value)?;
370 tc.check_type(&tv.value, &val_ty, &tv.common.ty)?;
371 }
372 ConstantInfo::Opaque(ov) => {
373 let mut tc = TypeChecker::new(env);
374 tc.ensure_sort(&ov.common.ty)?;
375 let val_ty = tc.infer_type(&ov.value)?;
376 tc.check_type(&ov.value, &val_ty, &ov.common.ty)?;
377 }
378 ConstantInfo::Inductive(iv) => {
379 check_inductive_val(env, iv)?;
380 }
381 ConstantInfo::Constructor(cv) => {
382 check_constructor_val(env, cv)?;
383 }
384 ConstantInfo::Recursor(rv) => {
385 for rule in &rv.rules {
388 check_term_depth(&name, &rule.rhs)?;
389 check_closed_term(&name, &rule.rhs)?;
390 }
391 derived_recursor = Some(check_recursor_val(env, rv)?);
395 }
396 ConstantInfo::Quotient(qv) => {
397 check_quotient_val(env, qv)?;
398 }
399 }
400 let ci = match derived_recursor {
401 Some(derived) => ConstantInfo::Recursor(derived),
402 None => ci,
403 };
404 env.add_constant(ci).map_err(|e| match e {
405 crate::env::EnvError::DuplicateDeclaration(_) => {
406 KernelError::Other(format!("duplicate declaration: {}", name))
407 }
408 crate::env::EnvError::NotFound(_) => {
409 KernelError::Other(format!("declaration not found: {}", name))
410 }
411 crate::env::EnvError::InvalidQuotient(msg) => KernelError::Other(msg),
412 })
413}
414#[allow(clippy::result_large_err)]
416pub fn check_constant_infos(
417 env: &mut Environment,
418 cis: Vec<ConstantInfo>,
419) -> Result<(), KernelError> {
420 for ci in cis {
421 check_constant_info(env, ci)?;
422 }
423 Ok(())
424}
425#[allow(clippy::result_large_err)]
452pub fn check_constant_infos_atomic(
453 env: &mut Environment,
454 cis: Vec<ConstantInfo>,
455) -> Result<(), KernelError> {
456 let mut added: Vec<crate::Name> = Vec::with_capacity(cis.len());
457 for ci in cis {
458 let name = ci.name().clone();
459 if let Err(e) = check_constant_info(env, ci) {
460 env.remove_constants(&added);
461 return Err(e);
462 }
463 added.push(name);
464 }
465 let guarded = {
466 let installed: Vec<&ConstantInfo> = added.iter().filter_map(|n| env.find(n)).collect();
467 crate::inductive::installed::check_derived_references(
468 env,
469 &installed,
470 crate::inductive::installed::DerivedTerms::Recursors,
471 )
472 };
473 if let Err(e) = guarded {
474 env.remove_constants(&added);
475 return Err(e);
476 }
477 Ok(())
478}
479#[allow(clippy::result_large_err)]
492pub(super) fn check_inductive_val(
493 env: &mut Environment,
494 iv: &InductiveVal,
495) -> Result<(), KernelError> {
496 crate::inductive::derive::validate_inductive_val(env, iv)
497}
498#[allow(clippy::result_large_err)]
506pub(super) fn check_constructor_val(
507 env: &mut Environment,
508 cv: &ConstructorVal,
509) -> Result<(), KernelError> {
510 crate::inductive::derive::verify_constructor_val(env, cv)
511}
512#[allow(clippy::result_large_err)]
521pub(super) fn check_recursor_val(
522 env: &mut Environment,
523 rv: &RecursorVal,
524) -> Result<RecursorVal, KernelError> {
525 crate::inductive::derive::verify_recursor_val(env, rv)
526}
527#[allow(clippy::result_large_err)]
537pub(super) fn check_quotient_val(env: &mut Environment, qv: &QuotVal) -> Result<(), KernelError> {
538 let canonical = crate::env::canonical_quot_type(qv.kind);
539 let expected_params = crate::env::canonical_quot_level_params(qv.kind);
540 if qv.common.level_params != expected_params {
541 return Err(KernelError::Other(format!(
542 "quotient `{}` has unexpected universe parameters: expected {:?}, got {:?}",
543 qv.common.name, expected_params, qv.common.level_params
544 )));
545 }
546 let mut tc = TypeChecker::new(env);
547 tc.ensure_sort(&qv.common.ty)?;
548 if !tc.is_def_eq(&qv.common.ty, &canonical) {
549 return Err(KernelError::TypeMismatch {
550 expected: canonical,
551 got: qv.common.ty.clone(),
552 context: format!("canonical type of quotient `{}`", qv.common.name),
553 });
554 }
555 Ok(())
556}
557pub fn summarize_declaration(decl: &Declaration) -> DeclSummary {
559 match decl {
560 Declaration::Axiom {
561 name, univ_params, ..
562 } => DeclSummary {
563 name: format!("{}", name),
564 kind: DeclKind::Axiom,
565 has_body: false,
566 num_univ_params: univ_params.len(),
567 },
568 Declaration::Definition {
569 name, univ_params, ..
570 } => DeclSummary {
571 name: format!("{}", name),
572 kind: DeclKind::Definition,
573 has_body: true,
574 num_univ_params: univ_params.len(),
575 },
576 Declaration::Theorem {
577 name, univ_params, ..
578 } => DeclSummary {
579 name: format!("{}", name),
580 kind: DeclKind::Theorem,
581 has_body: true,
582 num_univ_params: univ_params.len(),
583 },
584 Declaration::Opaque {
585 name, univ_params, ..
586 } => DeclSummary {
587 name: format!("{}", name),
588 kind: DeclKind::Opaque,
589 has_body: true,
590 num_univ_params: univ_params.len(),
591 },
592 }
593}
594pub fn check_declarations_collect_errors(
599 env: &mut Environment,
600 decls: Vec<Declaration>,
601) -> BatchCheckResult {
602 let mut num_ok = 0;
603 let mut num_failed = 0;
604 let mut errors = Vec::new();
605 for decl in decls {
606 let name = format!("{}", decl.name());
607 match check_declaration(env, decl) {
608 Ok(()) => num_ok += 1,
609 Err(e) => {
610 num_failed += 1;
611 errors.push((name, format!("{:?}", e)));
612 }
613 }
614 }
615 BatchCheckResult {
616 num_ok,
617 num_failed,
618 errors,
619 }
620}
621#[allow(clippy::result_large_err)]
626pub fn check_declarations_with_stats(
627 env: &mut Environment,
628 decls: Vec<Declaration>,
629) -> (CheckStats, Option<KernelError>) {
630 let mut stats = CheckStats::new();
631 for decl in decls {
632 let kind = summarize_declaration(&decl).kind;
633 match check_declaration(env, decl) {
634 Ok(()) => match kind {
635 DeclKind::Axiom => stats.num_axioms += 1,
636 DeclKind::Definition => stats.num_definitions += 1,
637 DeclKind::Theorem => stats.num_theorems += 1,
638 DeclKind::Opaque => stats.num_opaques += 1,
639 },
640 Err(e) => {
641 stats.num_failures += 1;
642 return (stats, Some(e));
643 }
644 }
645 }
646 (stats, None)
647}
648pub fn is_valid_decl_name(name: &str) -> bool {
650 !name.is_empty()
651 && name
652 .chars()
653 .all(|c| c.is_alphanumeric() || c == '_' || c == '.' || c == '\'')
654 && !name.starts_with('.')
655 && !name.ends_with('.')
656}
657pub fn has_unique_univ_params(params: &[crate::Name]) -> bool {
659 let mut seen = std::collections::HashSet::new();
660 params.iter().all(|p| seen.insert(format!("{}", p)))
661}
662pub fn univ_params_compatible(p1: &[crate::Name], p2: &[crate::Name]) -> bool {
664 p1.len() == p2.len()
665 && p1
666 .iter()
667 .zip(p2.iter())
668 .all(|(a, b)| format!("{}", a) == format!("{}", b))
669}
670pub fn format_decl_summary(summary: &DeclSummary) -> String {
672 let body_str = if summary.has_body { " := ..." } else { "" };
673 let params_str = if summary.num_univ_params > 0 {
674 format!(".{{u{}}}", summary.num_univ_params)
675 } else {
676 String::new()
677 };
678 format!(
679 "{} {}{}{} : ...",
680 summary.kind, summary.name, params_str, body_str
681 )
682}
683pub fn format_batch_result(result: &BatchCheckResult) -> String {
685 if result.all_ok() {
686 format!("All {} declarations OK", result.total())
687 } else {
688 let mut s = format!(
689 "{}/{} declarations OK. Failures:\n",
690 result.num_ok,
691 result.total()
692 );
693 for msg in result.error_messages() {
694 s.push_str(" - ");
695 s.push_str(&msg);
696 s.push('\n');
697 }
698 s
699 }
700}
701pub fn verify_environment_integrity(env: &Environment) -> Vec<String> {
706 let mut issues = Vec::new();
707 for name in env
708 .constant_names()
709 .cloned()
710 .collect::<Vec<_>>()
711 .into_iter()
712 {
713 if let Some(info) = env.get(&name) {
714 let ty = info.ty();
715 if !is_structurally_valid_expr(ty) {
716 issues.push(format!("{}: type is not structurally valid", name));
717 }
718 }
719 }
720 issues
721}
722pub fn is_structurally_valid_expr(expr: &crate::Expr) -> bool {
727 check_expr_bvars(expr, 0)
728}
729pub(super) fn check_expr_bvars(expr: &crate::Expr, depth: u32) -> bool {
730 use crate::Expr;
731 match expr {
732 Expr::BVar(i) => *i < depth,
733 Expr::FVar(_) | Expr::Sort(_) | Expr::Const(_, _) | Expr::Lit(_) => true,
734 Expr::App(f, a) => check_expr_bvars(f, depth) && check_expr_bvars(a, depth),
735 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
736 check_expr_bvars(ty, depth) && check_expr_bvars(body, depth + 1)
737 }
738 Expr::Let(_, ty, val, body) => {
739 check_expr_bvars(ty, depth)
740 && check_expr_bvars(val, depth)
741 && check_expr_bvars(body, depth + 1)
742 }
743 Expr::Proj(_, _, e) => check_expr_bvars(e, depth),
744 }
745}
746pub fn declaration_dependencies(decl: &Declaration) -> Vec<crate::Name> {
750 use crate::collect_const_names;
751 let mut deps = collect_const_names(decl.ty());
752 if let Some(val) = decl.value() {
753 deps.extend(collect_const_names(val));
754 }
755 deps.sort_by(|a, b| format!("{}", a).cmp(&format!("{}", b)));
756 deps.dedup_by(|a, b| format!("{}", a) == format!("{}", b));
757 deps
758}
759pub fn check_dependencies_exist(env: &Environment, decl: &Declaration) -> Vec<crate::Name> {
763 let deps = declaration_dependencies(decl);
764 deps.into_iter()
765 .filter(|name| env.get(name).is_none())
766 .collect()
767}
768#[cfg(test)]
769mod tests {
770 use super::*;
771 use crate::{Level, Literal, ReducibilityHint};
772 fn mk_type0() -> Expr {
773 Expr::Sort(Level::succ(Level::zero()))
774 }
775 fn mk_nat_axiom() -> Declaration {
776 Declaration::Axiom {
777 name: Name::str("Nat"),
778 univ_params: vec![],
779 ty: mk_type0(),
780 }
781 }
782 fn mk_nat_const() -> Expr {
783 Expr::Const(Name::str("Nat"), vec![])
784 }
785 #[test]
786 fn test_check_axiom() {
787 let mut env = Environment::new();
788 let nat_ty = Expr::Sort(Level::succ(Level::zero()));
789 let axiom = Declaration::Axiom {
790 name: Name::str("Nat"),
791 univ_params: vec![],
792 ty: nat_ty,
793 };
794 check_declaration(&mut env, axiom).expect("value should be present");
795 assert!(env.contains(&Name::str("Nat")));
796 }
797 #[test]
798 fn test_check_definition() {
799 let mut env = Environment::new();
800 env.add(mk_nat_axiom()).expect("value should be present");
801 let nat_ty = mk_nat_const();
802 let val = Expr::Lit(Literal::nat(42));
803 let def = Declaration::Definition {
804 name: Name::str("answer"),
805 univ_params: vec![],
806 ty: nat_ty,
807 val,
808 hint: ReducibilityHint::Regular(1),
809 };
810 check_declaration(&mut env, def).expect("value should be present");
811 assert!(env.contains(&Name::str("answer")));
812 }
813 #[test]
814 fn test_type_mismatch() {
815 let mut env = Environment::new();
816 let type0 = mk_type0();
817 env.add(Declaration::Axiom {
818 name: Name::str("String"),
819 univ_params: vec![],
820 ty: type0.clone(),
821 })
822 .expect("value should be present");
823 env.add(Declaration::Axiom {
824 name: Name::str("Nat"),
825 univ_params: vec![],
826 ty: type0,
827 })
828 .expect("value should be present");
829 let string_ty = Expr::Const(Name::str("String"), vec![]);
830 let val = Expr::Lit(Literal::nat(42));
831 let def = Declaration::Definition {
832 name: Name::str("bad"),
833 univ_params: vec![],
834 ty: string_ty,
835 val,
836 hint: ReducibilityHint::Regular(1),
837 };
838 let result = check_declaration(&mut env, def);
839 assert!(result.is_err());
840 }
841 #[test]
842 fn test_check_declarations_sequence() {
843 let mut env = Environment::new();
844 let decls = vec![
845 Declaration::Axiom {
846 name: Name::str("A"),
847 univ_params: vec![],
848 ty: mk_type0(),
849 },
850 Declaration::Axiom {
851 name: Name::str("B"),
852 univ_params: vec![],
853 ty: mk_type0(),
854 },
855 ];
856 check_declarations(&mut env, decls).expect("value should be present");
857 assert!(env.contains(&Name::str("A")));
858 assert!(env.contains(&Name::str("B")));
859 }
860 #[test]
861 fn test_decl_kind_display() {
862 assert_eq!(DeclKind::Axiom.as_str(), "axiom");
863 assert_eq!(DeclKind::Definition.as_str(), "def");
864 assert_eq!(DeclKind::Theorem.as_str(), "theorem");
865 assert_eq!(DeclKind::Opaque.as_str(), "opaque");
866 assert!(DeclKind::Theorem.is_proven());
867 assert!(DeclKind::Axiom.is_assumed());
868 assert!(DeclKind::Definition.is_definition());
869 assert!(!DeclKind::Axiom.is_definition());
870 }
871 #[test]
872 fn test_summarize_declaration() {
873 let decl = mk_nat_axiom();
874 let summary = summarize_declaration(&decl);
875 assert_eq!(summary.name, "Nat");
876 assert_eq!(summary.kind, DeclKind::Axiom);
877 assert!(!summary.has_body);
878 assert_eq!(summary.num_univ_params, 0);
879 }
880 #[test]
881 fn test_is_valid_decl_name() {
882 assert!(is_valid_decl_name("Nat"));
883 assert!(is_valid_decl_name("Nat.succ"));
884 assert!(is_valid_decl_name("foo_bar"));
885 assert!(!is_valid_decl_name(""));
886 assert!(!is_valid_decl_name(".leading_dot"));
887 assert!(!is_valid_decl_name("trailing_dot."));
888 }
889 #[test]
890 fn test_has_unique_univ_params() {
891 let u = Name::str("u");
892 let v = Name::str("v");
893 let params = vec![u.clone(), v.clone()];
894 assert!(has_unique_univ_params(¶ms));
895 let dup_params = vec![u.clone(), u.clone()];
896 assert!(!has_unique_univ_params(&dup_params));
897 }
898 #[test]
899 fn test_check_config_default() {
900 let cfg = CheckConfig::default();
901 assert!(cfg.check_type_is_sort);
902 assert!(cfg.check_value_type);
903 assert!(cfg.check_no_free_vars);
904 }
905 #[test]
906 fn test_check_config_lenient() {
907 let cfg = CheckConfig::lenient();
908 assert!(cfg.check_type_is_sort);
909 assert!(!cfg.check_value_type);
910 }
911 #[test]
912 fn test_check_config_strict() {
913 let cfg = CheckConfig::strict();
914 assert!(!cfg.allow_axioms);
915 assert!(cfg.max_depth > 0);
916 }
917 #[test]
918 fn test_batch_check_all_ok() {
919 let mut env = Environment::new();
920 let decls = vec![
921 Declaration::Axiom {
922 name: Name::str("X"),
923 univ_params: vec![],
924 ty: mk_type0(),
925 },
926 Declaration::Axiom {
927 name: Name::str("Y"),
928 univ_params: vec![],
929 ty: mk_type0(),
930 },
931 ];
932 let result = check_declarations_collect_errors(&mut env, decls);
933 assert!(result.all_ok());
934 assert_eq!(result.num_ok, 2);
935 assert_eq!(result.num_failed, 0);
936 }
937 #[test]
938 fn test_batch_check_with_error() {
939 let mut env = Environment::new();
940 let decls = vec![
941 Declaration::Axiom {
942 name: Name::str("M"),
943 univ_params: vec![],
944 ty: mk_type0(),
945 },
946 Declaration::Definition {
947 name: Name::str("bad_def"),
948 univ_params: vec![],
949 ty: Expr::Const(Name::str("UndefinedType"), vec![]),
950 val: Expr::Lit(Literal::nat(0)),
951 hint: ReducibilityHint::Regular(1),
952 },
953 ];
954 let result = check_declarations_collect_errors(&mut env, decls);
955 assert!(!result.all_ok());
956 assert_eq!(result.num_ok, 1);
957 assert_eq!(result.num_failed, 1);
958 }
959 #[test]
960 fn test_env_builder_clean() {
961 let mut builder = EnvBuilder::new();
962 let added = builder.add(Declaration::Axiom {
963 name: Name::str("P"),
964 univ_params: vec![],
965 ty: mk_type0(),
966 });
967 assert!(added);
968 assert!(builder.is_clean());
969 assert_eq!(builder.stats().num_axioms, 1);
970 }
971 #[test]
972 fn test_env_builder_with_error() {
973 let mut builder = EnvBuilder::new();
974 let added = builder.add(Declaration::Definition {
975 name: Name::str("oops"),
976 univ_params: vec![],
977 ty: Expr::Const(Name::str("NoSuchType"), vec![]),
978 val: Expr::Lit(Literal::nat(0)),
979 hint: ReducibilityHint::Regular(1),
980 });
981 assert!(!added);
982 assert!(!builder.is_clean());
983 assert_eq!(builder.errors().len(), 1);
984 }
985 #[test]
986 fn test_well_formed_result_display() {
987 let ok = WellFormedResult::Ok;
988 assert!(ok.is_ok());
989 assert_eq!(ok.description(), "well-formed");
990 let mismatch = WellFormedResult::TypeMismatch {
991 description: "Nat vs String".to_string(),
992 };
993 assert!(!mismatch.is_ok());
994 assert!(mismatch.description().contains("Nat vs String"));
995 }
996 #[test]
997 fn test_is_structurally_valid_expr() {
998 let bad = Expr::BVar(0);
999 assert!(!is_structurally_valid_expr(&bad));
1000 let sort = Expr::Sort(Level::zero());
1001 assert!(is_structurally_valid_expr(&sort));
1002 let lam = Expr::Lam(
1003 crate::BinderInfo::Default,
1004 Name::str("x"),
1005 Node::new(Expr::Sort(Level::zero())),
1006 Node::new(Expr::BVar(0)),
1007 );
1008 assert!(is_structurally_valid_expr(&lam));
1009 }
1010 #[test]
1011 fn test_format_decl_summary() {
1012 let summary = DeclSummary {
1013 name: "Nat.add".to_string(),
1014 kind: DeclKind::Definition,
1015 has_body: true,
1016 num_univ_params: 0,
1017 };
1018 let s = format_decl_summary(&summary);
1019 assert!(s.contains("Nat.add"));
1020 assert!(s.contains("def"));
1021 }
1022 #[test]
1023 fn test_check_stats_totals() {
1024 let stats = CheckStats {
1025 num_axioms: 2,
1026 num_definitions: 3,
1027 num_theorems: 1,
1028 num_opaques: 0,
1029 num_failures: 1,
1030 };
1031 assert_eq!(stats.total(), 6);
1032 assert_eq!(stats.num_ok(), 6);
1033 }
1034 #[test]
1035 fn test_format_batch_result_all_ok() {
1036 let result = BatchCheckResult {
1037 num_ok: 3,
1038 num_failed: 0,
1039 errors: vec![],
1040 };
1041 let s = format_batch_result(&result);
1042 assert!(s.contains("3"));
1043 }
1044 #[test]
1045 fn test_temp_env_scope() {
1046 let mut env = Environment::new();
1047 {
1048 let mut scope = TempEnvScope::new(&mut env);
1049 let ok = scope.add(Declaration::Axiom {
1050 name: Name::str("TempDecl"),
1051 univ_params: vec![],
1052 ty: mk_type0(),
1053 });
1054 assert!(ok.is_ok());
1055 assert_eq!(scope.num_added(), 1);
1056 }
1057 assert!(env.contains(&Name::str("TempDecl")));
1058 }
1059 #[allow(dead_code)]
1060 fn mk_type1() -> Expr {
1061 Expr::Sort(Level::succ(Level::succ(Level::zero())))
1062 }
1063 #[test]
1064 fn test_check_constant_info_axiom() {
1065 use crate::declaration::{AxiomVal, ConstantVal};
1066 let mut env = Environment::new();
1067 let ci = ConstantInfo::Axiom(AxiomVal {
1068 common: ConstantVal {
1069 name: Name::str("MyAxiom"),
1070 level_params: vec![],
1071 ty: mk_type0(),
1072 },
1073 is_unsafe: false,
1074 });
1075 check_constant_info(&mut env, ci).expect("value should be present");
1076 assert!(env.contains(&Name::str("MyAxiom")));
1077 }
1078 #[test]
1079 fn test_check_constant_info_inductive_simple() {
1080 use crate::declaration::{ConstantVal, InductiveVal};
1081 let mut env = Environment::new();
1082 let iv = InductiveVal {
1083 common: ConstantVal {
1084 name: Name::str("Bool"),
1085 level_params: vec![],
1086 ty: mk_type0(),
1087 },
1088 num_params: 0,
1089 num_indices: 0,
1090 all: vec![Name::str("Bool")],
1091 ctors: vec![Name::str("Bool.true"), Name::str("Bool.false")],
1092 num_nested: 0,
1093 is_rec: false,
1094 is_unsafe: false,
1095 is_reflexive: false,
1096 is_prop: false,
1097 };
1098 let ci = ConstantInfo::Inductive(iv);
1099 check_constant_info(&mut env, ci).expect("value should be present");
1100 assert!(env.contains(&Name::str("Bool")));
1101 }
1102 #[test]
1103 fn test_check_constant_info_inductive_empty() {
1104 use crate::declaration::{ConstantVal, InductiveVal};
1105 let mut env = Environment::new();
1106 let iv = InductiveVal {
1107 common: ConstantVal {
1108 name: Name::str("Empty"),
1109 level_params: vec![],
1110 ty: mk_type0(),
1111 },
1112 num_params: 0,
1113 num_indices: 0,
1114 all: vec![Name::str("Empty")],
1115 ctors: vec![],
1116 num_nested: 0,
1117 is_rec: false,
1118 is_unsafe: false,
1119 is_reflexive: false,
1120 is_prop: false,
1121 };
1122 let ci = ConstantInfo::Inductive(iv);
1123 check_constant_info(&mut env, ci).expect("value should be present");
1124 assert!(env.contains(&Name::str("Empty")));
1125 }
1126 #[test]
1127 fn test_check_constant_info_constructor_valid() {
1128 use crate::declaration::{ConstantVal, ConstructorVal, InductiveVal};
1129 let mut env = Environment::new();
1130 let ind_ci = ConstantInfo::Inductive(InductiveVal {
1131 common: ConstantVal {
1132 name: Name::str("Bool"),
1133 level_params: vec![],
1134 ty: mk_type0(),
1135 },
1136 num_params: 0,
1137 num_indices: 0,
1138 all: vec![Name::str("Bool")],
1139 ctors: vec![Name::str("Bool.true")],
1140 num_nested: 0,
1141 is_rec: false,
1142 is_unsafe: false,
1143 is_reflexive: false,
1144 is_prop: false,
1145 });
1146 check_constant_info(&mut env, ind_ci).expect("value should be present");
1147 let ctor_ci = ConstantInfo::Constructor(ConstructorVal {
1148 common: ConstantVal {
1149 name: Name::str("Bool.true"),
1150 level_params: vec![],
1151 ty: Expr::Const(Name::str("Bool"), vec![]),
1152 },
1153 induct: Name::str("Bool"),
1154 cidx: 0,
1155 num_params: 0,
1156 num_fields: 0,
1157 is_unsafe: false,
1158 });
1159 check_constant_info(&mut env, ctor_ci).expect("value should be present");
1160 assert!(env.contains(&Name::str("Bool.true")));
1161 }
1162 #[test]
1163 fn test_check_constant_info_constructor_wrong_return_type() {
1164 use crate::declaration::{ConstantVal, ConstructorVal, InductiveVal};
1165 let mut env = Environment::new();
1166 env.add_constant(ConstantInfo::Inductive(InductiveVal {
1167 common: ConstantVal {
1168 name: Name::str("Bool"),
1169 level_params: vec![],
1170 ty: mk_type0(),
1171 },
1172 num_params: 0,
1173 num_indices: 0,
1174 all: vec![Name::str("Bool")],
1175 ctors: vec![Name::str("Bool.bad")],
1176 num_nested: 0,
1177 is_rec: false,
1178 is_unsafe: false,
1179 is_reflexive: false,
1180 is_prop: false,
1181 }))
1182 .expect("value should be present");
1183 env.add_constant(ConstantInfo::Inductive(InductiveVal {
1184 common: ConstantVal {
1185 name: Name::str("Nat"),
1186 level_params: vec![],
1187 ty: mk_type0(),
1188 },
1189 num_params: 0,
1190 num_indices: 0,
1191 all: vec![Name::str("Nat")],
1192 ctors: vec![],
1193 num_nested: 0,
1194 is_rec: false,
1195 is_unsafe: false,
1196 is_reflexive: false,
1197 is_prop: false,
1198 }))
1199 .expect("value should be present");
1200 let ctor_ci = ConstantInfo::Constructor(ConstructorVal {
1201 common: ConstantVal {
1202 name: Name::str("Bool.bad"),
1203 level_params: vec![],
1204 ty: Expr::Const(Name::str("Nat"), vec![]),
1205 },
1206 induct: Name::str("Bool"),
1207 cidx: 0,
1208 num_params: 0,
1209 num_fields: 0,
1210 is_unsafe: false,
1211 });
1212 let result = check_constant_info(&mut env, ctor_ci);
1213 assert!(result.is_err(), "expected error for wrong return type");
1214 }
1215 #[test]
1216 fn test_check_constant_info_recursor_rejects_bogus() {
1217 use crate::declaration::{ConstantVal, InductiveVal, RecursorVal};
1221 let mut env = Environment::new();
1222 env.add_constant(ConstantInfo::Inductive(InductiveVal {
1223 common: ConstantVal {
1224 name: Name::str("Bool"),
1225 level_params: vec![],
1226 ty: mk_type0(),
1227 },
1228 num_params: 0,
1229 num_indices: 0,
1230 all: vec![Name::str("Bool")],
1231 ctors: vec![],
1232 num_nested: 0,
1233 is_rec: false,
1234 is_unsafe: false,
1235 is_reflexive: false,
1236 is_prop: false,
1237 }))
1238 .expect("value should be present");
1239 let rec_ty = mk_type0();
1240 let rec_ci = ConstantInfo::Recursor(RecursorVal {
1241 common: ConstantVal {
1242 name: Name::str("Bool.rec"),
1243 level_params: vec![],
1244 ty: rec_ty,
1245 },
1246 all: vec![Name::str("Bool")],
1247 num_params: 0,
1248 num_indices: 0,
1249 num_motives: 1,
1250 num_minors: 2,
1251 rules: vec![],
1252 k: false,
1253 is_unsafe: false,
1254 });
1255 let result = check_constant_info(&mut env, rec_ci);
1256 assert!(
1257 result.is_err(),
1258 "hand-supplied bogus recursor must be rejected"
1259 );
1260 assert!(!env.contains(&Name::str("Bool.rec")));
1261 }
1262 #[test]
1263 fn test_check_constant_info_quotient_rejects_noncanonical() {
1264 use crate::declaration::{ConstantVal, QuotKind, QuotVal};
1269 let mut env = Environment::new();
1270 let quot_ci = ConstantInfo::Quotient(QuotVal {
1271 common: ConstantVal {
1272 name: Name::str("Quot"),
1273 level_params: vec![],
1274 ty: mk_type0(),
1275 },
1276 kind: QuotKind::Type,
1277 });
1278 assert!(
1279 check_constant_info(&mut env, quot_ci).is_err(),
1280 "non-canonical quotient type must be rejected"
1281 );
1282 assert!(!env.contains(&Name::str("Quot")));
1283 }
1284 #[test]
1285 fn test_check_constant_infos_sequence() {
1286 use crate::declaration::{AxiomVal, ConstantVal};
1287 let mut env = Environment::new();
1288 let cis = vec![
1289 ConstantInfo::Axiom(AxiomVal {
1290 common: ConstantVal {
1291 name: Name::str("P"),
1292 level_params: vec![],
1293 ty: mk_type0(),
1294 },
1295 is_unsafe: false,
1296 }),
1297 ConstantInfo::Axiom(AxiomVal {
1298 common: ConstantVal {
1299 name: Name::str("Q"),
1300 level_params: vec![],
1301 ty: mk_type0(),
1302 },
1303 is_unsafe: false,
1304 }),
1305 ];
1306 check_constant_infos(&mut env, cis).expect("value should be present");
1307 assert!(env.contains(&Name::str("P")));
1308 assert!(env.contains(&Name::str("Q")));
1309 }
1310 #[test]
1311 fn test_check_constant_info_duplicate() {
1312 use crate::declaration::{AxiomVal, ConstantVal};
1313 let mut env = Environment::new();
1314 let make_ci = || {
1315 ConstantInfo::Axiom(AxiomVal {
1316 common: ConstantVal {
1317 name: Name::str("Dup"),
1318 level_params: vec![],
1319 ty: mk_type0(),
1320 },
1321 is_unsafe: false,
1322 })
1323 };
1324 check_constant_info(&mut env, make_ci()).expect("value should be present");
1325 let result = check_constant_info(&mut env, make_ci());
1326 assert!(result.is_err(), "duplicate should fail");
1327 }
1328}
1329#[cfg(test)]
1330mod tests_padding_infra {
1331 use super::*;
1332 #[test]
1333 fn test_stat_summary() {
1334 let mut ss = StatSummary::new();
1335 ss.record(10.0);
1336 ss.record(20.0);
1337 ss.record(30.0);
1338 assert_eq!(ss.count(), 3);
1339 assert!((ss.mean().expect("mean should succeed") - 20.0).abs() < 1e-9);
1340 assert_eq!(ss.min().expect("min should succeed") as i64, 10);
1341 assert_eq!(ss.max().expect("max should succeed") as i64, 30);
1342 }
1343 #[test]
1344 fn test_transform_stat() {
1345 let mut ts = TransformStat::new();
1346 ts.record_before(100.0);
1347 ts.record_after(80.0);
1348 let ratio = ts.mean_ratio().expect("ratio should be present");
1349 assert!((ratio - 0.8).abs() < 1e-9);
1350 }
1351 #[test]
1352 fn test_small_map() {
1353 let mut m: SmallMap<u32, &str> = SmallMap::new();
1354 m.insert(3, "three");
1355 m.insert(1, "one");
1356 m.insert(2, "two");
1357 assert_eq!(m.get(&2), Some(&"two"));
1358 assert_eq!(m.len(), 3);
1359 let keys = m.keys();
1360 assert_eq!(*keys[0], 1);
1361 assert_eq!(*keys[2], 3);
1362 }
1363 #[test]
1364 fn test_label_set() {
1365 let mut ls = LabelSet::new();
1366 ls.add("foo");
1367 ls.add("bar");
1368 ls.add("foo");
1369 assert_eq!(ls.count(), 2);
1370 assert!(ls.has("bar"));
1371 assert!(!ls.has("baz"));
1372 }
1373 #[test]
1374 fn test_config_node() {
1375 let mut root = ConfigNode::section("root");
1376 let child = ConfigNode::leaf("key", "value");
1377 root.add_child(child);
1378 assert_eq!(root.num_children(), 1);
1379 }
1380 #[test]
1381 fn test_versioned_record() {
1382 let mut vr = VersionedRecord::new(0u32);
1383 vr.update(1);
1384 vr.update(2);
1385 assert_eq!(*vr.current(), 2);
1386 assert_eq!(vr.version(), 2);
1387 assert!(vr.has_history());
1388 assert_eq!(*vr.at_version(0).expect("value should be present"), 0);
1389 }
1390 #[test]
1391 fn test_simple_dag() {
1392 let mut dag = SimpleDag::new(4);
1393 dag.add_edge(0, 1);
1394 dag.add_edge(1, 2);
1395 dag.add_edge(2, 3);
1396 assert!(dag.can_reach(0, 3));
1397 assert!(!dag.can_reach(3, 0));
1398 let order = dag.topological_sort().expect("order should be present");
1399 assert_eq!(order, vec![0, 1, 2, 3]);
1400 }
1401 #[test]
1402 fn test_focus_stack() {
1403 let mut fs: FocusStack<&str> = FocusStack::new();
1404 fs.focus("a");
1405 fs.focus("b");
1406 assert_eq!(fs.current(), Some(&"b"));
1407 assert_eq!(fs.depth(), 2);
1408 fs.blur();
1409 assert_eq!(fs.current(), Some(&"a"));
1410 }
1411}
1412#[cfg(test)]
1413mod tests_extra_iterators {
1414 use super::*;
1415 #[test]
1416 fn test_window_iterator() {
1417 let data = vec![1u32, 2, 3, 4, 5];
1418 let windows: Vec<_> = WindowIterator::new(&data, 3).collect();
1419 assert_eq!(windows.len(), 3);
1420 assert_eq!(windows[0], &[1, 2, 3]);
1421 assert_eq!(windows[2], &[3, 4, 5]);
1422 }
1423 #[test]
1424 fn test_non_empty_vec() {
1425 let mut nev = NonEmptyVec::singleton(10u32);
1426 nev.push(20);
1427 nev.push(30);
1428 assert_eq!(nev.len(), 3);
1429 assert_eq!(*nev.first(), 10);
1430 assert_eq!(*nev.last(), 30);
1431 }
1432}
1433#[cfg(test)]
1434mod tests_padding2 {
1435 use super::*;
1436 #[test]
1437 fn test_sliding_sum() {
1438 let mut ss = SlidingSum::new(3);
1439 ss.push(1.0);
1440 ss.push(2.0);
1441 ss.push(3.0);
1442 assert!((ss.sum() - 6.0).abs() < 1e-9);
1443 ss.push(4.0);
1444 assert!((ss.sum() - 9.0).abs() < 1e-9);
1445 assert_eq!(ss.count(), 3);
1446 }
1447 #[test]
1448 fn test_path_buf() {
1449 let mut pb = PathBuf::new();
1450 pb.push("src");
1451 pb.push("main");
1452 assert_eq!(pb.as_str(), "src/main");
1453 assert_eq!(pb.depth(), 2);
1454 pb.pop();
1455 assert_eq!(pb.as_str(), "src");
1456 }
1457 #[test]
1458 fn test_string_pool() {
1459 let mut pool = StringPool::new();
1460 let s = pool.take();
1461 assert!(s.is_empty());
1462 pool.give("hello".to_string());
1463 let s2 = pool.take();
1464 assert!(s2.is_empty());
1465 assert_eq!(pool.free_count(), 0);
1466 }
1467 #[test]
1468 fn test_transitive_closure() {
1469 let mut tc = TransitiveClosure::new(4);
1470 tc.add_edge(0, 1);
1471 tc.add_edge(1, 2);
1472 tc.add_edge(2, 3);
1473 assert!(tc.can_reach(0, 3));
1474 assert!(!tc.can_reach(3, 0));
1475 let r = tc.reachable_from(0);
1476 assert_eq!(r.len(), 4);
1477 }
1478 #[test]
1479 fn test_token_bucket() {
1480 let mut tb = TokenBucket::new(100, 0);
1481 assert_eq!(tb.available(), 100);
1482 assert!(tb.try_consume(50));
1483 assert_eq!(tb.available(), 50);
1484 assert!(!tb.try_consume(60));
1485 assert_eq!(tb.capacity(), 100);
1486 }
1487 #[test]
1488 fn test_rewrite_rule_set() {
1489 let mut rrs = RewriteRuleSet::new();
1490 rrs.add(RewriteRule::unconditional(
1491 "beta",
1492 "App(Lam(x, b), v)",
1493 "b[x:=v]",
1494 ));
1495 rrs.add(RewriteRule::conditional("comm", "a + b", "b + a"));
1496 assert_eq!(rrs.len(), 2);
1497 assert_eq!(rrs.unconditional_rules().len(), 1);
1498 assert_eq!(rrs.conditional_rules().len(), 1);
1499 assert!(rrs.get("beta").is_some());
1500 let disp = rrs
1501 .get("beta")
1502 .expect("element at \'beta\' should exist")
1503 .display();
1504 assert!(disp.contains("→"));
1505 }
1506}
1507#[cfg(test)]
1508mod tests_padding3 {
1509 use super::*;
1510 #[test]
1511 fn test_decision_node() {
1512 let tree = DecisionNode::Branch {
1513 key: "x".into(),
1514 val: "1".into(),
1515 yes_branch: Box::new(DecisionNode::Leaf("yes".into())),
1516 no_branch: Box::new(DecisionNode::Leaf("no".into())),
1517 };
1518 let mut ctx = std::collections::HashMap::new();
1519 ctx.insert("x".into(), "1".into());
1520 assert_eq!(tree.evaluate(&ctx), "yes");
1521 ctx.insert("x".into(), "2".into());
1522 assert_eq!(tree.evaluate(&ctx), "no");
1523 assert_eq!(tree.depth(), 1);
1524 }
1525 #[test]
1526 fn test_flat_substitution() {
1527 let mut sub = FlatSubstitution::new();
1528 sub.add("foo", "bar");
1529 sub.add("baz", "qux");
1530 assert_eq!(sub.apply("foo and baz"), "bar and qux");
1531 assert_eq!(sub.len(), 2);
1532 }
1533 #[test]
1534 fn test_stopwatch() {
1535 let mut sw = Stopwatch::start();
1536 sw.split();
1537 sw.split();
1538 assert_eq!(sw.num_splits(), 2);
1539 assert!(sw.elapsed_ms() >= 0.0);
1540 for &s in sw.splits() {
1541 assert!(s >= 0.0);
1542 }
1543 }
1544 #[test]
1545 fn test_either2() {
1546 let e: Either2<i32, &str> = Either2::First(42);
1547 assert!(e.is_first());
1548 let mapped = e.map_first(|x| x * 2);
1549 assert_eq!(mapped.first(), Some(84));
1550 let e2: Either2<i32, &str> = Either2::Second("hello");
1551 assert!(e2.is_second());
1552 assert_eq!(e2.second(), Some("hello"));
1553 }
1554 #[test]
1555 fn test_write_once() {
1556 let wo: WriteOnce<u32> = WriteOnce::new();
1557 assert!(!wo.is_written());
1558 assert!(wo.write(42));
1559 assert!(!wo.write(99));
1560 assert_eq!(wo.read(), Some(42));
1561 }
1562 #[test]
1563 fn test_sparse_vec() {
1564 let mut sv: SparseVec<i32> = SparseVec::new(100);
1565 sv.set(5, 10);
1566 sv.set(50, 20);
1567 assert_eq!(*sv.get(5), 10);
1568 assert_eq!(*sv.get(50), 20);
1569 assert_eq!(*sv.get(0), 0);
1570 assert_eq!(sv.nnz(), 2);
1571 sv.set(5, 0);
1572 assert_eq!(sv.nnz(), 1);
1573 }
1574 #[test]
1575 fn test_stack_calc() {
1576 let mut calc = StackCalc::new();
1577 calc.push(3);
1578 calc.push(4);
1579 assert_eq!(calc.add(), Some(7));
1580 assert_eq!(calc.peek(), Some(7));
1581 calc.push(2);
1582 assert_eq!(calc.mul(), Some(14));
1583 assert_eq!(calc.peek(), Some(14));
1584 }
1585}