diff --git a/README.md b/README.md index d3cb42d4..e5f8bb06 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ cd hvm-lang Install using cargo: ```bash -cargo install --path . +cargo install --path . --locked ``` ## Usage diff --git a/justfile b/justfile index 990bc091..39113726 100644 --- a/justfile +++ b/justfile @@ -26,9 +26,3 @@ audit: install: cargo install --locked cargo-sort cargo-audit - -llcheck: - cargo watch -x llcheck - -extras: - cargo install --locked cargo-watch cargo-limit amber diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 3c60825e..593c2658 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,16 +1,4 @@ -use crate::term::{ - check::{ - repeated_bind::RepeatedBindWarn, set_entrypoint::EntryErr, shared_names::TopLevelErr, - unbound_pats::UnboundCtrErr, unbound_vars::UnboundVarErr, - }, - display::DisplayFn, - transform::{ - apply_args::PatternArgError, encode_pattern_matching::MatchErr, resolve_refs::ReferencedMainErr, - simplify_ref_to_ref::CyclicDefErr, - }, - Name, -}; -use itertools::Itertools; +use crate::term::{display::DisplayFn, Name}; use std::{ collections::BTreeMap, fmt::{Display, Formatter}, @@ -19,40 +7,129 @@ use std::{ pub const ERR_INDENT_SIZE: usize = 2; #[derive(Debug, Clone, Default)] -pub struct Info { +pub struct Diagnostics { err_counter: usize, - book_errs: Vec, - rule_errs: BTreeMap>, - pub warns: Warnings, + pub diagnostics: BTreeMap>, + config: DiagnosticsConfig, } -impl Info { - pub fn error>(&mut self, e: E) { - self.err_counter += 1; - self.book_errs.push(e.into()) +#[derive(Debug, Clone, Copy)] +pub struct DiagnosticsConfig { + pub verbose: bool, + pub match_only_vars: Severity, + pub unused_definition: Severity, + pub repeated_bind: Severity, + pub mutual_recursion_cycle: Severity, +} + +#[derive(Debug, Clone)] +pub struct Diagnostic { + message: String, + severity: Severity, +} + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum DiagnosticOrigin { + /// An error from the relationship between multiple top-level definitions. + Book, + /// An error in a pattern-matching function definition rule. + Rule(Name), + /// An error in a compiled inet. + Inet(String), + /// An error during readback of hvm-core run results. + Readback, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Severity { + Error, + Warning, + Allow, +} + +#[derive(Debug, Clone, Copy)] +pub enum WarningType { + MatchOnlyVars, + UnusedDefinition, + RepeatedBind, + MutualRecursionCycle, +} + +pub trait ToStringVerbose { + fn to_string_verbose(&self, verbose: bool) -> String; +} + +impl Diagnostics { + pub fn new(config: DiagnosticsConfig) -> Self { + Self { err_counter: 0, diagnostics: Default::default(), config } } - pub fn def_error>(&mut self, name: Name, e: E) { + pub fn add_book_error(&mut self, err: impl ToStringVerbose) { self.err_counter += 1; - let entry = self.rule_errs.entry(name).or_default(); - entry.push(e.into()); + self.add_diagnostic(err, Severity::Error, DiagnosticOrigin::Book); } - pub fn take_err>(&mut self, result: Result, def_name: Option<&Name>) -> Option { + pub fn add_rule_error(&mut self, err: impl ToStringVerbose, def_name: Name) { + self.err_counter += 1; + self.add_diagnostic(err, Severity::Error, DiagnosticOrigin::Rule(def_name)); + } + + pub fn add_inet_error(&mut self, err: impl ToStringVerbose, def_name: String) { + self.err_counter += 1; + self.add_diagnostic(err, Severity::Error, DiagnosticOrigin::Inet(def_name)); + } + + pub fn add_rule_warning(&mut self, warn: impl ToStringVerbose, warn_type: WarningType, def_name: Name) { + let severity = self.config.warning_severity(warn_type); + if severity == Severity::Error { + self.err_counter += 1; + } + self.add_diagnostic(warn, severity, DiagnosticOrigin::Rule(def_name)); + } + + pub fn add_book_warning(&mut self, warn: impl ToStringVerbose, warn_type: WarningType) { + let severity = self.config.warning_severity(warn_type); + if severity == Severity::Error { + self.err_counter += 1; + } + self.add_diagnostic(warn, severity, DiagnosticOrigin::Book); + } + + pub fn add_diagnostic(&mut self, msg: impl ToStringVerbose, severity: Severity, orig: DiagnosticOrigin) { + let diag = Diagnostic { message: msg.to_string_verbose(self.config.verbose), severity }; + self.diagnostics.entry(orig).or_default().push(diag) + } + + pub fn take_rule_err(&mut self, result: Result, def_name: Name) -> Option { match result { Ok(t) => Some(t), Err(e) => { - match def_name { - None => self.error(e), - Some(def) => self.def_error(def.clone(), e), - } + self.add_rule_error(e, def_name); None } } } + pub fn take_inet_err( + &mut self, + result: Result, + def_name: String, + ) -> Option { + match result { + Ok(t) => Some(t), + Err(e) => { + self.add_inet_error(e, def_name); + None + } + } + } + + pub fn has_severity(&self, severity: Severity) -> bool { + self.diagnostics.values().any(|errs| errs.iter().any(|e| e.severity == severity)) + } + pub fn has_errors(&self) -> bool { - !(self.book_errs.is_empty() && self.rule_errs.is_empty()) + self.has_severity(Severity::Error) } /// Resets the internal counter @@ -63,172 +140,129 @@ impl Info { /// Checks if any error was emitted since the start of the pass, /// Returning all the current information as a `Err(Info)`, replacing `&mut self` with an empty one. /// Otherwise, returns the given arg as an `Ok(T)`. - pub fn fatal(&mut self, t: T) -> Result { + pub fn fatal(&mut self, t: T) -> Result { if self.err_counter == 0 { Ok(t) } else { Err(std::mem::take(self)) } } - pub fn warning>(&mut self, def_name: Name, warning: W) { - self.warns.0.entry(def_name).or_default().push(warning.into()); - } - - pub fn display(&self, verbose: bool) -> impl Display + '_ { + /// Returns a Display that prints the diagnostics with one of the given severities. + pub fn display_with_severity(&self, severity: Severity) -> impl std::fmt::Display + '_ { DisplayFn(move |f| { - writeln!(f, "{}", self.book_errs.iter().map(|err| err.display(verbose)).join("\n"))?; - - for (def_name, errs) in &self.rule_errs { - in_definition(def_name, f)?; - for err in errs { - writeln!(f, "{:ERR_INDENT_SIZE$}{}", "", err.display(verbose))?; - } + fn filter<'a>( + errs: impl IntoIterator, + severity: Severity, + ) -> impl Iterator { + errs.into_iter().filter(move |err| err.severity == severity) } + let mut has_msg = false; + for (orig, errs) in &self.diagnostics { + let mut errs = filter(errs, severity).peekable(); + if errs.peek().is_some() { + match orig { + DiagnosticOrigin::Book => { + for err in errs { + writeln!(f, "{err}")?; + } + } + DiagnosticOrigin::Rule(nam) => { + writeln!(f, "In definition '{nam}':")?; + for err in errs { + writeln!(f, "{:ERR_INDENT_SIZE$}{err}", "")?; + } + } + DiagnosticOrigin::Inet(nam) => { + writeln!(f, "In compiled inet '{nam}':")?; + for err in errs { + writeln!(f, "{:ERR_INDENT_SIZE$}{err}", "")?; + } + } + DiagnosticOrigin::Readback => { + writeln!(f, "During readback:")?; + for err in errs { + writeln!(f, "{:ERR_INDENT_SIZE$}{err}", "")?; + } + } + } + has_msg = true; + } + } + if has_msg { + writeln!(f)?; + } Ok(()) }) } } -fn in_definition(def_name: &Name, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - writeln!(f, "In definition '{def_name}':") -} - -impl Display for Info { +impl Display for Diagnostics { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.display(false)) - } -} - -impl From for Info { - fn from(value: String) -> Self { - Info { book_errs: vec![Error::Custom(value)], ..Default::default() } - } -} - -impl From<&str> for Info { - fn from(value: &str) -> Self { - Info::from(value.to_string()) - } -} - -#[derive(Debug, Clone)] -pub enum Error { - MainRef(ReferencedMainErr), - Match(MatchErr), - UnboundVar(UnboundVarErr), - UnboundCtr(UnboundCtrErr), - Cyclic(CyclicDefErr), - EntryPoint(EntryErr), - TopLevel(TopLevelErr), - Custom(String), - PatternArgError(PatternArgError), - RepeatedBind(RepeatedBindWarn), -} - -impl Display for Error { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.display(false)) - } -} - -impl Error { - pub fn display(&self, verbose: bool) -> impl Display + '_ { - DisplayFn(move |f| match self { - Error::Match(err) => write!(f, "{}", err.display(verbose)), - Error::UnboundVar(err) => write!(f, "{err}"), - Error::UnboundCtr(err) => write!(f, "{err}"), - Error::MainRef(err) => write!(f, "{err}"), - Error::Cyclic(err) => write!(f, "{err}"), - Error::EntryPoint(err) => write!(f, "{err}"), - Error::TopLevel(err) => write!(f, "{err}"), - Error::Custom(err) => write!(f, "{err}"), - Error::PatternArgError(err) => write!(f, "{err}"), - Error::RepeatedBind(err) => write!(f, "{err}"), - }) - } -} - -impl From for Error { - fn from(value: ReferencedMainErr) -> Self { - Self::MainRef(value) - } -} - -impl From for Error { - fn from(value: MatchErr) -> Self { - Self::Match(value) - } -} - -impl From for Error { - fn from(value: UnboundVarErr) -> Self { - Self::UnboundVar(value) - } -} - -impl From for Error { - fn from(value: UnboundCtrErr) -> Self { - Self::UnboundCtr(value) - } -} - -impl From for Error { - fn from(value: CyclicDefErr) -> Self { - Self::Cyclic(value) - } -} - -impl From for Error { - fn from(value: EntryErr) -> Self { - Self::EntryPoint(value) - } -} - -impl From for Error { - fn from(value: TopLevelErr) -> Self { - Self::TopLevel(value) - } -} - -impl From for Error { - fn from(value: PatternArgError) -> Self { - Self::PatternArgError(value) - } -} - -#[derive(Debug, Clone, Default)] -pub struct Warnings(pub BTreeMap>); - -#[derive(Debug, Clone)] -pub enum WarningType { - MatchOnlyVars, - UnusedDefinition, - RepeatedBind(RepeatedBindWarn), -} - -impl Display for WarningType { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - WarningType::MatchOnlyVars => write!(f, "Match expression at definition only uses var patterns."), - WarningType::UnusedDefinition => write!(f, "Definition is unused."), - WarningType::RepeatedBind(warn) => write!(f, "{warn}"), + if self.has_severity(Severity::Warning) { + write!(f, "Warnings:\n{}", self.display_with_severity(Severity::Warning))?; } - } -} - -impl Display for Warnings { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - for (def_name, warns) in &self.0 { - in_definition(def_name, f)?; - for warn in warns { - writeln!(f, "{:ERR_INDENT_SIZE$}{}", "", warn)?; - } + if self.has_severity(Severity::Error) { + write!(f, "Errors:\n{}", self.display_with_severity(Severity::Error))?; } - Ok(()) } } -impl From for WarningType { - fn from(value: RepeatedBindWarn) -> Self { - Self::RepeatedBind(value) +impl From for Diagnostics { + fn from(value: String) -> Self { + Self { + diagnostics: BTreeMap::from_iter([(DiagnosticOrigin::Book, vec![Diagnostic { + message: value, + severity: Severity::Error, + }])]), + ..Default::default() + } + } +} + +impl DiagnosticsConfig { + pub fn new(severity: Severity, verbose: bool) -> Self { + Self { + match_only_vars: severity, + unused_definition: severity, + repeated_bind: severity, + mutual_recursion_cycle: severity, + verbose, + } + } + + pub fn warning_severity(&self, warn: WarningType) -> Severity { + match warn { + WarningType::MatchOnlyVars => self.match_only_vars, + WarningType::UnusedDefinition => self.unused_definition, + WarningType::RepeatedBind => self.repeated_bind, + WarningType::MutualRecursionCycle => self.mutual_recursion_cycle, + } + } +} + +impl Default for DiagnosticsConfig { + fn default() -> Self { + Self::new(Severity::Warning, false) + } +} + +impl Diagnostic { + pub fn error(msg: impl ToString) -> Self { + Diagnostic { message: msg.to_string(), severity: Severity::Error } + } + + pub fn warning(msg: impl ToString) -> Self { + Diagnostic { message: msg.to_string(), severity: Severity::Warning } + } +} + +impl Display for Diagnostic { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.message) + } +} + +impl ToStringVerbose for &str { + fn to_string_verbose(&self, _verbose: bool) -> String { + self.to_string() } } diff --git a/src/hvmc_net/mutual_recursion.rs b/src/hvmc_net/mutual_recursion.rs index 2c7af96e..dbacb819 100644 --- a/src/hvmc_net/mutual_recursion.rs +++ b/src/hvmc_net/mutual_recursion.rs @@ -1,3 +1,4 @@ +use crate::diagnostics::{Diagnostics, WarningType, ERR_INDENT_SIZE}; use hvmc::ast::{Book, Tree}; use indexmap::{IndexMap, IndexSet}; use std::fmt::Debug; @@ -9,21 +10,27 @@ type RefSet = IndexSet; #[derive(Default)] pub struct Graph(IndexMap); -pub fn check_cycles(book: &Book) -> Result<(), String> { +pub fn check_cycles(book: &Book, diagnostics: &mut Diagnostics) -> Result<(), Diagnostics> { + diagnostics.start_pass(); + let graph = Graph::from(book); let cycles = graph.cycles(); - if cycles.is_empty() { - Ok(()) - } else { - Err(format!( - "{}\n{}\n{}\n{}", + if !cycles.is_empty() { + let msg = format!( + "{}\n{}\n{:ERR_INDENT_SIZE$}{}\n{:ERR_INDENT_SIZE$}{}", "Mutual recursion cycle detected in compiled functions:", pretty_print_cycles(&cycles), + "", "This program will expand infinitely in strict evaluation mode.", + "", "Read https://github.com/HigherOrderCO/hvm-lang/blob/main/docs/lazy-definitions.md for more information." - )) + ); + + diagnostics.add_book_warning(msg.as_str(), WarningType::MutualRecursionCycle); } + + diagnostics.fatal(()) } fn pretty_print_cycles(cycles: &[Vec]) -> String { @@ -32,7 +39,7 @@ fn pretty_print_cycles(cycles: &[Vec]) -> String { .enumerate() .map(|(i, cycle)| { let cycle_str = cycle.iter().chain(cycle.first()).cloned().collect::>().join(" -> "); - format!("Cycle {}: {}", 1 + i, cycle_str) + format!("{:ERR_INDENT_SIZE$}Cycle {}: {}", "", 1 + i, cycle_str) }) .collect::>() .join("\n") diff --git a/src/lib.rs b/src/lib.rs index 9f48321f..d6422a48 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![feature(box_patterns)] #![feature(let_chains)] -use diagnostics::{Info, WarningType, Warnings}; +use diagnostics::{DiagnosticOrigin, Diagnostics, DiagnosticsConfig, Severity}; use hvmc::{ ast::{self, Net}, dispatch_dyn_net, @@ -16,10 +16,7 @@ use std::{ sync::{Arc, Mutex}, time::Instant, }; -use term::{ - book_to_nets, display::display_readback_errors, net_to_term::net_to_term, term_to_net::Labels, AdtEncoding, - Book, Ctx, ReadbackError, Term, -}; +use term::{book_to_nets, net_to_term::net_to_term, term_to_net::Labels, AdtEncoding, Book, Ctx, Term}; pub mod diagnostics; pub mod hvmc_net; @@ -52,7 +49,8 @@ pub fn create_host(book: Arc, labels: Arc, adt_encoding: AdtEncodi let tree = host.readback_tree(&wire); let net = hvmc::ast::Net { root: tree, redexes: vec![] }; let (term, errs) = readback_hvmc(&net, &book, &labels, false, adt_encoding); - println!("{}{}", display_readback_errors(&errs), term); + eprint!("{errs}"); + println!("{term}"); } }))), ); @@ -79,37 +77,42 @@ pub fn create_host(book: Arc, labels: Arc, adt_encoding: AdtEncodi host } -pub fn check_book(book: &mut Book) -> Result<(), Info> { +pub fn check_book(book: &mut Book) -> Result<(), Diagnostics> { // TODO: Do the checks without having to do full compilation - // TODO: Shouldn't the check mode show warnings? - compile_book(book, true, CompileOpts::light(), None)?; + let res = compile_book(book, CompileOpts::light(), DiagnosticsConfig::new(Severity::Warning, false), None)?; + print!("{}", res.diagnostics); Ok(()) } pub fn compile_book( book: &mut Book, - lazy_mode: bool, opts: CompileOpts, + diagnostics_cfg: DiagnosticsConfig, args: Option>, -) -> Result { - let warns = desugar_book(book, opts, args)?; +) -> Result { + let mut diagnostics = desugar_book(book, opts, diagnostics_cfg, args)?; let (nets, labels) = book_to_nets(book); - let mut core_book = nets_to_hvmc(nets)?; + let mut core_book = nets_to_hvmc(nets, &mut diagnostics)?; + if opts.pre_reduce { core_book.pre_reduce(&|x| x == book.hvmc_entrypoint(), 1 << 24, 100_000)?; } if opts.prune { prune_defs(&mut core_book, book.hvmc_entrypoint().to_string()); } - if !lazy_mode { - mutual_recursion::check_cycles(&core_book)?; - } - Ok(CompileResult { core_book, labels, warns }) + mutual_recursion::check_cycles(&core_book, &mut diagnostics)?; + + Ok(CompileResult { core_book, labels, diagnostics }) } -pub fn desugar_book(book: &mut Book, opts: CompileOpts, args: Option>) -> Result { - let mut ctx = Ctx::new(book); +pub fn desugar_book( + book: &mut Book, + opts: CompileOpts, + diagnostics_cfg: DiagnosticsConfig, + args: Option>, +) -> Result { + let mut ctx = Ctx::new(book, diagnostics_cfg); ctx.check_shared_names(); ctx.set_entrypoint(); @@ -136,7 +139,7 @@ pub fn desugar_book(book: &mut Book, opts: CompileOpts, args: Option>) ctx.simplify_matches()?; if opts.linearize_matches.enabled() { - ctx.linearize_simple_matches(opts.linearize_matches.is_extra())?; + ctx.book.linearize_simple_matches(opts.linearize_matches.is_extra()); } ctx.book.encode_simple_matches(opts.adt_encoding); @@ -173,19 +176,24 @@ pub fn desugar_book(book: &mut Book, opts: CompileOpts, args: Option>) ctx.book.merge_definitions(); } - if !ctx.info.has_errors() { Ok(ctx.info.warns) } else { Err(ctx.info) } + if !ctx.info.has_errors() { Ok(ctx.info) } else { Err(ctx.info) } } pub fn run_book( mut book: Book, - mem_size: usize, + max_memory: usize, run_opts: RunOpts, - warning_opts: WarningOpts, compile_opts: CompileOpts, + diagnostics_cfg: DiagnosticsConfig, args: Option>, -) -> Result<(Term, RunInfo), Info> { - let CompileResult { core_book, labels, warns } = - compile_book(&mut book, run_opts.lazy_mode, compile_opts, args)?; +) -> Result<(Term, RunInfo), Diagnostics> { + let CompileResult { core_book, labels, diagnostics } = + compile_book(&mut book, compile_opts, diagnostics_cfg, args)?; + + // TODO: Printing should be taken care by the cli module, but we'd + // like to print any warnings before running so that the user can + // cancel the run if a problem is detected. + eprint!("{diagnostics}"); // Turn the book into an Arc so that we can use it for logging, debugging, etc. // from anywhere else in the program @@ -193,19 +201,17 @@ pub fn run_book( let book = Arc::new(book); let labels = Arc::new(labels); - display_warnings(warns, warning_opts)?; - // Run let debug_hook = run_opts.debug_hook(&book, &labels); let host = create_host(book.clone(), labels.clone(), compile_opts.adt_encoding); host.lock().unwrap().insert_book(&core_book); - let (res_lnet, stats) = run_compiled(host, mem_size, run_opts, debug_hook, book.hvmc_entrypoint()); + let (res_lnet, stats) = run_compiled(host, max_memory, run_opts, debug_hook, book.hvmc_entrypoint()); - let (res_term, readback_errors) = + let (res_term, diagnostics) = readback_hvmc(&res_lnet, &book, &labels, run_opts.linear, compile_opts.adt_encoding); - let info = RunInfo { stats, readback_errors, net: res_lnet, book, labels }; + let info = RunInfo { stats, diagnostics, net: res_lnet, book, labels }; Ok((res_term, info)) } @@ -252,7 +258,7 @@ pub fn run_compiled( ) -> (Net, RunStats) { let heap = Heap::new_bytes(mem_size); let mut root = DynNet::new(&heap, run_opts.lazy_mode); - let max_rwts = run_opts.max_rewrites.map(|x| x.clamp(usize::MIN as u64, usize::MAX as u64) as usize); + let max_rwts = run_opts.max_rewrites.map(|x| x.clamp(usize::MIN, usize::MAX)); // Expect won't be reached because there's // a pass that checks this. dispatch_dyn_net!(&mut root => { @@ -309,16 +315,19 @@ pub fn readback_hvmc( labels: &Arc, linear: bool, adt_encoding: AdtEncoding, -) -> (Term, Vec) { +) -> (Term, Diagnostics) { + let mut diags = Diagnostics::default(); let net = hvmc_to_net(net); - let (mut term, mut readback_errors) = net_to_term(&net, book, labels, linear); + let mut term = net_to_term(&net, book, labels, linear, &mut diags); let resugar_errs = term.resugar_adts(book, adt_encoding); term.resugar_builtins(); - readback_errors.extend(resugar_errs); + for err in resugar_errs { + diags.add_diagnostic(err, Severity::Warning, DiagnosticOrigin::Readback); + } - (term, readback_errors) + (term, diags) } #[derive(Clone, Copy, Debug, Default)] @@ -327,8 +336,8 @@ pub struct RunOpts { pub debug: bool, pub linear: bool, pub lazy_mode: bool, - pub max_memory: u64, - pub max_rewrites: Option, + pub max_memory: usize, + pub max_rewrites: Option, } impl RunOpts { @@ -340,8 +349,10 @@ impl RunOpts { self.debug.then_some({ |net: &_| { let net = hvmc_to_net(net); - let (res_term, errors) = net_to_term(&net, book, labels, self.linear); - println!("{}{}\n---------------------------------------", display_readback_errors(&errors), res_term,) + let mut diags = Diagnostics::default(); + let res_term = net_to_term(&net, book, labels, self.linear, &mut diags); + eprint!("{diags}"); + println!("{}\n---------------------------------------", res_term); } }) } @@ -457,101 +468,15 @@ impl CompileOpts { } } -#[derive(Default, Clone, Copy)] -pub struct WarningOpts { - pub match_only_vars: WarnState, - pub unused_defs: WarnState, - pub repeated_bind: WarnState, -} - -#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum WarnState { - #[default] - Warn, - Allow, - Deny, -} - -impl WarningOpts { - pub fn allow_all() -> Self { - Self { match_only_vars: WarnState::Allow, unused_defs: WarnState::Allow, repeated_bind: WarnState::Allow } - } - - pub fn deny_all() -> Self { - Self { match_only_vars: WarnState::Deny, unused_defs: WarnState::Deny, repeated_bind: WarnState::Deny } - } - - pub fn warn_all() -> Self { - Self { match_only_vars: WarnState::Warn, unused_defs: WarnState::Warn, repeated_bind: WarnState::Warn } - } - - /// Split warnings into two based on its Warn or Deny WarnState. - pub fn split(&self, warns: Warnings) -> (Warnings, Warnings) { - let mut warn = Warnings::default(); - let mut deny = Warnings::default(); - - warns - .0 - .into_iter() - .flat_map(|(def, warns)| warns.into_iter().map(move |warn| (def.clone(), warn))) - .for_each(|(def, w)| { - let ws = match w { - WarningType::MatchOnlyVars => self.match_only_vars, - WarningType::UnusedDefinition => self.unused_defs, - WarningType::RepeatedBind(_) => self.repeated_bind, - }; - - match ws { - WarnState::Allow => {} - WarnState::Warn => warn.0.entry(def).or_default().push(w), - WarnState::Deny => deny.0.entry(def).or_default().push(w), - }; - }); - - (warn, deny) - } -} - -/// Either just prints warnings or returns Err when any denied was produced. -pub fn display_warnings(warnings: Warnings, warning_opts: WarningOpts) -> Result<(), String> { - let (warns, denies) = warning_opts.split(warnings); - - if !warns.0.is_empty() { - eprintln!("Warnings:\n{}", warns); - } - - if !denies.0.is_empty() { - return Err(format!("{denies}\nCould not run the code because of the previous warnings.")); - } - - Ok(()) -} - pub struct CompileResult { - pub warns: Warnings, + pub diagnostics: Diagnostics, pub core_book: hvmc::ast::Book, pub labels: Labels, } -impl std::fmt::Debug for CompileResult { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if !self.warns.0.is_empty() { - writeln!(f, "// Warnings:\n{}", self.warns)?; - } - write!(f, "{}", self.core_book) - } -} - -impl CompileResult { - pub fn display_with_warns(self, opts: WarningOpts) -> Result { - display_warnings(self.warns, opts)?; - Ok(self.core_book.to_string()) - } -} - pub struct RunInfo { pub stats: RunStats, - pub readback_errors: Vec, + pub diagnostics: Diagnostics, pub net: Net, pub book: Arc, pub labels: Arc, diff --git a/src/main.rs b/src/main.rs index aa1473d1..589c4d23 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,12 @@ use clap::{Args, CommandFactory, Parser, Subcommand}; use hvml::{ check_book, compile_book, desugar_book, - diagnostics::Info, + diagnostics::{Diagnostics, DiagnosticsConfig, Severity}, load_file_to_book, run_book, - term::{display::display_readback_errors, AdtEncoding, Book, Name}, - CompileOpts, OptLevel, RunInfo, RunOpts, WarnState, WarningOpts, -}; -use std::{ - path::{Path, PathBuf}, - vec::IntoIter, + term::{AdtEncoding, Book, Name}, + CompileOpts, OptLevel, RunInfo, RunOpts, }; +use std::path::{Path, PathBuf}; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -54,10 +51,10 @@ enum Mode { /// Compiles the program and runs it with the hvm. Run { #[arg(short = 'm', long = "mem", help = "How much memory to allocate for the runtime", default_value = "1G", value_parser = mem_parser)] - max_mem: u64, + max_memory: usize, #[arg(short = 'r', long = "rwts", help = "Maximum amount of rewrites", value_parser = mem_parser)] - max_rwts: Option, + max_rewrites: Option, #[arg(short = 'd', help = "Debug mode (print each reduction step)")] debug: bool, @@ -98,9 +95,6 @@ enum Mode { }, /// Runs the lambda-term level desugaring passes. Desugar { - #[arg(short = 'L', help = "Lazy mode")] - lazy_mode: bool, - #[arg( short = 'O', value_delimiter = ' ', @@ -110,6 +104,12 @@ enum Mode { )] comp_opts: Vec, + #[arg(short = 'L', help = "Lazy mode")] + lazy_mode: bool, + + #[command(flatten)] + warn_opts: CliWarnOpts, + #[arg(help = "Path to the input file")] path: PathBuf, }, @@ -146,149 +146,6 @@ struct CliWarnOpts { pub allows: Vec, } -fn mem_parser(arg: &str) -> Result { - let (base, mult) = match arg.to_lowercase().chars().last() { - None => return Err("Mem size argument is empty".to_string()), - Some('k') => (&arg[0 .. arg.len() - 1], 1 << 10), - Some('m') => (&arg[0 .. arg.len() - 1], 1 << 20), - Some('g') => (&arg[0 .. arg.len() - 1], 1 << 30), - Some(_) => (arg, 1), - }; - let base = base.parse::().map_err(|e| e.to_string())?; - Ok(base * mult) -} - -fn main() { - #[cfg(not(feature = "cli"))] - compile_error!("The 'cli' feature is needed for the hvm-lang cli"); - - let cli = Cli::parse(); - let arg_verbose = cli.verbose; - - if let Err(e) = execute_cli_mode(cli) { - eprintln!("{}", e.display(arg_verbose)) - } -} - -fn execute_cli_mode(mut cli: Cli) -> Result<(), Info> { - let arg_verbose = cli.verbose; - let entrypoint = cli.entrypoint.take(); - - let load_book = |path: &Path| -> Result { - let mut book = load_file_to_book(path).map_err(Info::from)?; - book.entrypoint = entrypoint; - - if arg_verbose { - println!("{book}"); - } - - Ok(book) - }; - - match cli.mode { - Mode::Check { path } => { - let mut book = load_book(&path)?; - check_book(&mut book)?; - } - Mode::Compile { path, comp_opts, warn_opts, lazy_mode } => { - let warning_opts = warn_opts.get_warning_opts(WarningOpts::default()); - let mut opts = OptArgs::opts_from_cli(&comp_opts); - - if lazy_mode { - opts.lazy_mode(); - } - - let mut book = load_book(&path)?; - let compiled = compile_book(&mut book, lazy_mode, opts, None)?; - println!("{}", compiled.display_with_warns(warning_opts)?); - } - Mode::Desugar { path, comp_opts, lazy_mode } => { - let mut opts = OptArgs::opts_from_cli(&comp_opts); - if lazy_mode { - opts.lazy_mode(); - } - let mut book = load_book(&path)?; - // TODO: Shouldn't the desugar have `warn_opts` too? maybe WarningOpts::allow_all() by default - let _warns = desugar_book(&mut book, opts, None)?; - println!("{}", book); - } - Mode::Run { - path, - max_mem, - max_rwts, - debug, - mut single_core, - linear, - arg_stats, - comp_opts, - warn_opts, - lazy_mode, - arguments, - } => { - if debug && lazy_mode { - return Err("Unsupported configuration, can not use debug mode `-d` with lazy mode `-L`".into()); - } - - let warning_opts = warn_opts.get_warning_opts(WarningOpts::allow_all()); - let mut opts = OptArgs::opts_from_cli(&comp_opts); - opts.check(lazy_mode); - - if lazy_mode { - single_core = true; - opts.lazy_mode(); - } - - let book = load_book(&path)?; - - let run_opts = - RunOpts { single_core, debug, linear, lazy_mode, max_memory: max_mem, max_rewrites: max_rwts }; - let (res_term, RunInfo { stats, readback_errors, net, book: _, labels: _ }) = - run_book(book, max_mem as usize, run_opts, warning_opts, opts, arguments)?; - - let total_rewrites = stats.rewrites.total() as f64; - let rps = total_rewrites / stats.run_time / 1_000_000.0; - let size = stats.used; - - if cli.verbose { - println!("\n{}", net); - } - - println!("{}{}", display_readback_errors(&readback_errors), res_term); - - if arg_stats { - println!("\nRWTS : {}", total_rewrites); - println!("- ANNI : {}", stats.rewrites.anni); - println!("- COMM : {}", stats.rewrites.comm); - println!("- ERAS : {}", stats.rewrites.eras); - println!("- DREF : {}", stats.rewrites.dref); - println!("- OPER : {}", stats.rewrites.oper); - println!("TIME : {:.3} s", stats.run_time); - println!("RPS : {:.3} m", rps); - println!("SIZE : {} nodes", size); - } - } - }; - Ok(()) -} - -impl CliWarnOpts { - fn get_warning_opts(self, mut warning_opts: WarningOpts) -> WarningOpts { - let cmd = Cli::command(); - let matches = cmd.get_matches(); - - let subcmd_name = matches.subcommand_name().expect("To have a subcommand"); - let arg_matches = matches.subcommand_matches(subcmd_name).expect("To have a subcommand"); - - if let Some(wopts_id_seq) = arg_matches.get_many::("CliWarnOpts") { - let allows = &mut self.allows.into_iter(); - let denies = &mut self.denies.into_iter(); - let warns = &mut self.warns.into_iter(); - WarningArgs::wopts_from_cli(&mut warning_opts, wopts_id_seq.collect(), allows, denies, warns); - } - warning_opts - } -} - #[derive(clap::ValueEnum, Clone, Debug)] pub enum OptArgs { All, @@ -358,31 +215,195 @@ pub enum WarningArgs { All, UnusedDefs, MatchOnlyVars, + RepeatedBind, + MutualRecursionCycle, } -impl WarningArgs { - pub fn wopts_from_cli( - wopts: &mut WarningOpts, - wopts_id_seq: Vec<&clap::Id>, - allows: &mut IntoIter, - denies: &mut IntoIter, - warns: &mut IntoIter, - ) { - for id in wopts_id_seq { +fn main() { + #[cfg(not(feature = "cli"))] + compile_error!("The 'cli' feature is needed for the hvm-lang cli"); + + let cli = Cli::parse(); + + if let Err(diagnostics) = execute_cli_mode(cli) { + eprint!("{diagnostics}") + } +} + +fn execute_cli_mode(mut cli: Cli) -> Result<(), Diagnostics> { + let arg_verbose = cli.verbose; + let entrypoint = cli.entrypoint.take(); + + let load_book = |path: &Path| -> Result { + let mut book = load_file_to_book(path)?; + book.entrypoint = entrypoint; + + if arg_verbose { + println!("{book}"); + } + + Ok(book) + }; + + match cli.mode { + Mode::Check { path } => { + let mut book = load_book(&path)?; + check_book(&mut book)?; + } + Mode::Compile { path, comp_opts, warn_opts, lazy_mode } => { + let diagnostics_cfg = set_warning_cfg_from_cli( + DiagnosticsConfig::new(Severity::Warning, arg_verbose), + lazy_mode, + warn_opts, + ); + + let mut opts = OptArgs::opts_from_cli(&comp_opts); + if lazy_mode { + opts.lazy_mode(); + } + + let mut book = load_book(&path)?; + let compile_res = compile_book(&mut book, opts, diagnostics_cfg, None)?; + + eprint!("{}", compile_res.diagnostics); + println!("{}", compile_res.core_book); + } + Mode::Desugar { path, comp_opts, warn_opts, lazy_mode } => { + let diagnostics_cfg = set_warning_cfg_from_cli( + DiagnosticsConfig::new(Severity::Warning, arg_verbose), + lazy_mode, + warn_opts, + ); + + let mut opts = OptArgs::opts_from_cli(&comp_opts); + if lazy_mode { + opts.lazy_mode(); + } + + let mut book = load_book(&path)?; + let diagnostics = desugar_book(&mut book, opts, diagnostics_cfg, None)?; + + eprint!("{diagnostics}"); + println!("{book}"); + } + Mode::Run { + path, + max_memory, + max_rewrites, + debug, + mut single_core, + linear, + arg_stats, + comp_opts, + warn_opts, + lazy_mode, + arguments, + } => { + if debug && lazy_mode { + return Err(Diagnostics::from( + "Unsupported configuration, can not use debug mode `-d` with lazy mode `-L`".to_string(), + )); + } + + let diagnostics_cfg = + set_warning_cfg_from_cli(DiagnosticsConfig::new(Severity::Allow, arg_verbose), lazy_mode, warn_opts); + + let mut compile_opts = OptArgs::opts_from_cli(&comp_opts); + compile_opts.check(lazy_mode); + + if lazy_mode { + single_core = true; + compile_opts.lazy_mode(); + } + + let run_opts = RunOpts { single_core, debug, linear, lazy_mode, max_memory, max_rewrites }; + + let book = load_book(&path)?; + let (res_term, RunInfo { stats, diagnostics, net, book: _, labels: _ }) = + run_book(book, max_memory, run_opts, compile_opts, diagnostics_cfg, arguments)?; + + let total_rewrites = stats.rewrites.total() as f64; + let rps = total_rewrites / stats.run_time / 1_000_000.0; + let size = stats.used; + + if cli.verbose { + println!("{net}"); + } + + eprint!("{diagnostics}"); + println!("{res_term}"); + + if arg_stats { + println!("\nRWTS : {}", total_rewrites); + println!("- ANNI : {}", stats.rewrites.anni); + println!("- COMM : {}", stats.rewrites.comm); + println!("- ERAS : {}", stats.rewrites.eras); + println!("- DREF : {}", stats.rewrites.dref); + println!("- OPER : {}", stats.rewrites.oper); + println!("TIME : {:.3} s", stats.run_time); + println!("RPS : {:.3} m", rps); + println!("SIZE : {} nodes", size); + } + } + }; + Ok(()) +} + +fn mem_parser(arg: &str) -> Result { + let (base, mult) = match arg.to_lowercase().chars().last() { + None => return Err("Mem size argument is empty".to_string()), + Some('k') => (&arg[0 .. arg.len() - 1], 1 << 10), + Some('m') => (&arg[0 .. arg.len() - 1], 1 << 20), + Some('g') => (&arg[0 .. arg.len() - 1], 1 << 30), + Some(_) => (arg, 1), + }; + let base = base.parse::().map_err(|e| e.to_string())?; + Ok(base * mult) +} + +fn set_warning_cfg_from_cli( + mut cfg: DiagnosticsConfig, + lazy_mode: bool, + warn_opts: CliWarnOpts, +) -> DiagnosticsConfig { + fn set(cfg: &mut DiagnosticsConfig, severity: Severity, cli_val: WarningArgs, lazy_mode: bool) { + match cli_val { + WarningArgs::All => { + cfg.unused_definition = severity; + cfg.match_only_vars = severity; + cfg.repeated_bind = severity; + if !lazy_mode { + cfg.mutual_recursion_cycle = severity; + } + } + WarningArgs::UnusedDefs => cfg.unused_definition = severity, + WarningArgs::MatchOnlyVars => cfg.match_only_vars = severity, + WarningArgs::RepeatedBind => cfg.repeated_bind = severity, + WarningArgs::MutualRecursionCycle => cfg.mutual_recursion_cycle = severity, + } + } + + if !lazy_mode { + cfg.mutual_recursion_cycle = Severity::Warning; + } + + let cmd = Cli::command(); + let matches = cmd.get_matches(); + let subcmd_name = matches.subcommand_name().expect("To have a subcommand"); + let arg_matches = matches.subcommand_matches(subcmd_name).expect("To have a subcommand"); + + if let Some(warn_opts_ids) = arg_matches.get_many::("CliWarnOpts") { + let mut allows = warn_opts.allows.into_iter(); + let mut warns = warn_opts.warns.into_iter(); + let mut denies = warn_opts.denies.into_iter(); + for id in warn_opts_ids { match id.as_ref() { - "allows" => Self::set(wopts, allows.next().unwrap(), WarningOpts::allow_all, WarnState::Allow), - "denies" => Self::set(wopts, denies.next().unwrap(), WarningOpts::deny_all, WarnState::Deny), - "warns" => Self::set(wopts, warns.next().unwrap(), WarningOpts::warn_all, WarnState::Warn), - _ => {} + "allows" => set(&mut cfg, Severity::Allow, allows.next().unwrap(), lazy_mode), + "denies" => set(&mut cfg, Severity::Error, denies.next().unwrap(), lazy_mode), + "warns" => set(&mut cfg, Severity::Warning, warns.next().unwrap(), lazy_mode), + _ => unreachable!(), } } } - - fn set(wopts: &mut WarningOpts, val: WarningArgs, all: impl Fn() -> WarningOpts, switch: WarnState) { - match val { - WarningArgs::All => *wopts = all(), - WarningArgs::UnusedDefs => wopts.unused_defs = switch, - WarningArgs::MatchOnlyVars => wopts.match_only_vars = switch, - } - } + cfg } diff --git a/src/net/net_to_hvmc.rs b/src/net/net_to_hvmc.rs index 8c0471ef..dbbdbf60 100644 --- a/src/net/net_to_hvmc.rs +++ b/src/net/net_to_hvmc.rs @@ -1,21 +1,31 @@ use super::{INet, NodeId, NodeKind, Port, ROOT}; -use crate::term::num_to_name; +use crate::{ + diagnostics::{Diagnostics, ToStringVerbose}, + term::num_to_name, +}; use hvmc::ast::{Book, Net, Tree}; use std::collections::{HashMap, HashSet}; +pub struct ViciousCycleErr; + /// Converts the inet-encoded definitions into an hvmc AST Book. -pub fn nets_to_hvmc(nets: HashMap) -> Result { +pub fn nets_to_hvmc(nets: HashMap, info: &mut Diagnostics) -> Result { + info.start_pass(); + let mut book = Book::default(); for (name, inet) in nets { - let net = net_to_hvmc(&inet)?; - book.insert(name, net); + let res = net_to_hvmc(&inet); + if let Some(net) = info.take_inet_err(res, name.clone()) { + book.insert(name, net); + } } - Ok(book) + + info.fatal(book) } /// Convert an inet-encoded definition into an hvmc AST inet. -pub fn net_to_hvmc(inet: &INet) -> Result { +pub fn net_to_hvmc(inet: &INet) -> Result { let (net_root, net_redexes) = get_tree_roots(inet)?; let mut port_to_var_id: HashMap = HashMap::new(); let root = if let Some(net_root) = net_root { @@ -98,7 +108,7 @@ type VarId = NodeId; /// Finds the roots of all the trees in the inet. /// Returns them as the root of the root tree and the active pairs of the net. /// Active pairs are found by a right-to-left, depth-first search. -fn get_tree_roots(inet: &INet) -> Result<(Option, Vec<[NodeId; 2]>), String> { +fn get_tree_roots(inet: &INet) -> Result<(Option, Vec<[NodeId; 2]>), ViciousCycleErr> { let mut redex_roots: Vec<[NodeId; 2]> = vec![]; let mut movements: Vec = vec![]; let mut root_set = HashSet::from([ROOT.node()]); @@ -166,7 +176,7 @@ fn explore_side_link( movements: &mut Vec, redex_roots: &mut Vec<[NodeId; 2]>, root_set: &mut HashSet, -) -> Result<(), String> { +) -> Result<(), ViciousCycleErr> { let new_roots = go_up_tree(inet, node_id)?; // If this is a new tree, explore it downwards if !root_set.contains(&new_roots[0]) && !root_set.contains(&new_roots[1]) { @@ -181,12 +191,12 @@ fn explore_side_link( /// Goes up a node tree, starting from some given node. /// Returns the active pair at the root of this tree. -fn go_up_tree(inet: &INet, start_node: NodeId) -> Result<[NodeId; 2], String> { +fn go_up_tree(inet: &INet, start_node: NodeId) -> Result<[NodeId; 2], ViciousCycleErr> { let mut explored_nodes = HashSet::new(); let mut cur_node = start_node; loop { if !explored_nodes.insert(cur_node) { - return Err("Found term that compiles into an inet with a vicious cycle".to_string()); + return Err(ViciousCycleErr); } let up = inet.enter_port(Port(cur_node, 0)); @@ -198,3 +208,9 @@ fn go_up_tree(inet: &INet, start_node: NodeId) -> Result<[NodeId; 2], String> { cur_node = up.node(); } } + +impl ToStringVerbose for ViciousCycleErr { + fn to_string_verbose(&self, _verbose: bool) -> String { + "Found term that compiles into an inet with a vicious cycle".into() + } +} diff --git a/src/term/check/ctrs_arities.rs b/src/term/check/ctrs_arities.rs index d40e787a..5cdcbd58 100644 --- a/src/term/check/ctrs_arities.rs +++ b/src/term/check/ctrs_arities.rs @@ -1,16 +1,22 @@ use std::collections::HashMap; use crate::{ - diagnostics::Info, - term::{transform::encode_pattern_matching::MatchErr, Book, Ctx, Name, Pattern, Term}, + diagnostics::{Diagnostics, ToStringVerbose}, + term::{Book, Ctx, Name, Pattern, Term}, }; +pub struct CtrArityMismatchErr { + ctr_name: Name, + expected: usize, + found: usize, +} + impl Ctx<'_> { - /// Checks if every constructor pattern of every definition rule has the same arity from the - /// defined adt constructor. + /// Checks if every constructor pattern of every definition rule + /// has the same arity from the defined adt constructor. /// /// Constructors should be already resolved. - pub fn check_ctrs_arities(&mut self) -> Result<(), Info> { + pub fn check_ctrs_arities(&mut self) -> Result<(), Diagnostics> { self.info.start_pass(); let arities = self.book.ctr_arities(); @@ -18,10 +24,10 @@ impl Ctx<'_> { for rule in def.rules.iter() { for pat in rule.pats.iter() { let res = pat.check_ctrs_arities(&arities); - self.info.take_err(res, Some(def_name)); + self.info.take_rule_err(res, def_name.clone()); } let res = rule.body.check_ctrs_arities(&arities); - self.info.take_err(res, Some(def_name)); + self.info.take_rule_err(res, def_name.clone()); } } @@ -45,15 +51,15 @@ impl Book { } impl Pattern { - fn check_ctrs_arities(&self, arities: &HashMap) -> Result<(), MatchErr> { + fn check_ctrs_arities(&self, arities: &HashMap) -> Result<(), CtrArityMismatchErr> { let mut to_check = vec![self]; while let Some(pat) = to_check.pop() { - if let Pattern::Ctr(name, args) = pat { - let expected = arities.get(name).unwrap(); + if let Pattern::Ctr(ctr_name, args) = pat { + let expected = arities.get(ctr_name).unwrap(); let found = args.len(); if *expected != found { - return Err(MatchErr::CtrArityMismatch(name.clone(), found, *expected)); + return Err(CtrArityMismatchErr { ctr_name: ctr_name.clone(), found, expected: *expected }); } } for child in pat.children() { @@ -65,7 +71,7 @@ impl Pattern { } impl Term { - pub fn check_ctrs_arities(&self, arities: &HashMap) -> Result<(), MatchErr> { + pub fn check_ctrs_arities(&self, arities: &HashMap) -> Result<(), CtrArityMismatchErr> { Term::recursive_call(move || { for pat in self.patterns() { pat.check_ctrs_arities(arities)?; @@ -77,3 +83,12 @@ impl Term { }) } } + +impl ToStringVerbose for CtrArityMismatchErr { + fn to_string_verbose(&self, _verbose: bool) -> String { + format!( + "Constructor arity mismatch in pattern matching. Constructor '{}' expects {} fields, found {}.", + self.ctr_name, self.expected, self.found + ) + } +} diff --git a/src/term/check/match_arity.rs b/src/term/check/match_arity.rs index 05c2c31e..72b038e3 100644 --- a/src/term/check/match_arity.rs +++ b/src/term/check/match_arity.rs @@ -1,17 +1,21 @@ use crate::{ - diagnostics::Info, - term::{transform::encode_pattern_matching::MatchErr, Ctx, Definition, Term}, + diagnostics::{Diagnostics, ToStringVerbose}, + term::{Ctx, Definition, Term}, }; +pub struct MatchArityMismatchErr { + expected: usize, + found: usize, +} + impl Ctx<'_> { /// Checks that the number of arguments in every pattern matching rule is consistent. - pub fn check_match_arity(&mut self) -> Result<(), Info> { + pub fn check_match_arity(&mut self) -> Result<(), Diagnostics> { self.info.start_pass(); for (def_name, def) in self.book.defs.iter() { - if let Err(e) = def.check_match_arity() { - self.info.def_error(def_name.clone(), e) - }; + let res = def.check_match_arity(); + self.info.take_rule_err(res, def_name.clone()); } self.info.fatal(()) @@ -19,11 +23,12 @@ impl Ctx<'_> { } impl Definition { - pub fn check_match_arity(&self) -> Result<(), MatchErr> { - let expected_arity = self.arity(); + pub fn check_match_arity(&self) -> Result<(), MatchArityMismatchErr> { + let expected = self.arity(); for rule in &self.rules { - if rule.arity() != expected_arity { - return Err(MatchErr::ArityMismatch(rule.arity(), expected_arity)); + let found = rule.arity(); + if found != expected { + return Err(MatchArityMismatchErr { found, expected }); } rule.body.check_match_arity()?; } @@ -32,14 +37,14 @@ impl Definition { } impl Term { - pub fn check_match_arity(&self) -> Result<(), MatchErr> { + pub fn check_match_arity(&self) -> Result<(), MatchArityMismatchErr> { Term::recursive_call(move || { if let Term::Mat { args, rules } = self { let expected = args.len(); for rule in rules { let found = rule.pats.len(); if found != expected { - return Err(MatchErr::ArityMismatch(found, expected)); + return Err(MatchArityMismatchErr { found, expected }); } } } @@ -51,3 +56,9 @@ impl Term { }) } } + +impl ToStringVerbose for MatchArityMismatchErr { + fn to_string_verbose(&self, _verbose: bool) -> String { + format!("Arity mismatch in pattern matching. Expected {} patterns, found {}.", self.expected, self.found) + } +} diff --git a/src/term/check/repeated_bind.rs b/src/term/check/repeated_bind.rs index 48f72870..60c74b5d 100644 --- a/src/term/check/repeated_bind.rs +++ b/src/term/check/repeated_bind.rs @@ -1,5 +1,8 @@ -use crate::term::{Ctx, Name, Term}; -use std::{collections::HashSet, fmt::Display}; +use crate::{ + diagnostics::{ToStringVerbose, WarningType}, + term::{Ctx, Name, Term}, +}; +use std::collections::HashSet; #[derive(Debug, Clone)] pub enum RepeatedBindWarn { @@ -7,15 +10,6 @@ pub enum RepeatedBindWarn { Match(Name), } -impl Display for RepeatedBindWarn { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - RepeatedBindWarn::Rule(bind) => write!(f, "Repeated bind inside rule pattern: '{bind}'."), - RepeatedBindWarn::Match(bind) => write!(f, "Repeated bind inside match arm: '{bind}'."), - } - } -} - impl Ctx<'_> { /// Checks that there are no unbound variables in all definitions. pub fn check_repeated_binds(&mut self) { @@ -25,7 +19,11 @@ impl Ctx<'_> { for pat in &rule.pats { for nam in pat.binds().flatten() { if !binds.insert(nam) { - self.info.warning(def_name.clone(), RepeatedBindWarn::Rule(nam.clone())); + self.info.add_rule_warning( + RepeatedBindWarn::Rule(nam.clone()), + WarningType::RepeatedBind, + def_name.clone(), + ); } } } @@ -33,8 +31,8 @@ impl Ctx<'_> { let mut repeated_in_matches = Vec::new(); rule.body.check_repeated_binds(&mut repeated_in_matches); - for repeated in repeated_in_matches { - self.info.warning(def_name.clone(), repeated); + for warn in repeated_in_matches { + self.info.add_rule_warning(warn, WarningType::RepeatedBind, def_name.clone()); } } } @@ -68,3 +66,12 @@ impl Term { }) } } + +impl ToStringVerbose for RepeatedBindWarn { + fn to_string_verbose(&self, _verbose: bool) -> String { + match self { + RepeatedBindWarn::Rule(bind) => format!("Repeated bind inside rule pattern: '{bind}'."), + RepeatedBindWarn::Match(bind) => format!("Repeated bind inside match arm: '{bind}'."), + } + } +} diff --git a/src/term/check/set_entrypoint.rs b/src/term/check/set_entrypoint.rs index 1f0832a9..35e21273 100644 --- a/src/term/check/set_entrypoint.rs +++ b/src/term/check/set_entrypoint.rs @@ -1,8 +1,8 @@ use crate::{ + diagnostics::ToStringVerbose, term::{Book, Ctx, Definition, Name}, ENTRY_POINT, HVM1_ENTRY_POINT, }; -use std::fmt::Display; #[derive(Debug, Clone)] pub enum EntryErr { @@ -11,21 +11,6 @@ pub enum EntryErr { MultipleRules, } -impl Display for EntryErr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - EntryErr::NotFound(name) => write!(f, "File has no '{name}' definition."), - EntryErr::Multiple(fnd) if fnd.len() == 2 => { - write!(f, "File has both '{}' and '{}' definitions.", fnd[0], fnd[1]) - } - EntryErr::Multiple(fnd) => { - write!(f, "File has '{}', '{}' and '{}' definitions.", fnd[0], fnd[1], fnd[2]) - } - EntryErr::MultipleRules => write!(f, "Main definition can't have more than one rule."), - } - } -} - impl Ctx<'_> { pub fn set_entrypoint(&mut self) { let mut entrypoint = None; @@ -35,30 +20,31 @@ impl Ctx<'_> { (Some(entry), None, None) | (None, Some(entry), None) | (None, None, Some(entry)) => { match validate_entry_point(entry) { Ok(name) => entrypoint = Some(name), - Err(err) => self.info.error(err), + Err(err) => self.info.add_book_error(err), } } (Some(a), Some(b), None) | (None, Some(a), Some(b)) | (Some(a), None, Some(b)) => { - self.info.error(EntryErr::Multiple(vec![a.name.clone(), b.name.clone()])); + self.info.add_book_error(EntryErr::Multiple(vec![a.name.clone(), b.name.clone()])); match validate_entry_point(a) { Ok(name) => entrypoint = Some(name), - Err(err) => self.info.error(err), + Err(err) => self.info.add_book_error(err), } } (Some(a), Some(b), Some(c)) => { - self.info.error(EntryErr::Multiple(vec![a.name.clone(), b.name.clone(), c.name.clone()])); + self.info.add_book_error(EntryErr::Multiple(vec![a.name.clone(), b.name.clone(), c.name.clone()])); match validate_entry_point(a) { Ok(name) => entrypoint = Some(name), - Err(err) => self.info.error(err), + Err(err) => self.info.add_book_error(err), } } (None, None, None) => { - self.info.error(EntryErr::NotFound(self.book.entrypoint.clone().unwrap_or(Name::from(ENTRY_POINT)))) + let entrypoint = self.book.entrypoint.clone().unwrap_or(Name::from(ENTRY_POINT)); + self.info.add_book_error(EntryErr::NotFound(entrypoint)) } } @@ -78,3 +64,18 @@ impl Book { (custom, main, hvm1_main) } } + +impl ToStringVerbose for EntryErr { + fn to_string_verbose(&self, _verbose: bool) -> String { + match self { + EntryErr::NotFound(name) => format!("File has no '{name}' definition."), + EntryErr::Multiple(fnd) if fnd.len() == 2 => { + format!("File has both '{}' and '{}' definitions.", fnd[0], fnd[1]) + } + EntryErr::Multiple(fnd) => { + format!("File has '{}', '{}' and '{}' definitions.", fnd[0], fnd[1], fnd[2]) + } + EntryErr::MultipleRules => "Main definition can't have more than one rule.".to_string(), + } + } +} diff --git a/src/term/check/shared_names.rs b/src/term/check/shared_names.rs index 0b2c7e95..f837cf0e 100644 --- a/src/term/check/shared_names.rs +++ b/src/term/check/shared_names.rs @@ -3,86 +3,96 @@ use std::fmt::Display; use indexmap::IndexMap; use crate::{ - diagnostics, + diagnostics::ToStringVerbose, term::{Ctx, Name}, }; #[derive(Debug, Clone)] -pub struct TopLevelErr(Name); - -impl Display for TopLevelErr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Duplicated top-level name '{}'.", self.0) - } +pub struct RepeatedTopLevelNameErr { + kind_fst: NameKind, + kind_snd: NameKind, + name: Name, } impl Ctx<'_> { - /// Checks if exists shared names from definitions, adts and constructors, allowing constructors - /// share the adt name once. + /// Checks if there are any repeated top level names. Constructors + /// and functions can't share names and adts can't share names. pub fn check_shared_names(&mut self) { - let mut checked = IndexMap::<&Name, NameInfo>::new(); + let mut names = NameInfo::default(); for adt_name in self.book.adts.keys() { - checked.entry(adt_name).or_insert(NameInfo::new(NameKind::Adt)).with_adt(adt_name, &mut self.info); + names.add_name(adt_name, NameKind::Adt); } for ctr_name in self.book.ctrs.keys() { - checked.entry(ctr_name).or_insert(NameInfo::new(NameKind::Ctr)).with_ctr(ctr_name, &mut self.info); + names.add_name(ctr_name, NameKind::Ctr); } for def_name in self.book.defs.keys() { - checked.entry(def_name).or_insert(NameInfo::new(NameKind::Def)).with_def(def_name, &mut self.info); + names.add_name(def_name, NameKind::Def); } - for (name, name_info) in checked.into_iter() { - if name_info.count > 1 { - self.info.error(TopLevelErr(name.clone())); - } + for err in names.into_errs() { + self.info.add_book_error(err); } } } -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] enum NameKind { Adt, Def, Ctr, } -#[derive(Debug)] -struct NameInfo { - kind: NameKind, - count: usize, -} +#[derive(Debug, Default)] +struct NameInfo<'a>(IndexMap<&'a Name, Vec>); -impl NameInfo { - fn new(kind: NameKind) -> Self { - Self { kind, count: 0 } +impl<'a> NameInfo<'a> { + fn add_name(&mut self, name: &'a Name, kind: NameKind) { + self.0.entry(name).or_default().push(kind); + } + + fn into_errs(self) -> Vec { + let mut errs = vec![]; + for (name, kinds) in self.0 { + let mut num_adts = 0; + let mut fst_ctr_def = None; + for kind in kinds { + if let NameKind::Adt = kind { + num_adts += 1; + if num_adts >= 2 { + errs.push(RepeatedTopLevelNameErr { + kind_fst: NameKind::Adt, + kind_snd: NameKind::Adt, + name: name.clone(), + }); + } + } else if let Some(fst) = fst_ctr_def { + errs.push(RepeatedTopLevelNameErr { kind_fst: fst, kind_snd: kind, name: name.clone() }); + } else { + fst_ctr_def = Some(kind); + } + } + } + errs } } -impl NameInfo { - fn with_ctr(&mut self, current_name: &Name, info: &mut diagnostics::Info) { - match self.kind { - NameKind::Adt => {} // Error caught by the parser - NameKind::Def => info.error(TopLevelErr(current_name.clone())), - NameKind::Ctr => {} // Error caught by the parser - } - } - - fn with_def(&mut self, current_name: &Name, info: &mut diagnostics::Info) { - match self.kind { - NameKind::Adt => self.count += 1, - NameKind::Def => {} - NameKind::Ctr => info.error(TopLevelErr(current_name.clone())), - } - } - - fn with_adt(&mut self, current_name: &Name, info: &mut diagnostics::Info) { - match self.kind { - NameKind::Adt => self.count += 1, - NameKind::Def => info.error(TopLevelErr(current_name.clone())), - NameKind::Ctr => self.count += 1, +impl Display for NameKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + NameKind::Adt => write!(f, "data type"), + NameKind::Def => write!(f, "function"), + NameKind::Ctr => write!(f, "constructor"), } } } + +impl ToStringVerbose for RepeatedTopLevelNameErr { + fn to_string_verbose(&self, _verbose: bool) -> String { + let mut snd = self.kind_snd.to_string(); + snd[0 .. 1].make_ascii_uppercase(); + format!("{} '{}' has the same name as a previously defined {}", snd, self.name, self.kind_fst) + } +} diff --git a/src/term/check/type_check.rs b/src/term/check/type_check.rs index 62b7498a..e903693a 100644 --- a/src/term/check/type_check.rs +++ b/src/term/check/type_check.rs @@ -1,9 +1,22 @@ -use crate::term::{transform::encode_pattern_matching::MatchErr, Constructors, Name, Pattern, Rule, Type}; +use crate::{ + diagnostics::ToStringVerbose, + term::{Constructors, Name, Pattern, Rule, Type}, +}; use indexmap::IndexMap; pub type DefinitionTypes = IndexMap>; -pub fn infer_match_arg_type(rules: &[Rule], arg_idx: usize, ctrs: &Constructors) -> Result { +#[derive(Debug)] +pub struct TypeMismatchErr { + expected: Type, + found: Type, +} + +pub fn infer_match_arg_type( + rules: &[Rule], + arg_idx: usize, + ctrs: &Constructors, +) -> Result { infer_type(rules.iter().map(|r| &r.pats[arg_idx]), ctrs) } @@ -11,7 +24,7 @@ pub fn infer_match_arg_type(rules: &[Rule], arg_idx: usize, ctrs: &Constructors) pub fn infer_type<'a>( pats: impl IntoIterator, ctrs: &Constructors, -) -> Result { +) -> Result { let mut arg_type = Type::Any; for pat in pats.into_iter() { arg_type = unify(arg_type, pat.to_type(ctrs))?; @@ -19,7 +32,7 @@ pub fn infer_type<'a>( Ok(arg_type) } -fn unify(old: Type, new: Type) -> Result { +fn unify(old: Type, new: Type) -> Result { match (old, new) { (Type::Any, new) => Ok(new), (old, Type::Any) => Ok(old), @@ -34,6 +47,12 @@ fn unify(old: Type, new: Type) -> Result { (Type::Tup(a), Type::Tup(b)) if a == b => Ok(Type::Tup(a)), - (old, new) => Err(MatchErr::TypeMismatch(new, old)), + (old, new) => Err(TypeMismatchErr { found: new, expected: old }), + } +} + +impl ToStringVerbose for TypeMismatchErr { + fn to_string_verbose(&self, _verbose: bool) -> String { + format!("Type mismatch in pattern matching. Expected '{}', found '{}'.", self.expected, self.found) } } diff --git a/src/term/check/unbound_pats.rs b/src/term/check/unbound_pats.rs index 5a605e09..9dcb6a16 100644 --- a/src/term/check/unbound_pats.rs +++ b/src/term/check/unbound_pats.rs @@ -1,21 +1,15 @@ use crate::{ - diagnostics::Info, + diagnostics::{Diagnostics, ToStringVerbose}, term::{Ctx, Name, Pattern, Term}, }; -use std::{collections::HashSet, fmt::Display}; +use std::collections::HashSet; #[derive(Debug, Clone)] pub struct UnboundCtrErr(Name); -impl Display for UnboundCtrErr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Unbound constructor '{}'.", self.0) - } -} - impl Ctx<'_> { /// Check if the constructors in rule patterns or match patterns are defined. - pub fn check_unbound_pats(&mut self) -> Result<(), Info> { + pub fn check_unbound_pats(&mut self) -> Result<(), Diagnostics> { self.info.start_pass(); let is_ctr = |nam: &Name| self.book.ctrs.contains_key(nam); @@ -23,11 +17,11 @@ impl Ctx<'_> { for rule in &def.rules { for pat in &rule.pats { let res = pat.check_unbounds(&is_ctr); - self.info.take_err(res, Some(def_name)); + self.info.take_rule_err(res, def_name.clone()); } let res = rule.body.check_unbound_pats(&is_ctr); - self.info.take_err(res, Some(def_name)); + self.info.take_rule_err(res, def_name.clone()); } } @@ -70,3 +64,9 @@ impl Term { }) } } + +impl ToStringVerbose for UnboundCtrErr { + fn to_string_verbose(&self, _verbose: bool) -> String { + format!("Unbound constructor '{}'.", self.0) + } +} diff --git a/src/term/check/unbound_vars.rs b/src/term/check/unbound_vars.rs index a6bc0098..f783ac14 100644 --- a/src/term/check/unbound_vars.rs +++ b/src/term/check/unbound_vars.rs @@ -1,11 +1,8 @@ use crate::{ - diagnostics::Info, + diagnostics::{Diagnostics, ToStringVerbose}, term::{Ctx, Name, Term}, }; -use std::{ - collections::{hash_map::Entry, HashMap}, - fmt::Display, -}; +use std::collections::{hash_map::Entry, HashMap}; #[derive(Debug, Clone)] pub enum UnboundVarErr { @@ -13,26 +10,9 @@ pub enum UnboundVarErr { Global { var: Name, declared: usize, used: usize }, } -impl Display for UnboundVarErr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - UnboundVarErr::Local(var) => write!(f, "Unbound variable '{var}'."), - UnboundVarErr::Global { var, declared, used } => match (declared, used) { - (0, _) => write!(f, "Unbound unscoped variable '${var}'."), - (_, 0) => write!(f, "Unscoped variable from lambda 'λ${var}' is never used."), - (1, _) => write!(f, "Unscoped variable '${var}' used more than once."), - (_, 1) => write!(f, "Unscoped lambda 'λ${var}' declared more than once."), - (_, _) => { - write!(f, "Unscoped lambda 'λ${var}' and unscoped variable '${var}' used more than once.") - } - }, - } - } -} - impl Ctx<'_> { /// Checks that there are no unbound variables in all definitions. - pub fn check_unbound_vars(&mut self) -> Result<(), Info> { + pub fn check_unbound_vars(&mut self) -> Result<(), Diagnostics> { self.info.start_pass(); for (def_name, def) in self.book.defs.iter_mut() { @@ -47,7 +27,7 @@ impl Ctx<'_> { } for err in errs { - self.info.def_error(def_name.clone(), err); + self.info.add_rule_error(err, def_name.clone()); } } @@ -128,3 +108,20 @@ fn pop_scope<'a>(nam: Option<&'a Name>, scope: &mut HashMap<&'a Name, u64>) { } } } + +impl ToStringVerbose for UnboundVarErr { + fn to_string_verbose(&self, _verbose: bool) -> String { + match self { + UnboundVarErr::Local(var) => format!("Unbound variable '{var}'."), + UnboundVarErr::Global { var, declared, used } => match (declared, used) { + (0, _) => format!("Unbound unscoped variable '${var}'."), + (_, 0) => format!("Unscoped variable from lambda 'λ${var}' is never used."), + (1, _) => format!("Unscoped variable '${var}' used more than once."), + (_, 1) => format!("Unscoped lambda 'λ${var}' declared more than once."), + (_, _) => { + format!("Unscoped lambda 'λ${var}' and unscoped variable '${var}' used more than once.") + } + }, + } + } +} diff --git a/src/term/display.rs b/src/term/display.rs index 2a4b5a66..78c00e0c 100644 --- a/src/term/display.rs +++ b/src/term/display.rs @@ -1,4 +1,4 @@ -use super::{net_to_term::ReadbackError, Book, Definition, Name, NumCtr, Op, Pattern, Rule, Tag, Term, Type}; +use super::{Book, Definition, Name, NumCtr, Op, Pattern, Rule, Tag, Term, Type}; use std::{fmt, ops::Deref}; /* Some aux structures for things that are not so simple to display */ @@ -189,58 +189,6 @@ impl fmt::Display for Type { } } -impl fmt::Display for ReadbackError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ReadbackError::InvalidNumericMatch => write!(f, "Invalid Numeric Match"), - ReadbackError::InvalidNumericOp => write!(f, "Invalid Numeric Operation"), - ReadbackError::ReachedRoot => write!(f, "Reached Root"), - ReadbackError::Cyclic => write!(f, "Cyclic Term"), - ReadbackError::InvalidBind => write!(f, "Invalid Bind"), - ReadbackError::InvalidAdt => write!(f, "Invalid Adt"), - ReadbackError::UnexpectedTag(exp, fnd) => { - write!(f, "Unexpected tag found during Adt readback, expected '{exp}', but found ")?; - - match fnd { - Tag::Static => write!(f, "no tag"), - _ => write!(f, "'{fnd}'"), - } - } - ReadbackError::InvalidAdtMatch => write!(f, "Invalid Adt Match"), - ReadbackError::InvalidStrTerm(term) => { - write!(f, "Invalid String Character value '{term}'") - } - } - } -} - -pub fn display_readback_errors(errs: &[ReadbackError]) -> impl fmt::Display + '_ { - DisplayFn(move |f| { - if errs.is_empty() { - return Ok(()); - } - - writeln!(f, "Readback Warning:")?; - let mut err_counts = std::collections::HashMap::new(); - for err in errs { - if err.can_count() { - *err_counts.entry(err).or_insert(0) += 1; - } else { - writeln!(f, "{err}")?; - } - } - - for (err, count) in err_counts { - write!(f, "{err}")?; - if count > 1 { - writeln!(f, " ({count} occurrences)")?; - } - } - - writeln!(f) - }) -} - impl Term { fn display_app<'a>(&'a self, tag: &'a Tag) -> impl fmt::Display + 'a { DisplayFn(move |f| match self { diff --git a/src/term/mod.rs b/src/term/mod.rs index c0430f86..2620f268 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -1,5 +1,9 @@ use self::{check::type_check::infer_match_arg_type, parser::lexer::STRINGS}; -use crate::{diagnostics::Info, term::builtins::*, ENTRY_POINT}; +use crate::{ + diagnostics::{Diagnostics, DiagnosticsConfig}, + term::builtins::*, + ENTRY_POINT, +}; use indexmap::{IndexMap, IndexSet}; use interner::global::GlobalString; use itertools::Itertools; @@ -24,12 +28,12 @@ pub use term_to_net::{book_to_nets, term_to_compat_net}; #[derive(Debug)] pub struct Ctx<'book> { pub book: &'book mut Book, - pub info: Info, + pub info: Diagnostics, } impl Ctx<'_> { - pub fn new(book: &mut Book) -> Ctx { - Ctx { book, info: Info::default() } + pub fn new(book: &mut Book, diagnostics_cfg: DiagnosticsConfig) -> Ctx { + Ctx { book, info: Diagnostics::new(diagnostics_cfg) } } } diff --git a/src/term/net_to_term.rs b/src/term/net_to_term.rs index 1e33eb6f..44c1cc6a 100644 --- a/src/term/net_to_term.rs +++ b/src/term/net_to_term.rs @@ -1,4 +1,5 @@ use crate::{ + diagnostics::{DiagnosticOrigin, Diagnostics, Severity}, net::{INet, NodeId, NodeKind::*, Port, SlotId, ROOT}, term::{num_to_name, term_to_net::Labels, Book, Name, Op, Pattern, Tag, Term}, }; @@ -6,7 +7,13 @@ use std::collections::{BTreeSet, HashMap, HashSet}; // TODO: Display scopeless lambdas as such /// Converts an Interaction-INet to a Lambda Calculus term -pub fn net_to_term(net: &INet, book: &Book, labels: &Labels, linear: bool) -> (Term, Vec) { +pub fn net_to_term( + net: &INet, + book: &Book, + labels: &Labels, + linear: bool, + diagnostics: &mut Diagnostics, +) -> Term { let mut reader = Reader { net, labels, @@ -38,7 +45,9 @@ pub fn net_to_term(net: &INet, book: &Book, labels: &Labels, linear: bool) -> (T let result = term.insert_split(split, uses); debug_assert_eq!(result, None); } - (term, reader.errors) + + reader.report_errors(diagnostics); + term } // BTreeSet for consistent readback of dups @@ -56,7 +65,7 @@ pub struct Reader<'a> { errors: Vec, } -impl<'a> Reader<'a> { +impl Reader<'_> { fn read_term(&mut self, next: Port) -> Term { Term::recursive_call(move || { if self.dup_paths.is_none() && !self.seen.insert(next) { @@ -277,6 +286,19 @@ impl<'a> Reader<'a> { pub fn error(&mut self, error: ReadbackError) { self.errors.push(error); } + + pub fn report_errors(&mut self, diagnostics: &mut Diagnostics) { + let mut err_counts = std::collections::HashMap::new(); + for err in &self.errors { + *err_counts.entry(*err).or_insert(0) += 1; + } + + for (err, count) in err_counts { + let count_msg = if count > 1 { format!(" ({count} occurrences)") } else { "".to_string() }; + let msg = format!("{}{}", err, count_msg); + diagnostics.add_diagnostic(msg.as_str(), Severity::Warning, DiagnosticOrigin::Readback); + } + } } /// Represents `let (fst, snd) = val` if `tag` is `None`, and `dup#tag fst snd = val` otherwise. @@ -473,33 +495,13 @@ fn is_op_swapped(op: hvmc::ops::Op) -> bool { ) } -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub enum ReadbackError { InvalidNumericMatch, InvalidNumericOp, ReachedRoot, Cyclic, InvalidBind, - InvalidAdt, - InvalidAdtMatch, - InvalidStrTerm(Term), - UnexpectedTag(Tag, Tag), -} - -impl ReadbackError { - pub fn can_count(&self) -> bool { - match self { - ReadbackError::InvalidNumericMatch => true, - ReadbackError::InvalidNumericOp => true, - ReadbackError::ReachedRoot => true, - ReadbackError::Cyclic => true, - ReadbackError::InvalidBind => true, - ReadbackError::InvalidAdt => true, - ReadbackError::InvalidAdtMatch => true, - ReadbackError::InvalidStrTerm(_) => false, - ReadbackError::UnexpectedTag(..) => false, - } - } } impl PartialEq for ReadbackError { @@ -515,3 +517,15 @@ impl std::hash::Hash for ReadbackError { core::mem::discriminant(self).hash(state); } } + +impl std::fmt::Display for ReadbackError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ReadbackError::InvalidNumericMatch => write!(f, "Invalid Numeric Match."), + ReadbackError::InvalidNumericOp => write!(f, "Invalid Numeric Operation."), + ReadbackError::ReachedRoot => write!(f, "Reached Root."), + ReadbackError::Cyclic => write!(f, "Cyclic Term."), + ReadbackError::InvalidBind => write!(f, "Invalid Bind."), + } + } +} diff --git a/src/term/term_to_net.rs b/src/term/term_to_net.rs index e3a120aa..a72adf0f 100644 --- a/src/term/term_to_net.rs +++ b/src/term/term_to_net.rs @@ -61,7 +61,7 @@ struct EncodeTermState<'a> { labels: &'a mut Labels, } -impl<'a> EncodeTermState<'a> { +impl EncodeTermState<'_> { /// Adds a subterm connected to `up` to the `inet`. /// `scope` has the current variable scope. /// `vars` has the information of which ports the variables are declared and used in. diff --git a/src/term/transform/apply_args.rs b/src/term/transform/apply_args.rs index 077dd1ba..f496e467 100644 --- a/src/term/transform/apply_args.rs +++ b/src/term/transform/apply_args.rs @@ -1,18 +1,9 @@ -use std::fmt::Display; - use crate::{ - diagnostics::Info, + diagnostics::{Diagnostics, ToStringVerbose}, term::{Ctx, Pattern, Term}, }; -#[derive(Clone, Debug)] -pub struct PatternArgError(Pattern); - -impl Display for PatternArgError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Expected a variable pattern, found '{}'.", self.0) - } -} +struct PatternArgError(Pattern); impl Ctx<'_> { /// Applies the arguments to the program being run by applying them to the main function. @@ -25,7 +16,7 @@ impl Ctx<'_> { /// ```hvm /// main = (λx1 λx2 λx3 (MainBody x1 x2 x3) arg1 arg2 arg3) /// ``` - pub fn apply_args(&mut self, args: Option>) -> Result<(), Info> { + pub fn apply_args(&mut self, args: Option>) -> Result<(), Diagnostics> { self.info.start_pass(); if let Some(entrypoint) = &self.book.entrypoint { @@ -33,7 +24,7 @@ impl Ctx<'_> { for pat in &main_def.rules[0].pats { if !matches!(pat, Pattern::Var(Some(..))) { - self.info.def_error(entrypoint.clone(), PatternArgError(pat.clone())); + self.info.add_rule_error(PatternArgError(pat.clone()), entrypoint.clone()); } } @@ -48,3 +39,9 @@ impl Ctx<'_> { self.info.fatal(()) } } + +impl ToStringVerbose for PatternArgError { + fn to_string_verbose(&self, _verbose: bool) -> String { + format!("Expected the entrypoint to only have variable pattern, found '{}'.", self.0) + } +} diff --git a/src/term/transform/definition_pruning.rs b/src/term/transform/definition_pruning.rs index 0539db71d..0f11e5c8 100644 --- a/src/term/transform/definition_pruning.rs +++ b/src/term/transform/definition_pruning.rs @@ -1,11 +1,12 @@ -use std::collections::{hash_map::Entry, HashMap}; - use crate::{ - diagnostics::WarningType, + diagnostics::{ToStringVerbose, WarningType}, term::{Adt, AdtEncoding, Book, Ctx, Name, Tag, Term, LIST, STRING}, CORE_BUILTINS, }; use indexmap::IndexSet; +use std::collections::{hash_map::Entry, HashMap}; + +struct UnusedDefinitionWarning; #[derive(Clone, Copy, Debug, PartialEq)] enum Used { @@ -72,7 +73,7 @@ impl Ctx<'_> { if prune_all || def.builtin { self.book.defs.swap_remove(&def_name); } else if !def_name.is_generated() { - self.info.warning(def_name.clone(), WarningType::UnusedDefinition); + self.info.add_rule_warning(UnusedDefinitionWarning, WarningType::UnusedDefinition, def_name); } } } @@ -153,3 +154,9 @@ impl Book { } } } + +impl ToStringVerbose for UnusedDefinitionWarning { + fn to_string_verbose(&self, _verbose: bool) -> String { + "Definition is unused.".to_string() + } +} diff --git a/src/term/transform/encode_pattern_matching.rs b/src/term/transform/encode_pattern_matching.rs index 32123d11..6cccd5c3 100644 --- a/src/term/transform/encode_pattern_matching.rs +++ b/src/term/transform/encode_pattern_matching.rs @@ -1,13 +1,6 @@ -use std::fmt::Display; - -use itertools::Itertools; - -use crate::{ - diagnostics::ERR_INDENT_SIZE, - term::{ - check::type_check::infer_match_arg_type, display::DisplayFn, AdtEncoding, Adts, Book, Constructors, Name, - NumCtr, Pattern, Rule, Tag, Term, Type, - }, +use crate::term::{ + check::type_check::infer_match_arg_type, AdtEncoding, Adts, Book, Constructors, Name, NumCtr, Pattern, + Rule, Tag, Term, Type, }; impl Book { @@ -180,84 +173,3 @@ fn encode_adt(arg: Term, rules: Vec, adt: Name, adt_encoding: AdtEncoding) } } } - -#[derive(Debug, Clone)] -pub enum MatchErr { - RepeatedBind(Name), - LetPat(Box), - Linearize(Name), - NotExhaustive(ExhaustivenessErr), - TypeMismatch(Type, Type), - ArityMismatch(usize, usize), - CtrArityMismatch(Name, usize, usize), - MalformedNumSucc(Pattern, Pattern), -} - -#[derive(Debug, Clone)] -pub struct ExhaustivenessErr(pub Vec); - -const PATTERN_ERROR_LIMIT: usize = 5; -const ERROR_LIMIT_HINT: &str = "Use the --verbose option to see all cases."; - -impl MatchErr { - pub fn display(&self, verbose: bool) -> impl std::fmt::Display + '_ { - DisplayFn(move |f| match self { - MatchErr::RepeatedBind(bind) => write!(f, "Repeated var name in a match block: {}", bind), - MatchErr::LetPat(err) => { - let let_err = err.to_string().replace("match block", "let bind"); - write!(f, "{let_err}")?; - - if matches!(err.as_ref(), MatchErr::NotExhaustive(..)) { - write!(f, "\nConsider using a match block instead")?; - } - - Ok(()) - } - MatchErr::Linearize(var) => write!(f, "Unable to linearize variable {var} in a match block."), - MatchErr::NotExhaustive(err) if verbose => write!(f, "{}", err.display_with_limit(usize::MAX)), - MatchErr::NotExhaustive(err) => write!(f, "{err}"), - MatchErr::TypeMismatch(got, exp) => { - write!(f, "Type mismatch in pattern matching. Expected '{exp}', found '{got}'.") - } - MatchErr::ArityMismatch(got, exp) => { - write!(f, "Arity mismatch in pattern matching. Expected {exp} patterns, found {got}.") - } - MatchErr::CtrArityMismatch(ctr, got, exp) => write!( - f, - "Constructor arity mismatch in pattern matching. Constructor '{ctr}' expects {exp} fields, found {got}." - ), - MatchErr::MalformedNumSucc(got, exp) => { - write!(f, "Expected a sequence of incrementing numbers ending with '{exp}', found '{got}'.") - } - }) - } -} - -impl std::fmt::Display for MatchErr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.display(false)) - } -} - -impl ExhaustivenessErr { - pub fn display_with_limit(&self, limit: usize) -> String { - let ident = ERR_INDENT_SIZE * 2; - let hints = - self.0.iter().take(limit).map(|pat| format!("{:ident$}Case '{pat}' not covered.", "")).join("\n"); - - let mut str = format!("Non-exhaustive pattern matching. Hint:\n{}", hints); - - let len = self.0.len(); - if len > limit { - str.push_str(&format!(" ... and {} others.\n{:ident$}{}", len - limit, "", ERROR_LIMIT_HINT)) - } - - str - } -} - -impl Display for ExhaustivenessErr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.display_with_limit(PATTERN_ERROR_LIMIT)) - } -} diff --git a/src/term/transform/linearize_matches.rs b/src/term/transform/linearize_matches.rs index a2d280b0..c899e28c 100644 --- a/src/term/transform/linearize_matches.rs +++ b/src/term/transform/linearize_matches.rs @@ -1,39 +1,28 @@ -use super::encode_pattern_matching::MatchErr; -use crate::{ - diagnostics::Info, - term::{Ctx, Name, Term}, -}; +use crate::term::{Book, Name, Term}; use itertools::Itertools; use std::collections::{BTreeMap, BTreeSet}; -impl Ctx<'_> { +impl Book { /// Linearizes the variables between match cases, transforming them into combinators when possible. - pub fn linearize_simple_matches(&mut self, lift_all_vars: bool) -> Result<(), Info> { - self.info.start_pass(); - - for (def_name, def) in self.book.defs.iter_mut() { + pub fn linearize_simple_matches(&mut self, lift_all_vars: bool) { + for def in self.defs.values_mut() { for rule in def.rules.iter_mut() { - let res = rule.body.linearize_simple_matches(lift_all_vars); - self.info.take_err(res, Some(def_name)); + rule.body.linearize_simple_matches(lift_all_vars); } } - - self.info.fatal(()) } } impl Term { - fn linearize_simple_matches(&mut self, lift_all_vars: bool) -> Result<(), MatchErr> { + fn linearize_simple_matches(&mut self, lift_all_vars: bool) { Term::recursive_call(move || { for child in self.children_mut() { - child.linearize_simple_matches(lift_all_vars)?; + child.linearize_simple_matches(lift_all_vars); } if let Term::Mat { .. } = self { lift_match_vars(self, lift_all_vars); } - - Ok(()) }) } } diff --git a/src/term/transform/resolve_refs.rs b/src/term/transform/resolve_refs.rs index d1527f5a..63b1ece1 100644 --- a/src/term/transform/resolve_refs.rs +++ b/src/term/transform/resolve_refs.rs @@ -1,22 +1,13 @@ use crate::{ - diagnostics::Info, + diagnostics::{Diagnostics, ToStringVerbose}, term::{Ctx, Name, Pattern, Term}, CORE_BUILTINS, }; -use std::{ - collections::{HashMap, HashSet}, - fmt::Display, -}; +use std::collections::{HashMap, HashSet}; #[derive(Debug, Clone)] pub struct ReferencedMainErr; -impl Display for ReferencedMainErr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Main definition can't be referenced inside the program.") - } -} - impl Ctx<'_> { /// Decides if names inside a term belong to a Var or to a Ref. /// Converts `Term::Var(nam)` into `Term::Ref(nam)` when the name @@ -26,7 +17,7 @@ impl Ctx<'_> { /// Precondition: Refs are encoded as vars, Constructors are resolved. /// /// Postcondition: Refs are encoded as refs, with the correct def id. - pub fn resolve_refs(&mut self) -> Result<(), Info> { + pub fn resolve_refs(&mut self) -> Result<(), Diagnostics> { self.info.start_pass(); let def_names = self.book.defs.keys().cloned().collect::>(); @@ -39,7 +30,7 @@ impl Ctx<'_> { } let res = rule.body.resolve_refs(&def_names, self.book.entrypoint.as_ref(), &mut scope); - self.info.take_err(res, Some(def_name)); + self.info.take_rule_err(res, def_name.clone()); } } @@ -105,3 +96,9 @@ fn is_var_in_scope<'a>(name: &'a Name, scope: &HashMap<&'a Name, usize>) -> bool None => true, } } + +impl ToStringVerbose for ReferencedMainErr { + fn to_string_verbose(&self, _verbose: bool) -> String { + "Main definition can't be referenced inside the program.".to_string() + } +} diff --git a/src/term/transform/resugar_adts.rs b/src/term/transform/resugar_adts.rs index 9ba8d115..9b0a21cf 100644 --- a/src/term/transform/resugar_adts.rs +++ b/src/term/transform/resugar_adts.rs @@ -1,7 +1,16 @@ -use crate::term::{net_to_term::ReadbackError, Adt, AdtEncoding, Book, Name, Pattern, Rule, Tag, Term}; +use crate::{ + diagnostics::ToStringVerbose, + term::{Adt, AdtEncoding, Book, Name, Pattern, Rule, Tag, Term}, +}; + +pub enum AdtReadbackError { + InvalidAdt, + InvalidAdtMatch, + UnexpectedTag(Tag, Tag), +} impl Term { - pub fn resugar_adts(&mut self, book: &Book, adt_encoding: AdtEncoding) -> Vec { + pub fn resugar_adts(&mut self, book: &Book, adt_encoding: AdtEncoding) -> Vec { let mut errs = Default::default(); match adt_encoding { // No way of resugaring simple scott encoded terms. @@ -11,7 +20,7 @@ impl Term { errs } - fn resugar_tagged_scott(&mut self, book: &Book, errs: &mut Vec) { + fn resugar_tagged_scott(&mut self, book: &Book, errs: &mut Vec) { Term::recursive_call(move || match self { Term::Lam { tag: Tag::Named(adt_name), bod, .. } | Term::Chn { tag: Tag::Named(adt_name), bod, .. } => { if let Some((adt_name, adt)) = book.adts.get_key_value(adt_name) { @@ -59,7 +68,7 @@ impl Term { book: &Book, adt: &Adt, adt_name: &Name, - errs: &mut Vec, + errs: &mut Vec, ) { let mut app = &mut *self; let mut current_arm = None; @@ -69,7 +78,7 @@ impl Term { Term::Lam { tag: Tag::Named(tag), nam, bod } if tag == adt_name => { if let Some(nam) = nam { if current_arm.is_some() { - errs.push(ReadbackError::InvalidAdt); + errs.push(AdtReadbackError::InvalidAdt); return; } current_arm = Some((nam.clone(), ctr)); @@ -77,14 +86,14 @@ impl Term { app = bod; } _ => { - errs.push(ReadbackError::InvalidAdt); + errs.push(AdtReadbackError::InvalidAdt); return; } } } let Some((arm_name, (ctr, ctr_args))) = current_arm else { - errs.push(ReadbackError::InvalidAdt); + errs.push(AdtReadbackError::InvalidAdt); return; }; @@ -100,11 +109,11 @@ impl Term { cur = fun.as_mut(); } Term::App { tag, .. } => { - errs.push(ReadbackError::UnexpectedTag(expected_tag, tag.clone())); + errs.push(AdtReadbackError::UnexpectedTag(expected_tag, tag.clone())); return; } _ => { - errs.push(ReadbackError::InvalidAdt); + errs.push(AdtReadbackError::InvalidAdt); return; } } @@ -113,7 +122,7 @@ impl Term { match cur { Term::Var { nam } if nam == &arm_name => {} _ => { - errs.push(ReadbackError::InvalidAdt); + errs.push(AdtReadbackError::InvalidAdt); return; } } @@ -157,7 +166,7 @@ impl Term { book: &Book, adt_name: &Name, adt: &Adt, - errs: &mut Vec, + errs: &mut Vec, ) { let mut cur = &mut *self; let mut arms = Vec::new(); @@ -180,7 +189,7 @@ impl Term { } _ => { if let Term::Lam { tag, .. } = arm { - errs.push(ReadbackError::UnexpectedTag(expected_tag.clone(), tag.clone())); + errs.push(AdtReadbackError::UnexpectedTag(expected_tag.clone(), tag.clone())); } let arg = Name::new(format!("{ctr}.{field}")); @@ -194,7 +203,7 @@ impl Term { cur = &mut *fun; } _ => { - errs.push(ReadbackError::InvalidAdtMatch); + errs.push(AdtReadbackError::InvalidAdtMatch); return; } } @@ -208,3 +217,16 @@ impl Term { self.resugar_tagged_scott(book, errs); } } + +impl ToStringVerbose for AdtReadbackError { + fn to_string_verbose(&self, _verbose: bool) -> String { + match self { + AdtReadbackError::InvalidAdt => "Invalid Adt.".to_string(), + AdtReadbackError::InvalidAdtMatch => "Invalid Adt Match.".to_string(), + AdtReadbackError::UnexpectedTag(expected, found) => { + let found = if let Tag::Static = found { "no tag".to_string() } else { format!("'{found}'") }; + format!("Unexpected tag found during Adt readback, expected '{}', but found {}.", expected, found) + } + } + } +} diff --git a/src/term/transform/simplify_matches.rs b/src/term/transform/simplify_matches.rs index 1201cbab..33910a96 100644 --- a/src/term/transform/simplify_matches.rs +++ b/src/term/transform/simplify_matches.rs @@ -1,22 +1,27 @@ -use indexmap::IndexSet; -use itertools::Itertools; - use crate::{ - diagnostics::Info, + diagnostics::{Diagnostics, ToStringVerbose, ERR_INDENT_SIZE}, term::{ - check::type_check::infer_match_arg_type, - transform::encode_pattern_matching::{ExhaustivenessErr, MatchErr}, + check::type_check::{infer_match_arg_type, TypeMismatchErr}, + display::{DisplayFn, DisplayJoin}, Adts, Constructors, Ctx, Definition, Name, NumCtr, Pattern, Rule, Term, Type, }, }; +use indexmap::IndexSet; +use itertools::Itertools; + +pub enum SimplifyMatchErr { + NotExhaustive(Vec), + TypeMismatch(TypeMismatchErr), + MalformedNumSucc(Pattern, Pattern), +} impl Ctx<'_> { - pub fn simplify_matches(&mut self) -> Result<(), Info> { + pub fn simplify_matches(&mut self) -> Result<(), Diagnostics> { self.info.start_pass(); for (def_name, def) in self.book.defs.iter_mut() { let res = def.simplify_matches(&self.book.ctrs, &self.book.adts); - self.info.take_err(res, Some(def_name)); + self.info.take_rule_err(res, def_name.clone()); } self.info.fatal(()) @@ -24,7 +29,7 @@ impl Ctx<'_> { } impl Definition { - pub fn simplify_matches(&mut self, ctrs: &Constructors, adts: &Adts) -> Result<(), MatchErr> { + pub fn simplify_matches(&mut self, ctrs: &Constructors, adts: &Adts) -> Result<(), SimplifyMatchErr> { for rule in self.rules.iter_mut() { rule.body.simplify_matches(ctrs, adts)?; } @@ -38,7 +43,7 @@ impl Term { /// simple (non-nested) patterns, and one rule for each constructor. /// /// See `[simplify_match_expression]` for more information. - pub fn simplify_matches(&mut self, ctrs: &Constructors, adts: &Adts) -> Result<(), MatchErr> { + pub fn simplify_matches(&mut self, ctrs: &Constructors, adts: &Adts) -> Result<(), SimplifyMatchErr> { Term::recursive_call(move || { match self { Term::Mat { args, rules } => { @@ -87,7 +92,7 @@ fn simplify_match_expression( rules: Vec, ctrs: &Constructors, adts: &Adts, -) -> Result { +) -> Result { let fst_row_irrefutable = rules[0].pats.iter().all(|p| p.is_wildcard()); let fst_col_type = infer_match_arg_type(&rules, 0, ctrs)?; @@ -108,7 +113,7 @@ fn irrefutable_fst_row_rule( mut rules: Vec, ctrs: &Constructors, adts: &Adts, -) -> Result { +) -> Result { rules.truncate(1); let Rule { pats, body: mut term } = rules.pop().unwrap(); @@ -132,7 +137,7 @@ fn var_rule( rules: Vec, ctrs: &Constructors, adts: &Adts, -) -> Result { +) -> Result { let mut new_rules = vec![]; for mut rule in rules { let rest = rule.pats.split_off(1); @@ -201,7 +206,7 @@ fn switch_rule( typ: Type, ctrs: &Constructors, adts: &Adts, -) -> Result { +) -> Result { let mut new_rules = vec![]; let adt_ctrs = match typ { @@ -225,7 +230,7 @@ fn switch_rule( Type::Num => { // Number match without + must have a default case if !rules.iter().any(|r| r.pats[0].is_wildcard()) { - return Err(MatchErr::NotExhaustive(ExhaustivenessErr(vec![Name::from("+")]))); + return Err(SimplifyMatchErr::NotExhaustive(vec![Name::from("+")])); } } Type::NumSucc(exp) => { @@ -235,7 +240,7 @@ fn switch_rule( if let Pattern::Num(NumCtr::Num(got)) = rule.pats[0] && got >= exp { - return Err(MatchErr::MalformedNumSucc( + return Err(SimplifyMatchErr::MalformedNumSucc( rule.pats[0].clone(), Pattern::Num(NumCtr::Succ(exp, None)), )); @@ -291,7 +296,7 @@ fn switch_rule_submatch( rules: &[Rule], ctr: &Pattern, nested_fields: &[Option], -) -> Result { +) -> Result { // Create the nested match expression. let new_args = nested_fields.iter().cloned().map(Term::var_or_era); let old_args = args[1 ..].iter().cloned(); @@ -304,7 +309,7 @@ fn switch_rule_submatch( if rules.is_empty() { // TODO: Return the full pattern - return Err(MatchErr::NotExhaustive(ExhaustivenessErr(vec![ctr.ctr_name().unwrap()]))); + return Err(SimplifyMatchErr::NotExhaustive(vec![ctr.ctr_name().unwrap()])); } let mat = Term::Mat { args, rules }; @@ -384,3 +389,52 @@ fn bind_extracted_args(extracted: Vec<(Name, Term)>, term: Term) -> Term { nxt: Box::new(term), }) } + +const PATTERN_ERROR_LIMIT: usize = 5; +const ERROR_LIMIT_HINT: &str = "Use the --verbose option to see all cases."; + +impl SimplifyMatchErr { + pub fn display(&self, verbose: bool) -> impl std::fmt::Display + '_ { + let limit = if verbose { usize::MAX } else { PATTERN_ERROR_LIMIT }; + DisplayFn(move |f| match self { + SimplifyMatchErr::NotExhaustive(cases) => { + let ident = ERR_INDENT_SIZE * 2; + let hints = DisplayJoin( + || { + cases + .iter() + .take(limit) + .map(|pat| DisplayFn(move |f| write!(f, "{:ident$}Case '{pat}' not covered.", ""))) + }, + "\n", + ); + write!(f, "Non-exhaustive pattern matching. Hint:\n{}", hints)?; + + let len = cases.len(); + if len > limit { + write!(f, " ... and {} others.\n{:ident$}{}", len - limit, "", ERROR_LIMIT_HINT)?; + } + + Ok(()) + } + SimplifyMatchErr::TypeMismatch(err) => { + write!(f, "{}", err.to_string_verbose(verbose)) + } + SimplifyMatchErr::MalformedNumSucc(got, exp) => { + write!(f, "Expected a sequence of incrementing numbers ending with '{exp}', found '{got}'.") + } + }) + } +} + +impl ToStringVerbose for SimplifyMatchErr { + fn to_string_verbose(&self, verbose: bool) -> String { + format!("{}", self.display(verbose)) + } +} + +impl From for SimplifyMatchErr { + fn from(value: TypeMismatchErr) -> Self { + SimplifyMatchErr::TypeMismatch(value) + } +} diff --git a/src/term/transform/simplify_ref_to_ref.rs b/src/term/transform/simplify_ref_to_ref.rs index 8b5f84ac..529c98e5 100644 --- a/src/term/transform/simplify_ref_to_ref.rs +++ b/src/term/transform/simplify_ref_to_ref.rs @@ -1,25 +1,36 @@ -// Pass for inlining functions that are just a reference to another one. - use crate::{ - diagnostics::Info, + diagnostics::{Diagnostics, ToStringVerbose}, term::{Ctx, Name, Term}, }; -use std::{collections::BTreeMap, fmt::Display}; +use std::collections::BTreeMap; #[derive(Debug, Clone)] pub struct CyclicDefErr; -impl Display for CyclicDefErr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Definition is a reference to itself.") - } -} - impl Ctx<'_> { - // When we find a function that is simply directly calling another function, - // substitutes all occurrences of that function to the one being called, avoiding the unnecessary redirect. - // In case there is a long chain of ref-to-ref-to-ref, we substitute values by the last function in the chain. - pub fn simplify_ref_to_ref(&mut self) -> Result<(), Info> { + /// Substitutes all references of functions that are just + /// references to other functions by the function they reference. + /// + /// In case there is a long chain of ref-to-ref-to-ref, we + /// substitute values by the last function in the chain. + /// + /// ### Example: + /// ```hvm + /// A = @x @y (x y) + /// B = A + /// C = B + /// main = @x (C x) + /// ``` + /// becomes + /// ```hvm + /// A = @x @y (x y) + /// B = A + /// C = A + /// main = @x (A x) + /// ``` + /// Functions `B` and `C` will no longer be referenced anywhere in + /// the program. + pub fn simplify_ref_to_ref(&mut self) -> Result<(), Diagnostics> { self.info.start_pass(); let mut ref_map: BTreeMap = BTreeMap::new(); @@ -29,7 +40,7 @@ impl Ctx<'_> { let mut is_ref_to_ref = false; while let Term::Ref { nam: next_ref } = &self.book.defs.get(ref_name).unwrap().rule().body { if next_ref == ref_name { - self.info.def_error(def_name.clone(), CyclicDefErr); + self.info.add_rule_error(CyclicDefErr, def_name.clone()); continue 'outer; } ref_name = next_ref; @@ -70,3 +81,9 @@ pub fn subst_ref_to_ref(term: &mut Term, ref_map: &BTreeMap) -> bool } }) } + +impl ToStringVerbose for CyclicDefErr { + fn to_string_verbose(&self, _verbose: bool) -> String { + "Definition is a reference to itself.".to_string() + } +} diff --git a/tests/golden_tests.rs b/tests/golden_tests.rs index b374e471..b6d36268 100644 --- a/tests/golden_tests.rs +++ b/tests/golden_tests.rs @@ -1,20 +1,19 @@ use hvml::{ compile_book, desugar_book, - diagnostics::Info, + diagnostics::{Diagnostics, DiagnosticsConfig, Severity, ToStringVerbose}, net::{hvmc_to_net::hvmc_to_net, net_to_hvmc::net_to_hvmc}, run_book, term::{ - display::display_readback_errors, load_book::do_parse_book, net_to_term::net_to_term, parser::parse_term, - term_to_compat_net, term_to_net::Labels, AdtEncoding, Book, Ctx, Name, Term, + load_book::do_parse_book, net_to_term::net_to_term, parser::parse_term, term_to_compat_net, + term_to_net::Labels, AdtEncoding, Book, Ctx, Name, Term, }, - CompileOpts, RunOpts, WarningOpts, + CompileOpts, RunOpts, }; use insta::assert_snapshot; use itertools::Itertools; use std::{ collections::HashMap, fmt::Write, - fs, io::Read, path::{Path, PathBuf}, str::FromStr, @@ -24,7 +23,7 @@ use stdext::function_name; use walkdir::WalkDir; fn format_output(output: std::process::Output) -> String { - format!("{}\n{}", String::from_utf8_lossy(&output.stderr), String::from_utf8_lossy(&output.stdout)) + format!("{}{}", String::from_utf8_lossy(&output.stderr), String::from_utf8_lossy(&output.stdout)) } fn do_parse_term(code: &str) -> Result { @@ -39,9 +38,9 @@ const TESTS_PATH: &str = "/tests/golden_tests/"; fn run_single_golden_test( path: &Path, - run: &[&dyn Fn(&str, &Path) -> Result], + run: &[&dyn Fn(&str, &Path) -> Result], ) -> Result<(), String> { - let code = fs::read_to_string(path).map_err(|e| e.to_string())?; + let code = std::fs::read_to_string(path).map_err(|e| e.to_string())?; let file_name = path.to_str().and_then(|path| path.rsplit_once(TESTS_PATH)).unwrap().1; // unfortunately we need to do this @@ -69,11 +68,14 @@ fn run_single_golden_test( Ok(()) } -fn run_golden_test_dir(test_name: &str, run: &dyn Fn(&str, &Path) -> Result) { +fn run_golden_test_dir(test_name: &str, run: &dyn Fn(&str, &Path) -> Result) { run_golden_test_dir_multiple(test_name, &[run]) } -fn run_golden_test_dir_multiple(test_name: &str, run: &[&dyn Fn(&str, &Path) -> Result]) { +fn run_golden_test_dir_multiple( + test_name: &str, + run: &[&dyn Fn(&str, &Path) -> Result], +) { let root = PathBuf::from(format!( "{}{TESTS_PATH}{}", env!("CARGO_MANIFEST_DIR"), @@ -103,13 +105,13 @@ fn compile_term() { term.check_unbound_vars(&mut HashMap::new(), &mut vec); if !vec.is_empty() { - return Err(vec.into_iter().join("\n").into()); + return Err(vec.into_iter().map(|e| e.to_string_verbose(true)).join("\n").into()); } term.make_var_names_unique(); term.linearize_vars(); let compat_net = term_to_compat_net(&term, &mut Default::default()); - let net = net_to_hvmc(&compat_net)?; + let net = net_to_hvmc(&compat_net).map_err(|e| e.to_string_verbose(true))?; Ok(format!("{}", net)) }) @@ -118,33 +120,36 @@ fn compile_term() { #[test] fn compile_file_o_all() { run_golden_test_dir(function_name!(), &|code, path| { + let diagnostics_cfg = DiagnosticsConfig::new(Severity::Warning, true); let mut book = do_parse_book(code, path)?; - let compiled = compile_book(&mut book, true /*ignore check_cycles*/, CompileOpts::heavy(), None)?; - Ok(format!("{:?}", compiled)) + let res = compile_book(&mut book, CompileOpts::heavy(), diagnostics_cfg, None)?; + Ok(format!("{}{}", res.diagnostics, res.core_book)) }) } #[test] fn compile_file() { run_golden_test_dir(function_name!(), &|code, path| { + let diagnostics_cfg = DiagnosticsConfig::new(Severity::Warning, true); let mut book = do_parse_book(code, path)?; - let compiled = compile_book(&mut book, true /*ignore check_cycles*/, CompileOpts::light(), None)?; - Ok(format!("{:?}", compiled)) + let res = compile_book(&mut book, CompileOpts::light(), diagnostics_cfg, None)?; + Ok(format!("{}{}", res.diagnostics, res.core_book)) }) } #[test] fn linear_readback() { run_golden_test_dir(function_name!(), &|code, path| { + let diagnostics_cfg = DiagnosticsConfig::new(Severity::Error, true); let book = do_parse_book(code, path)?; let (res, info) = run_book( book, 1 << 20, RunOpts { linear: true, ..Default::default() }, - WarningOpts::deny_all(), CompileOpts::heavy(), + diagnostics_cfg, None, )?; - Ok(format!("{}{}", display_readback_errors(&info.readback_errors), res)) + Ok(format!("{}{}", info.diagnostics, res)) }); } #[test] @@ -172,6 +177,10 @@ fn run_file() { #[test] fn run_lazy() { run_golden_test_dir(function_name!(), &|code, path| { + let diagnostics_cfg = DiagnosticsConfig { + mutual_recursion_cycle: Severity::Allow, + ..DiagnosticsConfig::new(Severity::Error, true) + }; let book = do_parse_book(code, path)?; let mut desugar_opts = CompileOpts::heavy(); @@ -179,8 +188,8 @@ fn run_lazy() { desugar_opts.lazy_mode(); // 1 million nodes for the test runtime. Smaller doesn't seem to make it any faster - let (res, info) = run_book(book, 1 << 24, run_opts, WarningOpts::deny_all(), desugar_opts, None)?; - Ok(format!("{}{}", display_readback_errors(&info.readback_errors), res)) + let (res, info) = run_book(book, 1 << 24, run_opts, desugar_opts, diagnostics_cfg, None)?; + Ok(format!("{}{}", info.diagnostics, res)) }) } @@ -190,16 +199,18 @@ fn readback_lnet() { let net = do_parse_net(code)?; let book = Book::default(); let compat_net = hvmc_to_net(&net); - let (term, errors) = net_to_term(&compat_net, &book, &Labels::default(), false); - Ok(format!("{}{}", display_readback_errors(&errors), term)) + let mut diags = Diagnostics::default(); + let term = net_to_term(&compat_net, &book, &Labels::default(), false, &mut diags); + Ok(format!("{}{}", diags, term)) }) } #[test] fn simplify_matches() { run_golden_test_dir(function_name!(), &|code, path| { + let diagnostics_cfg = DiagnosticsConfig::new(Severity::Error, true); let mut book = do_parse_book(code, path)?; - let mut ctx = Ctx::new(&mut book); + let mut ctx = Ctx::new(&mut book, diagnostics_cfg); ctx.check_shared_names(); ctx.set_entrypoint(); ctx.book.encode_adts(AdtEncoding::TaggedScott); @@ -214,7 +225,7 @@ fn simplify_matches() { ctx.check_ctrs_arities()?; ctx.check_unbound_vars()?; ctx.simplify_matches()?; - ctx.linearize_simple_matches(true)?; + ctx.book.linearize_simple_matches(true); ctx.check_unbound_vars()?; ctx.book.make_var_names_unique(); ctx.book.linearize_vars(); @@ -236,8 +247,9 @@ fn encode_pattern_match() { run_golden_test_dir(function_name!(), &|code, path| { let mut result = String::new(); for adt_encoding in [AdtEncoding::TaggedScott, AdtEncoding::Scott] { + let diagnostics_cfg = DiagnosticsConfig::new(Severity::Error, true); let mut book = do_parse_book(code, path)?; - let mut ctx = Ctx::new(&mut book); + let mut ctx = Ctx::new(&mut book, diagnostics_cfg); ctx.check_shared_names(); ctx.set_entrypoint(); ctx.book.encode_adts(adt_encoding); @@ -252,7 +264,7 @@ fn encode_pattern_match() { ctx.check_ctrs_arities()?; ctx.check_unbound_vars()?; ctx.simplify_matches()?; - ctx.linearize_simple_matches(true)?; + ctx.book.linearize_simple_matches(true); ctx.book.encode_simple_matches(adt_encoding); ctx.check_unbound_vars()?; ctx.book.make_var_names_unique(); @@ -269,8 +281,9 @@ fn encode_pattern_match() { #[test] fn desugar_file() { run_golden_test_dir(function_name!(), &|code, path| { + let diagnostics_cfg = DiagnosticsConfig::new(Severity::Error, true); let mut book = do_parse_book(code, path)?; - desugar_book(&mut book, CompileOpts::light(), None)?; + desugar_book(&mut book, CompileOpts::light(), diagnostics_cfg, None)?; Ok(book.to_string()) }) } @@ -281,40 +294,42 @@ fn hangs() { let expected_normalization_time = 5; run_golden_test_dir(function_name!(), &|code, path| { + let diagnostics_cfg = DiagnosticsConfig::new(Severity::Error, true); let book = do_parse_book(code, path)?; let lck = Arc::new(RwLock::new(false)); let got = lck.clone(); std::thread::spawn(move || { - let _ = - run_book(book, 1 << 20, RunOpts::default(), WarningOpts::deny_all(), CompileOpts::heavy(), None); + let _ = run_book(book, 1 << 20, RunOpts::default(), CompileOpts::heavy(), diagnostics_cfg, None); *got.write().unwrap() = true; }); std::thread::sleep(std::time::Duration::from_secs(expected_normalization_time)); - if !*lck.read().unwrap() { Ok("Hangs".into()) } else { Err("Doesn't hang".into()) } + if !*lck.read().unwrap() { Ok("Hangs".into()) } else { Err("Doesn't hang".to_string().into()) } }) } #[test] fn compile_entrypoint() { run_golden_test_dir(function_name!(), &|code, path| { + let diagnostics_cfg = DiagnosticsConfig::new(Severity::Error, true); let mut book = do_parse_book(code, path)?; book.entrypoint = Some(Name::from("foo")); - let compiled = compile_book(&mut book, true /*ignore check_cycles*/, CompileOpts::light(), None)?; - Ok(format!("{:?}", compiled)) + let res = compile_book(&mut book, CompileOpts::light(), diagnostics_cfg, None)?; + Ok(format!("{}{}", res.diagnostics, res.core_book)) }) } #[test] fn run_entrypoint() { run_golden_test_dir(function_name!(), &|code, path| { + let diagnostics_cfg = DiagnosticsConfig::new(Severity::Error, true); let mut book = do_parse_book(code, path)?; book.entrypoint = Some(Name::from("foo")); // 1 million nodes for the test runtime. Smaller doesn't seem to make it any faster let (res, info) = - run_book(book, 1 << 24, RunOpts::default(), WarningOpts::deny_all(), CompileOpts::heavy(), None)?; - Ok(format!("{}{}", display_readback_errors(&info.readback_errors), res)) + run_book(book, 1 << 24, RunOpts::default(), CompileOpts::heavy(), diagnostics_cfg, None)?; + Ok(format!("{}{}", info.diagnostics, res)) }) } @@ -325,7 +340,7 @@ fn cli() { assert!(args_path.set_extension("args")); let mut args_buf = String::with_capacity(16); - let mut args_file = fs::File::open(args_path).expect("File exists"); + let mut args_file = std::fs::File::open(args_path).expect("File exists"); args_file.read_to_string(&mut args_buf).expect("Read args"); let args = args_buf.lines(); @@ -339,8 +354,12 @@ fn cli() { #[test] fn mutual_recursion() { run_golden_test_dir(function_name!(), &|code, path| { + let diagnostics_cfg = DiagnosticsConfig { + mutual_recursion_cycle: Severity::Error, + ..DiagnosticsConfig::new(Severity::Allow, true) + }; let mut book = do_parse_book(code, path)?; - let compiled = compile_book(&mut book, false, CompileOpts::light(), None)?; - Ok(format!("{:?}", compiled)) + let res = compile_book(&mut book, CompileOpts::light(), diagnostics_cfg, None)?; + Ok(format!("{}{}", res.diagnostics, res.core_book)) }) } diff --git a/tests/golden_tests/cli/warn_and_err.args b/tests/golden_tests/cli/warn_and_err.args new file mode 100644 index 00000000..d73c45ea --- /dev/null +++ b/tests/golden_tests/cli/warn_and_err.args @@ -0,0 +1,2 @@ +compile +tests/golden_tests/cli/warn_and_err.hvm diff --git a/tests/golden_tests/cli/warn_and_err.hvm b/tests/golden_tests/cli/warn_and_err.hvm new file mode 100644 index 00000000..4324c89f --- /dev/null +++ b/tests/golden_tests/cli/warn_and_err.hvm @@ -0,0 +1,3 @@ +Foo a a = a + +Main = (Foo a) \ No newline at end of file diff --git a/tests/golden_tests/compile_file/warn_and_err.hvm b/tests/golden_tests/compile_file/warn_and_err.hvm new file mode 100644 index 00000000..4324c89f --- /dev/null +++ b/tests/golden_tests/compile_file/warn_and_err.hvm @@ -0,0 +1,3 @@ +Foo a a = a + +Main = (Foo a) \ No newline at end of file diff --git a/tests/snapshots/cli__compile_pre_reduce.hvm.snap b/tests/snapshots/cli__compile_pre_reduce.hvm.snap index 29cdb1d8..24880e54 100644 --- a/tests/snapshots/cli__compile_pre_reduce.hvm.snap +++ b/tests/snapshots/cli__compile_pre_reduce.hvm.snap @@ -6,6 +6,5 @@ Warnings: In definition 'I': Definition is unused. - @I = #5 @main = * diff --git a/tests/snapshots/cli__desugar_merge.hvm.snap b/tests/snapshots/cli__desugar_merge.hvm.snap index 1a2ab0a4..a7ff569f 100644 --- a/tests/snapshots/cli__desugar_merge.hvm.snap +++ b/tests/snapshots/cli__desugar_merge.hvm.snap @@ -2,6 +2,10 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/cli/desugar_merge.hvm --- +Warnings: +In definition 'Z': + Definition is unused. + (F_$_Z) = λ* λb b (main) = F_$_Z diff --git a/tests/snapshots/cli__desugar_ref_to_ref.hvm.snap b/tests/snapshots/cli__desugar_ref_to_ref.hvm.snap index 01462e5f..8d531e4e 100644 --- a/tests/snapshots/cli__desugar_ref_to_ref.hvm.snap +++ b/tests/snapshots/cli__desugar_ref_to_ref.hvm.snap @@ -2,6 +2,10 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/cli/desugar_ref_to_ref.hvm --- +Warnings: +In definition 'Bar': + Definition is unused. + (Foo) = λ* 0 (Bar) = Foo diff --git a/tests/snapshots/cli__desugar_simplify_main.hvm.snap b/tests/snapshots/cli__desugar_simplify_main.hvm.snap index 33d62237..8f835810 100644 --- a/tests/snapshots/cli__desugar_simplify_main.hvm.snap +++ b/tests/snapshots/cli__desugar_simplify_main.hvm.snap @@ -2,6 +2,10 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/cli/desugar_simplify_main.hvm --- +Warnings: +In definition 'id': + Definition is unused. + (id) = λa a (main) = λa a diff --git a/tests/snapshots/cli__warn_and_err.hvm.snap b/tests/snapshots/cli__warn_and_err.hvm.snap new file mode 100644 index 00000000..8ccfed5a --- /dev/null +++ b/tests/snapshots/cli__warn_and_err.hvm.snap @@ -0,0 +1,11 @@ +--- +source: tests/golden_tests.rs +input_file: tests/golden_tests/cli/warn_and_err.hvm +--- +Warnings: +In definition 'Foo': + Repeated bind inside rule pattern: 'a'. + +Errors: +In definition 'Main': + Unbound variable 'a'. diff --git a/tests/snapshots/compile_file__crlf.hvm.snap b/tests/snapshots/compile_file__crlf.hvm.snap index 3609f7dc..3974dd4d 100644 --- a/tests/snapshots/compile_file__crlf.hvm.snap +++ b/tests/snapshots/compile_file__crlf.hvm.snap @@ -2,7 +2,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/crlf.hvm --- -// Warnings: +Warnings: In definition 'a': Definition is unused. diff --git a/tests/snapshots/compile_file__error_data_def_name.hvm.snap b/tests/snapshots/compile_file__error_data_def_name.hvm.snap index 6cb6428d..58de22ac 100644 --- a/tests/snapshots/compile_file__error_data_def_name.hvm.snap +++ b/tests/snapshots/compile_file__error_data_def_name.hvm.snap @@ -2,4 +2,5 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/error_data_def_name.hvm --- -Duplicated top-level name 'A'. +Errors: +Function 'A' has the same name as a previously defined constructor diff --git a/tests/snapshots/compile_file__error_messages.hvm.snap b/tests/snapshots/compile_file__error_messages.hvm.snap index a24e2c01..768d39f9 100644 --- a/tests/snapshots/compile_file__error_messages.hvm.snap +++ b/tests/snapshots/compile_file__error_messages.hvm.snap @@ -2,5 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/error_messages.hvm --- +Errors: At tests/golden_tests/compile_file/error_messages.hvm:3:10: Repeated constructor 'B'  3 | data C = (B) diff --git a/tests/snapshots/compile_file__just_a_name.hvm.snap b/tests/snapshots/compile_file__just_a_name.hvm.snap index f552fa11..e30831e4 100644 --- a/tests/snapshots/compile_file__just_a_name.hvm.snap +++ b/tests/snapshots/compile_file__just_a_name.hvm.snap @@ -2,5 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/just_a_name.hvm --- +Errors: At tests/golden_tests/compile_file/just_a_name.hvm:1:1: found end of input expected '+', '(', '[', or '='  1 | asdf diff --git a/tests/snapshots/compile_file__just_data.hvm.snap b/tests/snapshots/compile_file__just_data.hvm.snap index a911e89b..17b54de0 100644 --- a/tests/snapshots/compile_file__just_data.hvm.snap +++ b/tests/snapshots/compile_file__just_data.hvm.snap @@ -2,5 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/just_data.hvm --- +Errors: At tests/golden_tests/compile_file/just_data.hvm:1:5: found end of input expected  1 | data diff --git a/tests/snapshots/compile_file__just_paren.hvm.snap b/tests/snapshots/compile_file__just_paren.hvm.snap index cd00e3e2..9e4de9f1 100644 --- a/tests/snapshots/compile_file__just_paren.hvm.snap +++ b/tests/snapshots/compile_file__just_paren.hvm.snap @@ -2,5 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/just_paren.hvm --- +Errors: At tests/golden_tests/compile_file/just_paren.hvm:2:1: found end of input expected  2 | ( diff --git a/tests/snapshots/compile_file__just_rule_paren.hvm.snap b/tests/snapshots/compile_file__just_rule_paren.hvm.snap index 2ba1aeb6..321091c4 100644 --- a/tests/snapshots/compile_file__just_rule_paren.hvm.snap +++ b/tests/snapshots/compile_file__just_rule_paren.hvm.snap @@ -2,5 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/just_rule_paren.hvm --- +Errors: At tests/golden_tests/compile_file/just_rule_paren.hvm:1:6: found end of input expected =  1 | (rule) diff --git a/tests/snapshots/compile_file__match_num_all_patterns.hvm.snap b/tests/snapshots/compile_file__match_num_all_patterns.hvm.snap index 939d809b..0534e916 100644 --- a/tests/snapshots/compile_file__match_num_all_patterns.hvm.snap +++ b/tests/snapshots/compile_file__match_num_all_patterns.hvm.snap @@ -2,7 +2,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/match_num_all_patterns.hvm --- -// Warnings: +Warnings: In definition 'succ_var': Definition is unused. In definition 'succ_var_zero': diff --git a/tests/snapshots/compile_file__match_num_unscoped_lambda.hvm.snap b/tests/snapshots/compile_file__match_num_unscoped_lambda.hvm.snap index 1938ef3e..a859b220 100644 --- a/tests/snapshots/compile_file__match_num_unscoped_lambda.hvm.snap +++ b/tests/snapshots/compile_file__match_num_unscoped_lambda.hvm.snap @@ -2,7 +2,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/match_num_unscoped_lambda.hvm --- -// Warnings: +Warnings: In definition 'lambda_in': Definition is unused. In definition 'lambda_out': diff --git a/tests/snapshots/compile_file__missing_adt_eq.hvm.snap b/tests/snapshots/compile_file__missing_adt_eq.hvm.snap index b971f611..12669988 100644 --- a/tests/snapshots/compile_file__missing_adt_eq.hvm.snap +++ b/tests/snapshots/compile_file__missing_adt_eq.hvm.snap @@ -2,5 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/missing_adt_eq.hvm --- +Errors: At tests/golden_tests/compile_file/missing_adt_eq.hvm:1:9: found end of input expected '='  1 | data Adt diff --git a/tests/snapshots/compile_file__missing_ctrs.hvm.snap b/tests/snapshots/compile_file__missing_ctrs.hvm.snap index 678d3b4c..a5d37015 100644 --- a/tests/snapshots/compile_file__missing_ctrs.hvm.snap +++ b/tests/snapshots/compile_file__missing_ctrs.hvm.snap @@ -2,5 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/missing_ctrs.hvm --- +Errors: At tests/golden_tests/compile_file/missing_ctrs.hvm:1:12: found end of input expected constructor  1 | data Adt =  diff --git a/tests/snapshots/compile_file__missing_pat.hvm.snap b/tests/snapshots/compile_file__missing_pat.hvm.snap index 93fd5db3..d56dbd0f 100644 --- a/tests/snapshots/compile_file__missing_pat.hvm.snap +++ b/tests/snapshots/compile_file__missing_pat.hvm.snap @@ -2,5 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/missing_pat.hvm --- +Errors: At tests/golden_tests/compile_file/missing_pat.hvm:2:3: found ':' expected '(', '#', '$', , '[', '{', 'λ', 'let', 'match', '*', '|', +, , , or  2 | : * diff --git a/tests/snapshots/compile_file__nested_ctr_wrong_arity.hvm.snap b/tests/snapshots/compile_file__nested_ctr_wrong_arity.hvm.snap index b1bb3e2e..cddfacc1 100644 --- a/tests/snapshots/compile_file__nested_ctr_wrong_arity.hvm.snap +++ b/tests/snapshots/compile_file__nested_ctr_wrong_arity.hvm.snap @@ -2,5 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/nested_ctr_wrong_arity.hvm --- +Errors: In definition 'fst_fst': Constructor arity mismatch in pattern matching. Constructor 'Pair' expects 2 fields, found 1. diff --git a/tests/snapshots/compile_file__ref_to_main.hvm.snap b/tests/snapshots/compile_file__ref_to_main.hvm.snap index 9d2472d6..feb5dfc7 100644 --- a/tests/snapshots/compile_file__ref_to_main.hvm.snap +++ b/tests/snapshots/compile_file__ref_to_main.hvm.snap @@ -2,6 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/ref_to_main.hvm --- +Errors: In definition 'Foo': Main definition can't be referenced inside the program. - diff --git a/tests/snapshots/compile_file__repeated_bind_match.hvm.snap b/tests/snapshots/compile_file__repeated_bind_match.hvm.snap index 95c3e681..6cc335d6 100644 --- a/tests/snapshots/compile_file__repeated_bind_match.hvm.snap +++ b/tests/snapshots/compile_file__repeated_bind_match.hvm.snap @@ -2,7 +2,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/repeated_bind_match.hvm --- -// Warnings: +Warnings: In definition 'main': Repeated bind inside match arm: 'x'. diff --git a/tests/snapshots/compile_file__repeated_bind_rule.hvm.snap b/tests/snapshots/compile_file__repeated_bind_rule.hvm.snap index 8c4c8339..4d647e2d 100644 --- a/tests/snapshots/compile_file__repeated_bind_rule.hvm.snap +++ b/tests/snapshots/compile_file__repeated_bind_rule.hvm.snap @@ -2,7 +2,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/repeated_bind_rule.hvm --- -// Warnings: +Warnings: In definition 'Foo': Repeated bind inside rule pattern: 'a'. diff --git a/tests/snapshots/compile_file__unbound_unscoped_var.hvm.snap b/tests/snapshots/compile_file__unbound_unscoped_var.hvm.snap index 3c5a5f43..4386b061 100644 --- a/tests/snapshots/compile_file__unbound_unscoped_var.hvm.snap +++ b/tests/snapshots/compile_file__unbound_unscoped_var.hvm.snap @@ -2,6 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/unbound_unscoped_var.hvm --- +Errors: In definition 'main': Unbound unscoped variable '$a'. - diff --git a/tests/snapshots/compile_file__unbound_with_tup_pattern.hvm.snap b/tests/snapshots/compile_file__unbound_with_tup_pattern.hvm.snap index bcd3e0be..c2c715ca 100644 --- a/tests/snapshots/compile_file__unbound_with_tup_pattern.hvm.snap +++ b/tests/snapshots/compile_file__unbound_with_tup_pattern.hvm.snap @@ -2,6 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/unbound_with_tup_pattern.hvm --- +Errors: In definition 'Foo': Unbound variable 'a'. - diff --git a/tests/snapshots/compile_file__unexpected_top_char.hvm.snap b/tests/snapshots/compile_file__unexpected_top_char.hvm.snap index 0e25b6d0..6cc24dce 100644 --- a/tests/snapshots/compile_file__unexpected_top_char.hvm.snap +++ b/tests/snapshots/compile_file__unexpected_top_char.hvm.snap @@ -2,5 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/unexpected_top_char.hvm --- +Errors: At tests/golden_tests/compile_file/unexpected_top_char.hvm:1:1: found end of input expected data, , or '('  1 | * diff --git a/tests/snapshots/compile_file__unscoped_dup_use.hvm.snap b/tests/snapshots/compile_file__unscoped_dup_use.hvm.snap index 95e3c183..d4a83d1e 100644 --- a/tests/snapshots/compile_file__unscoped_dup_use.hvm.snap +++ b/tests/snapshots/compile_file__unscoped_dup_use.hvm.snap @@ -2,6 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/unscoped_dup_use.hvm --- +Errors: In definition 'main': Unscoped variable '$a' used more than once. - diff --git a/tests/snapshots/compile_file__unused_unscoped_bind.hvm.snap b/tests/snapshots/compile_file__unused_unscoped_bind.hvm.snap index db1fe784..99bc5221 100644 --- a/tests/snapshots/compile_file__unused_unscoped_bind.hvm.snap +++ b/tests/snapshots/compile_file__unused_unscoped_bind.hvm.snap @@ -2,6 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/unused_unscoped_bind.hvm --- +Errors: In definition 'main': Unscoped variable from lambda 'λ$a' is never used. - diff --git a/tests/snapshots/compile_file__warn_and_err.hvm.snap b/tests/snapshots/compile_file__warn_and_err.hvm.snap new file mode 100644 index 00000000..38a42ccb --- /dev/null +++ b/tests/snapshots/compile_file__warn_and_err.hvm.snap @@ -0,0 +1,11 @@ +--- +source: tests/golden_tests.rs +input_file: tests/golden_tests/compile_file/warn_and_err.hvm +--- +Warnings: +In definition 'Foo': + Repeated bind inside rule pattern: 'a'. + +Errors: +In definition 'Main': + Unbound variable 'a'. diff --git a/tests/snapshots/compile_file__wrong_ctr_arity.hvm.snap b/tests/snapshots/compile_file__wrong_ctr_arity.hvm.snap index a40a9141..f71b97ae 100644 --- a/tests/snapshots/compile_file__wrong_ctr_arity.hvm.snap +++ b/tests/snapshots/compile_file__wrong_ctr_arity.hvm.snap @@ -2,6 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/wrong_ctr_arity.hvm --- +Errors: In definition 'Bar': Constructor arity mismatch in pattern matching. Constructor 'Box' expects 1 fields, found 2. - diff --git a/tests/snapshots/compile_file__wrong_ctr_var_arity.hvm.snap b/tests/snapshots/compile_file__wrong_ctr_var_arity.hvm.snap index 5d584c10..a8fb6631 100644 --- a/tests/snapshots/compile_file__wrong_ctr_var_arity.hvm.snap +++ b/tests/snapshots/compile_file__wrong_ctr_var_arity.hvm.snap @@ -2,6 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/wrong_ctr_var_arity.hvm --- +Errors: In definition 'foo': Constructor arity mismatch in pattern matching. Constructor 'pair' expects 2 fields, found 0. - diff --git a/tests/snapshots/compile_file_o_all__adt_string.hvm.snap b/tests/snapshots/compile_file_o_all__adt_string.hvm.snap index b0438403..6ca16cdd 100644 --- a/tests/snapshots/compile_file_o_all__adt_string.hvm.snap +++ b/tests/snapshots/compile_file_o_all__adt_string.hvm.snap @@ -2,5 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file_o_all/adt_string.hvm --- +Errors: At tests/golden_tests/compile_file_o_all/adt_string.hvm:1:6: String is a built-in datatype and should not be overridden.  1 | data String = S diff --git a/tests/snapshots/compile_file_o_all__bad_parens_making_erased_let.hvm.snap b/tests/snapshots/compile_file_o_all__bad_parens_making_erased_let.hvm.snap index 3045e01a..10d1ffaf 100644 --- a/tests/snapshots/compile_file_o_all__bad_parens_making_erased_let.hvm.snap +++ b/tests/snapshots/compile_file_o_all__bad_parens_making_erased_let.hvm.snap @@ -2,7 +2,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file_o_all/bad_parens_making_erased_let.hvm --- +Errors: In definition 'main': Unbound variable 'two'. Unbound variable 'qua'. - diff --git a/tests/snapshots/compile_file_o_all__cyclic_dup.hvm.snap b/tests/snapshots/compile_file_o_all__cyclic_dup.hvm.snap index 18228a48..785e5990 100644 --- a/tests/snapshots/compile_file_o_all__cyclic_dup.hvm.snap +++ b/tests/snapshots/compile_file_o_all__cyclic_dup.hvm.snap @@ -2,6 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file_o_all/cyclic_dup.hvm --- +Errors: In definition 'main': Unbound variable 'y1'. - diff --git a/tests/snapshots/compile_file_o_all__double_main.hvm.snap b/tests/snapshots/compile_file_o_all__double_main.hvm.snap index f9119791..b3856a19 100644 --- a/tests/snapshots/compile_file_o_all__double_main.hvm.snap +++ b/tests/snapshots/compile_file_o_all__double_main.hvm.snap @@ -2,4 +2,5 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file_o_all/double_main.hvm --- +Errors: File has both 'main' and 'Main' definitions. diff --git a/tests/snapshots/compile_file_o_all__let_adt_non_exhaustive.hvm.snap b/tests/snapshots/compile_file_o_all__let_adt_non_exhaustive.hvm.snap index eb704260..1ae92f1a 100644 --- a/tests/snapshots/compile_file_o_all__let_adt_non_exhaustive.hvm.snap +++ b/tests/snapshots/compile_file_o_all__let_adt_non_exhaustive.hvm.snap @@ -2,7 +2,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file_o_all/let_adt_non_exhaustive.hvm --- +Errors: In definition 'main': Non-exhaustive pattern matching. Hint: Case 'None' not covered. - diff --git a/tests/snapshots/compile_file_o_all__match_adt_non_exhaustive.hvm.snap b/tests/snapshots/compile_file_o_all__match_adt_non_exhaustive.hvm.snap index 7ecdf054..c23745ef 100644 --- a/tests/snapshots/compile_file_o_all__match_adt_non_exhaustive.hvm.snap +++ b/tests/snapshots/compile_file_o_all__match_adt_non_exhaustive.hvm.snap @@ -2,7 +2,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file_o_all/match_adt_non_exhaustive.hvm --- +Errors: In definition 'main': Non-exhaustive pattern matching. Hint: Case 'Some' not covered. - diff --git a/tests/snapshots/compile_file_o_all__non_exhaustive_and.hvm.snap b/tests/snapshots/compile_file_o_all__non_exhaustive_and.hvm.snap index eb10cf0d..7bbbad94 100644 --- a/tests/snapshots/compile_file_o_all__non_exhaustive_and.hvm.snap +++ b/tests/snapshots/compile_file_o_all__non_exhaustive_and.hvm.snap @@ -2,7 +2,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file_o_all/non_exhaustive_and.hvm --- +Errors: In definition 'Bool.and': Non-exhaustive pattern matching. Hint: Case 'F' not covered. - diff --git a/tests/snapshots/compile_file_o_all__non_exhaustive_different_types.hvm.snap b/tests/snapshots/compile_file_o_all__non_exhaustive_different_types.hvm.snap index 8daab652..e40de091 100644 --- a/tests/snapshots/compile_file_o_all__non_exhaustive_different_types.hvm.snap +++ b/tests/snapshots/compile_file_o_all__non_exhaustive_different_types.hvm.snap @@ -2,7 +2,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file_o_all/non_exhaustive_different_types.hvm --- +Errors: In definition 'foo': Non-exhaustive pattern matching. Hint: Case 't3' not covered. - diff --git a/tests/snapshots/compile_file_o_all__non_exhaustive_pattern.hvm.snap b/tests/snapshots/compile_file_o_all__non_exhaustive_pattern.hvm.snap index 12a7e29a..0e3f9afd 100644 --- a/tests/snapshots/compile_file_o_all__non_exhaustive_pattern.hvm.snap +++ b/tests/snapshots/compile_file_o_all__non_exhaustive_pattern.hvm.snap @@ -2,7 +2,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file_o_all/non_exhaustive_pattern.hvm --- +Errors: In definition 'Foo': Non-exhaustive pattern matching. Hint: Case 'A' not covered. - diff --git a/tests/snapshots/compile_file_o_all__non_exhaustive_tree.hvm.snap b/tests/snapshots/compile_file_o_all__non_exhaustive_tree.hvm.snap index 91a12ece..8bcc44b4 100644 --- a/tests/snapshots/compile_file_o_all__non_exhaustive_tree.hvm.snap +++ b/tests/snapshots/compile_file_o_all__non_exhaustive_tree.hvm.snap @@ -2,7 +2,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file_o_all/non_exhaustive_tree.hvm --- +Errors: In definition 'Warp': Non-exhaustive pattern matching. Hint: Case 'Both' not covered. - diff --git a/tests/snapshots/compile_file_o_all__repeated_name_trucation.hvm.snap b/tests/snapshots/compile_file_o_all__repeated_name_trucation.hvm.snap index 1afcc189..91f26475 100644 --- a/tests/snapshots/compile_file_o_all__repeated_name_trucation.hvm.snap +++ b/tests/snapshots/compile_file_o_all__repeated_name_trucation.hvm.snap @@ -2,8 +2,13 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file_o_all/repeated_name_trucation.hvm --- +Warnings: +Mutual recursion cycle detected in compiled functions: + Cycle 1: long_name_that_truncates -> long_name_that_truncates$S0 -> long_name_that_truncates + This program will expand infinitely in strict evaluation mode. + Read https://github.com/HigherOrderCO/hvm-lang/blob/main/docs/lazy-definitions.md for more information. + @long_name_that_truncates = (* @long_name_that_truncates$S0) @long_name_that_truncates$S0 = (* @long_name_that_truncates) @main = a & @long_name_that_truncates ~ ((b b) a) - diff --git a/tests/snapshots/compile_file_o_all__self_ref.hvm.snap b/tests/snapshots/compile_file_o_all__self_ref.hvm.snap index 8fd24eb6..d8a2494b 100644 --- a/tests/snapshots/compile_file_o_all__self_ref.hvm.snap +++ b/tests/snapshots/compile_file_o_all__self_ref.hvm.snap @@ -2,8 +2,8 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file_o_all/self_ref.hvm --- +Errors: In definition 'Foo': Definition is a reference to itself. In definition 'main': Definition is a reference to itself. - diff --git a/tests/snapshots/compile_term__cyclic_global_lam.hvm.snap b/tests/snapshots/compile_term__cyclic_global_lam.hvm.snap index fc81c167..3213e3f3 100644 --- a/tests/snapshots/compile_term__cyclic_global_lam.hvm.snap +++ b/tests/snapshots/compile_term__cyclic_global_lam.hvm.snap @@ -2,4 +2,5 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_term/cyclic_global_lam.hvm --- +Errors: Found term that compiles into an inet with a vicious cycle diff --git a/tests/snapshots/compile_term__unbound_var.hvm.snap b/tests/snapshots/compile_term__unbound_var.hvm.snap index 4803ad94..cf990073 100644 --- a/tests/snapshots/compile_term__unbound_var.hvm.snap +++ b/tests/snapshots/compile_term__unbound_var.hvm.snap @@ -2,4 +2,5 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_term/unbound_var.hvm --- +Errors: Unbound variable 'a'. diff --git a/tests/snapshots/compile_term__unbound_var_scope.hvm.snap b/tests/snapshots/compile_term__unbound_var_scope.hvm.snap index fdd658aa..bb07c378 100644 --- a/tests/snapshots/compile_term__unbound_var_scope.hvm.snap +++ b/tests/snapshots/compile_term__unbound_var_scope.hvm.snap @@ -2,4 +2,5 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_term/unbound_var_scope.hvm --- +Errors: Unbound variable 'b'. diff --git a/tests/snapshots/compile_term__wrong_nums.hvm.snap b/tests/snapshots/compile_term__wrong_nums.hvm.snap index 38a2b1b0..81cae79c 100644 --- a/tests/snapshots/compile_term__wrong_nums.hvm.snap +++ b/tests/snapshots/compile_term__wrong_nums.hvm.snap @@ -2,5 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_term/wrong_nums.hvm --- +Errors: found invalid number literal expected number found invalid number literal expected number diff --git a/tests/snapshots/desugar_file__non_exaustive_limit.hvm.snap b/tests/snapshots/desugar_file__non_exaustive_limit.hvm.snap index 3b9d0f3d..0e234604 100644 --- a/tests/snapshots/desugar_file__non_exaustive_limit.hvm.snap +++ b/tests/snapshots/desugar_file__non_exaustive_limit.hvm.snap @@ -2,7 +2,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/desugar_file/non_exaustive_limit.hvm --- +Errors: In definition 'Bar': Non-exhaustive pattern matching. Hint: Case 'B' not covered. - diff --git a/tests/snapshots/hangs__recursive_with_unscoped.hvm.snap.new b/tests/snapshots/hangs__recursive_with_unscoped.hvm.snap.new new file mode 100644 index 00000000..b43c0073 --- /dev/null +++ b/tests/snapshots/hangs__recursive_with_unscoped.hvm.snap.new @@ -0,0 +1,7 @@ +--- +source: tests/golden_tests.rs +assertion_line: 64 +input_file: tests/golden_tests/hangs/recursive_with_unscoped.hvm +--- +Errors: +Doesn't hang diff --git a/tests/snapshots/mutual_recursion__a_b_c.hvm.snap b/tests/snapshots/mutual_recursion__a_b_c.hvm.snap index c839e890..6bed21d2 100644 --- a/tests/snapshots/mutual_recursion__a_b_c.hvm.snap +++ b/tests/snapshots/mutual_recursion__a_b_c.hvm.snap @@ -2,7 +2,8 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/mutual_recursion/a_b_c.hvm --- +Errors: Mutual recursion cycle detected in compiled functions: -Cycle 1: A -> B -> C -> A -This program will expand infinitely in strict evaluation mode. -Read https://github.com/HigherOrderCO/hvm-lang/blob/main/docs/lazy-definitions.md for more information. + Cycle 1: A -> B -> C -> A + This program will expand infinitely in strict evaluation mode. + Read https://github.com/HigherOrderCO/hvm-lang/blob/main/docs/lazy-definitions.md for more information. diff --git a/tests/snapshots/mutual_recursion__multiple.hvm.snap b/tests/snapshots/mutual_recursion__multiple.hvm.snap index b8b5f437..d5a1d7ce 100644 --- a/tests/snapshots/mutual_recursion__multiple.hvm.snap +++ b/tests/snapshots/mutual_recursion__multiple.hvm.snap @@ -2,10 +2,11 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/mutual_recursion/multiple.hvm --- +Errors: Mutual recursion cycle detected in compiled functions: -Cycle 1: A -> B -> C -> A -Cycle 2: H -> I -> H -Cycle 3: M -> M -Cycle 4: N -> N -This program will expand infinitely in strict evaluation mode. -Read https://github.com/HigherOrderCO/hvm-lang/blob/main/docs/lazy-definitions.md for more information. + Cycle 1: A -> B -> C -> A + Cycle 2: H -> I -> H + Cycle 3: M -> M + Cycle 4: N -> N + This program will expand infinitely in strict evaluation mode. + Read https://github.com/HigherOrderCO/hvm-lang/blob/main/docs/lazy-definitions.md for more information. diff --git a/tests/snapshots/mutual_recursion__odd_even.hvm.snap b/tests/snapshots/mutual_recursion__odd_even.hvm.snap index 0791ec31..bbbdb0da 100644 --- a/tests/snapshots/mutual_recursion__odd_even.hvm.snap +++ b/tests/snapshots/mutual_recursion__odd_even.hvm.snap @@ -2,7 +2,8 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/mutual_recursion/odd_even.hvm --- +Errors: Mutual recursion cycle detected in compiled functions: -Cycle 1: isEven -> isOdd -> isEven -This program will expand infinitely in strict evaluation mode. -Read https://github.com/HigherOrderCO/hvm-lang/blob/main/docs/lazy-definitions.md for more information. + Cycle 1: isEven -> isOdd -> isEven + This program will expand infinitely in strict evaluation mode. + Read https://github.com/HigherOrderCO/hvm-lang/blob/main/docs/lazy-definitions.md for more information. diff --git a/tests/snapshots/parse_file__repeated_adt_name.hvm.snap b/tests/snapshots/parse_file__repeated_adt_name.hvm.snap index 3829a36a..d5ffd6ea 100644 --- a/tests/snapshots/parse_file__repeated_adt_name.hvm.snap +++ b/tests/snapshots/parse_file__repeated_adt_name.hvm.snap @@ -2,5 +2,6 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/parse_file/repeated_adt_name.hvm --- +Errors: At tests/golden_tests/parse_file/repeated_adt_name.hvm:2:6: Repeated datatype 'Foo'  2 | data Foo = B diff --git a/tests/snapshots/readback_lnet__bad_net.hvm.snap b/tests/snapshots/readback_lnet__bad_net.hvm.snap index 9b054c73..5fda17e0 100644 --- a/tests/snapshots/readback_lnet__bad_net.hvm.snap +++ b/tests/snapshots/readback_lnet__bad_net.hvm.snap @@ -2,6 +2,8 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/readback_lnet/bad_net.hvm --- -Readback Warning: -Reached Root +Warnings: +During readback: + Reached Root. + diff --git a/tests/snapshots/readback_lnet__invalid_mat_mat.hvm.snap b/tests/snapshots/readback_lnet__invalid_mat_mat.hvm.snap index 432597a2..8fb00e8f 100644 --- a/tests/snapshots/readback_lnet__invalid_mat_mat.hvm.snap +++ b/tests/snapshots/readback_lnet__invalid_mat_mat.hvm.snap @@ -2,7 +2,8 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/readback_lnet/invalid_mat_mat.hvm --- -Readback Warning: -Invalid Numeric Match (4 occurrences) +Warnings: +During readback: + Invalid Numeric Match. (4 occurrences) λa match match { 0: 3; 1+*: 4 } { 0: ; 1+: } diff --git a/tests/snapshots/readback_lnet__invalid_op2_op2.hvm.snap b/tests/snapshots/readback_lnet__invalid_op2_op2.hvm.snap index 0c75460f..fbb06871 100644 --- a/tests/snapshots/readback_lnet__invalid_op2_op2.hvm.snap +++ b/tests/snapshots/readback_lnet__invalid_op2_op2.hvm.snap @@ -2,7 +2,8 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/readback_lnet/invalid_op2_op2.hvm --- -Readback Warning: -Invalid Numeric Operation (2 occurrences) +Warnings: +During readback: + Invalid Numeric Operation. (2 occurrences) λa (+ (+ 1) (1 )) diff --git a/tests/snapshots/run_file__addition.hvm.snap b/tests/snapshots/run_file__addition.hvm.snap index 265485b5..7c4b5b52 100644 --- a/tests/snapshots/run_file__addition.hvm.snap +++ b/tests/snapshots/run_file__addition.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/addition.hvm --- Lazy mode: - 10 Strict mode: - 10 diff --git a/tests/snapshots/run_file__adt_match.hvm.snap b/tests/snapshots/run_file__adt_match.hvm.snap index 7dae34ed..7b6e1662 100644 --- a/tests/snapshots/run_file__adt_match.hvm.snap +++ b/tests/snapshots/run_file__adt_match.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/adt_match.hvm --- Lazy mode: - (Some 2) Strict mode: - (Some 2) diff --git a/tests/snapshots/run_file__adt_match_wrong_tag.hvm.snap b/tests/snapshots/run_file__adt_match_wrong_tag.hvm.snap index 1ab6c3b6..66d0d02c 100644 --- a/tests/snapshots/run_file__adt_match_wrong_tag.hvm.snap +++ b/tests/snapshots/run_file__adt_match_wrong_tag.hvm.snap @@ -3,15 +3,17 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/adt_match_wrong_tag.hvm --- Lazy mode: +Warnings: +During readback: + Unexpected tag found during Adt readback, expected '#Option', but found '#wrong_tag'. + Invalid Adt Match. -Readback Warning: -Unexpected tag found during Adt readback, expected '#Option', but found '#wrong_tag' -Invalid Adt Match λa match a { (Some Some.val): #Option (#wrong_tag λb b Some.val); (None): * } Strict mode: +Warnings: +During readback: + Unexpected tag found during Adt readback, expected '#Option', but found '#wrong_tag'. + Invalid Adt Match. -Readback Warning: -Unexpected tag found during Adt readback, expected '#Option', but found '#wrong_tag' -Invalid Adt Match λa match a { (Some Some.val): #Option (#wrong_tag λb b Some.val); (None): * } diff --git a/tests/snapshots/run_file__adt_option_and.hvm.snap b/tests/snapshots/run_file__adt_option_and.hvm.snap index fc3dc86d..2b6ec01d 100644 --- a/tests/snapshots/run_file__adt_option_and.hvm.snap +++ b/tests/snapshots/run_file__adt_option_and.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/adt_option_and.hvm --- Lazy mode: - λa λb match a { (Some c): match b { (Some d): (Some (c, d)); (None): None }; (None): None } Strict mode: - λa match a { (Some b): λc (match c { (Some d): λe (Some (e, d)); (None): λ* None } b); (None): λ* None } diff --git a/tests/snapshots/run_file__adt_wrong_tag.hvm.snap b/tests/snapshots/run_file__adt_wrong_tag.hvm.snap index 19e1bcf2..efc9ce81 100644 --- a/tests/snapshots/run_file__adt_wrong_tag.hvm.snap +++ b/tests/snapshots/run_file__adt_wrong_tag.hvm.snap @@ -3,15 +3,17 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/adt_wrong_tag.hvm --- Lazy mode: +Warnings: +During readback: + Unexpected tag found during Adt readback, expected '#Option', but found '#wrong_tag'. + Invalid Adt Match. -Readback Warning: -Unexpected tag found during Adt readback, expected '#Option', but found '#wrong_tag' -Invalid Adt Match λa match a { (Some Some.val): #Option (#wrong_tag λb b Some.val); (None): * } Strict mode: +Warnings: +During readback: + Unexpected tag found during Adt readback, expected '#Option', but found '#wrong_tag'. + Invalid Adt Match. -Readback Warning: -Unexpected tag found during Adt readback, expected '#Option', but found '#wrong_tag' -Invalid Adt Match λa match a { (Some Some.val): #Option (#wrong_tag λb b Some.val); (None): * } diff --git a/tests/snapshots/run_file__and.hvm.snap b/tests/snapshots/run_file__and.hvm.snap index 4f22b55a..4270ffc9 100644 --- a/tests/snapshots/run_file__and.hvm.snap +++ b/tests/snapshots/run_file__and.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/and.hvm --- Lazy mode: - false Strict mode: - false diff --git a/tests/snapshots/run_file__bitonic_sort.hvm.snap b/tests/snapshots/run_file__bitonic_sort.hvm.snap index 0d4451d1..28700b54 100644 --- a/tests/snapshots/run_file__bitonic_sort.hvm.snap +++ b/tests/snapshots/run_file__bitonic_sort.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/bitonic_sort.hvm --- Lazy mode: - 120 Strict mode: - 120 diff --git a/tests/snapshots/run_file__bitonic_sort_lam.hvm.snap b/tests/snapshots/run_file__bitonic_sort_lam.hvm.snap index 43bb6d4a..c8b9863a 100644 --- a/tests/snapshots/run_file__bitonic_sort_lam.hvm.snap +++ b/tests/snapshots/run_file__bitonic_sort_lam.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/bitonic_sort_lam.hvm --- Lazy mode: - 32640 Strict mode: - 32640 diff --git a/tests/snapshots/run_file__box.hvm.snap b/tests/snapshots/run_file__box.hvm.snap index 58d180f2..1bcde89b 100644 --- a/tests/snapshots/run_file__box.hvm.snap +++ b/tests/snapshots/run_file__box.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/box.hvm --- Lazy mode: - (Box 10) Strict mode: - (Box 10) diff --git a/tests/snapshots/run_file__box2.hvm.snap b/tests/snapshots/run_file__box2.hvm.snap index b895a219..327b0b53 100644 --- a/tests/snapshots/run_file__box2.hvm.snap +++ b/tests/snapshots/run_file__box2.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/box2.hvm --- Lazy mode: - (Box 4) Strict mode: - (Box 4) diff --git a/tests/snapshots/run_file__callcc.hvm.snap b/tests/snapshots/run_file__callcc.hvm.snap index d4b24a83..5d20cf71 100644 --- a/tests/snapshots/run_file__callcc.hvm.snap +++ b/tests/snapshots/run_file__callcc.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/callcc.hvm --- Lazy mode: - 52 Strict mode: - 52 diff --git a/tests/snapshots/run_file__chars.hvm.snap b/tests/snapshots/run_file__chars.hvm.snap index b8826b41..c0b92693 100644 --- a/tests/snapshots/run_file__chars.hvm.snap +++ b/tests/snapshots/run_file__chars.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/chars.hvm --- Lazy mode: - "ሴ!7" Strict mode: - "ሴ!7" diff --git a/tests/snapshots/run_file__chars_forall.hvm.snap b/tests/snapshots/run_file__chars_forall.hvm.snap index d3b73004..7e729e28 100644 --- a/tests/snapshots/run_file__chars_forall.hvm.snap +++ b/tests/snapshots/run_file__chars_forall.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/chars_forall.hvm --- Lazy mode: - 8704 Strict mode: - 8704 diff --git a/tests/snapshots/run_file__chars_lambda.hvm.snap b/tests/snapshots/run_file__chars_lambda.hvm.snap index 0dad4773..8e212198 100644 --- a/tests/snapshots/run_file__chars_lambda.hvm.snap +++ b/tests/snapshots/run_file__chars_lambda.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/chars_lambda.hvm --- Lazy mode: - 955 Strict mode: - 955 diff --git a/tests/snapshots/run_file__def_bool_num.hvm.snap b/tests/snapshots/run_file__def_bool_num.hvm.snap index fa131680..0bd2a05e 100644 --- a/tests/snapshots/run_file__def_bool_num.hvm.snap +++ b/tests/snapshots/run_file__def_bool_num.hvm.snap @@ -3,15 +3,14 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/def_bool_num.hvm --- Lazy mode: - +Errors: In definition 'go': Non-exhaustive pattern matching. Hint: Case '+' not covered. - Strict mode: - +Errors: In definition 'go': Non-exhaustive pattern matching. Hint: Case '+' not covered. diff --git a/tests/snapshots/run_file__def_num_bool.hvm.snap b/tests/snapshots/run_file__def_num_bool.hvm.snap index b5306ee0..59302bb0 100644 --- a/tests/snapshots/run_file__def_num_bool.hvm.snap +++ b/tests/snapshots/run_file__def_num_bool.hvm.snap @@ -3,15 +3,14 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/def_num_bool.hvm --- Lazy mode: - +Errors: In definition 'go': Non-exhaustive pattern matching. Hint: Case '+' not covered. - Strict mode: - +Errors: In definition 'go': Non-exhaustive pattern matching. Hint: Case '+' not covered. diff --git a/tests/snapshots/run_file__def_tups.hvm.snap b/tests/snapshots/run_file__def_tups.hvm.snap index 0d74fb81..ab456799 100644 --- a/tests/snapshots/run_file__def_tups.hvm.snap +++ b/tests/snapshots/run_file__def_tups.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/def_tups.hvm --- Lazy mode: - 15 Strict mode: - 15 diff --git a/tests/snapshots/run_file__dup_global_lam.hvm.snap b/tests/snapshots/run_file__dup_global_lam.hvm.snap index ef9e21da..d2a6698d 100644 --- a/tests/snapshots/run_file__dup_global_lam.hvm.snap +++ b/tests/snapshots/run_file__dup_global_lam.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/dup_global_lam.hvm --- Lazy mode: - λa a Strict mode: - λa a diff --git a/tests/snapshots/run_file__empty.hvm.snap b/tests/snapshots/run_file__empty.hvm.snap index 23d2f6f0..a9c4d7de 100644 --- a/tests/snapshots/run_file__empty.hvm.snap +++ b/tests/snapshots/run_file__empty.hvm.snap @@ -3,9 +3,10 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/empty.hvm --- Lazy mode: +Errors: File has no 'main' definition. - Strict mode: +Errors: File has no 'main' definition. diff --git a/tests/snapshots/run_file__escape_sequences.hvm.snap b/tests/snapshots/run_file__escape_sequences.hvm.snap index 890d8e37..c122166f 100644 --- a/tests/snapshots/run_file__escape_sequences.hvm.snap +++ b/tests/snapshots/run_file__escape_sequences.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/escape_sequences.hvm --- Lazy mode: - ("\n\r\t\0\"'\u{afe}`", "\n\r\t\0\"'\u{afe}`") Strict mode: - ("\n\r\t\0\"'\u{afe}`", "\n\r\t\0\"'\u{afe}`") diff --git a/tests/snapshots/run_file__eta.hvm.snap b/tests/snapshots/run_file__eta.hvm.snap index 6e458d74..9616d2f8 100644 --- a/tests/snapshots/run_file__eta.hvm.snap +++ b/tests/snapshots/run_file__eta.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/eta.hvm --- Lazy mode: - λa a Strict mode: - λa a diff --git a/tests/snapshots/run_file__example.hvm.snap b/tests/snapshots/run_file__example.hvm.snap index e5e068f6..e9b11aeb 100644 --- a/tests/snapshots/run_file__example.hvm.snap +++ b/tests/snapshots/run_file__example.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/example.hvm --- Lazy mode: - 8 Strict mode: - 8 diff --git a/tests/snapshots/run_file__exp.hvm.snap b/tests/snapshots/run_file__exp.hvm.snap index 8c0137a3..c2770134 100644 --- a/tests/snapshots/run_file__exp.hvm.snap +++ b/tests/snapshots/run_file__exp.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/exp.hvm --- Lazy mode: - λa λb (a (a (a (a b)))) Strict mode: - λa λb (a (a (a (a b)))) diff --git a/tests/snapshots/run_file__extracted_match_pred.hvm.snap b/tests/snapshots/run_file__extracted_match_pred.hvm.snap index 3aacf25e..c699ba72 100644 --- a/tests/snapshots/run_file__extracted_match_pred.hvm.snap +++ b/tests/snapshots/run_file__extracted_match_pred.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/extracted_match_pred.hvm --- Lazy mode: - 0 Strict mode: - 0 diff --git a/tests/snapshots/run_file__field_vectorization.hvm.snap b/tests/snapshots/run_file__field_vectorization.hvm.snap index 8505ee3f..113c02cd 100644 --- a/tests/snapshots/run_file__field_vectorization.hvm.snap +++ b/tests/snapshots/run_file__field_vectorization.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/field_vectorization.hvm --- Lazy mode: - (Cons T (Cons T (Cons F (Cons T Nil)))) Strict mode: - (Cons T (Cons T (Cons F (Cons T Nil)))) diff --git a/tests/snapshots/run_file__id_underscore.hvm.snap b/tests/snapshots/run_file__id_underscore.hvm.snap index 7e996bb4..47e2b0d1 100644 --- a/tests/snapshots/run_file__id_underscore.hvm.snap +++ b/tests/snapshots/run_file__id_underscore.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/id_underscore.hvm --- Lazy mode: - (2, 3) Strict mode: - (2, 3) diff --git a/tests/snapshots/run_file__lam_op2.hvm.snap b/tests/snapshots/run_file__lam_op2.hvm.snap index 6dadaf1d..b060f03f 100644 --- a/tests/snapshots/run_file__lam_op2.hvm.snap +++ b/tests/snapshots/run_file__lam_op2.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/lam_op2.hvm --- Lazy mode: - λa (+ a 2) Strict mode: - λa (+ a 2) diff --git a/tests/snapshots/run_file__lam_op2_nested.hvm.snap b/tests/snapshots/run_file__lam_op2_nested.hvm.snap index a8dcedf5..198a6817 100644 --- a/tests/snapshots/run_file__lam_op2_nested.hvm.snap +++ b/tests/snapshots/run_file__lam_op2_nested.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/lam_op2_nested.hvm --- Lazy mode: - λa (+ (* a a) (+ (+ a 2) 3)) Strict mode: - λa (+ (* a a) (+ (+ a 2) 3)) diff --git a/tests/snapshots/run_file__let_tup_readback.hvm.snap b/tests/snapshots/run_file__let_tup_readback.hvm.snap index fb0b064a..a4777045 100644 --- a/tests/snapshots/run_file__let_tup_readback.hvm.snap +++ b/tests/snapshots/run_file__let_tup_readback.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/let_tup_readback.hvm --- Lazy mode: - λa let (b, c) = a; (b c) Strict mode: - λa let (b, c) = a; (b c) diff --git a/tests/snapshots/run_file__linearize_match.hvm.snap b/tests/snapshots/run_file__linearize_match.hvm.snap index 0167d008..614a80e0 100644 --- a/tests/snapshots/run_file__linearize_match.hvm.snap +++ b/tests/snapshots/run_file__linearize_match.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/linearize_match.hvm --- Lazy mode: - λa match a { 0: λb b; 1+c: λd (+ c d) } Strict mode: - λa match a { 0: λb b; 1+c: λd (+ c d) } diff --git a/tests/snapshots/run_file__list_resugar.hvm.snap b/tests/snapshots/run_file__list_resugar.hvm.snap index 355f9af5..19683993 100644 --- a/tests/snapshots/run_file__list_resugar.hvm.snap +++ b/tests/snapshots/run_file__list_resugar.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/list_resugar.hvm --- Lazy mode: - [42, [λd d]] Strict mode: - [42, [λd d]] diff --git a/tests/snapshots/run_file__list_reverse.hvm.snap b/tests/snapshots/run_file__list_reverse.hvm.snap index 355dd6f2..09d7d963 100644 --- a/tests/snapshots/run_file__list_reverse.hvm.snap +++ b/tests/snapshots/run_file__list_reverse.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/list_reverse.hvm --- Lazy mode: - (cons 1 (cons 2 (cons 3 nil))) Strict mode: - (cons 1 (cons 2 (cons 3 nil))) diff --git a/tests/snapshots/run_file__list_take.hvm.snap b/tests/snapshots/run_file__list_take.hvm.snap index 110530e5..06589704 100644 --- a/tests/snapshots/run_file__list_take.hvm.snap +++ b/tests/snapshots/run_file__list_take.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/list_take.hvm --- Lazy mode: - [3, 2] Strict mode: - [3, 2] diff --git a/tests/snapshots/run_file__list_to_tree.hvm.snap b/tests/snapshots/run_file__list_to_tree.hvm.snap index b79cdddb..ea647db0 100644 --- a/tests/snapshots/run_file__list_to_tree.hvm.snap +++ b/tests/snapshots/run_file__list_to_tree.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/list_to_tree.hvm --- Lazy mode: - ((1, 2), (3, (4, 5))) Strict mode: - ((1, 2), (3, (4, 5))) diff --git a/tests/snapshots/run_file__log.hvm.snap b/tests/snapshots/run_file__log.hvm.snap index 0188ec6f..74910894 100644 --- a/tests/snapshots/run_file__log.hvm.snap +++ b/tests/snapshots/run_file__log.hvm.snap @@ -3,13 +3,11 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/log.hvm --- Lazy mode: - 59 (Some "Hello world") "Hi" Strict mode: - 59 (Some "Hello world") "Hi" diff --git a/tests/snapshots/run_file__match.hvm.snap b/tests/snapshots/run_file__match.hvm.snap index 8b808fdb..822e2834 100644 --- a/tests/snapshots/run_file__match.hvm.snap +++ b/tests/snapshots/run_file__match.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/match.hvm --- Lazy mode: - λ* λa a Strict mode: - λ* λa a diff --git a/tests/snapshots/run_file__match_builtins.hvm.snap b/tests/snapshots/run_file__match_builtins.hvm.snap index 2a738f04..5f933f7d 100644 --- a/tests/snapshots/run_file__match_builtins.hvm.snap +++ b/tests/snapshots/run_file__match_builtins.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/match_builtins.hvm --- Lazy mode: - ("ello", "world") Strict mode: - ("ello", "world") diff --git a/tests/snapshots/run_file__match_mult_linearization.hvm.snap b/tests/snapshots/run_file__match_mult_linearization.hvm.snap index 7bce6a30..34d59d8a 100644 --- a/tests/snapshots/run_file__match_mult_linearization.hvm.snap +++ b/tests/snapshots/run_file__match_mult_linearization.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/match_mult_linearization.hvm --- Lazy mode: - λa match a { 0: λb λc λd (+ (+ b c) d); 1+e: λf λg λh (+ (+ (+ e f) g) h) } Strict mode: - λa match a { 0: λb λc λd (+ (+ b c) d); 1+e: λf λg λh (+ (+ (+ e f) g) h) } diff --git a/tests/snapshots/run_file__match_num_adt_tup_parser.hvm.snap b/tests/snapshots/run_file__match_num_adt_tup_parser.hvm.snap index 58db6534..fdb2ca36 100644 --- a/tests/snapshots/run_file__match_num_adt_tup_parser.hvm.snap +++ b/tests/snapshots/run_file__match_num_adt_tup_parser.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/match_num_adt_tup_parser.hvm --- Lazy mode: - (40, (Err ("+", *))) Strict mode: - (40, (Err ("+", *))) diff --git a/tests/snapshots/run_file__match_num_explicit_bind.hvm.snap b/tests/snapshots/run_file__match_num_explicit_bind.hvm.snap index 5c738334..ef2c3d89 100644 --- a/tests/snapshots/run_file__match_num_explicit_bind.hvm.snap +++ b/tests/snapshots/run_file__match_num_explicit_bind.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/match_num_explicit_bind.hvm --- Lazy mode: - 3 Strict mode: - 3 diff --git a/tests/snapshots/run_file__match_num_num_to_char.hvm.snap b/tests/snapshots/run_file__match_num_num_to_char.hvm.snap index 50fc22a5..a861cd20 100644 --- a/tests/snapshots/run_file__match_num_num_to_char.hvm.snap +++ b/tests/snapshots/run_file__match_num_num_to_char.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/match_num_num_to_char.hvm --- Lazy mode: - (([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1152921504606846975]), [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 0]) Strict mode: - (([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1152921504606846975]), [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 0]) diff --git a/tests/snapshots/run_file__match_num_succ_complex.hvm.snap b/tests/snapshots/run_file__match_num_succ_complex.hvm.snap index 0466129c..0ff5b6fb 100644 --- a/tests/snapshots/run_file__match_num_succ_complex.hvm.snap +++ b/tests/snapshots/run_file__match_num_succ_complex.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/match_num_succ_complex.hvm --- Lazy mode: - [[5, 5, 0, 0, 0, 6], [5, 5, 0, 0, 0, 6], [5, 5, 0, 0, 0, 6]] Strict mode: - [[5, 5, 0, 0, 0, 6], [5, 5, 0, 0, 0, 6], [5, 5, 0, 0, 0, 6]] diff --git a/tests/snapshots/run_file__match_str.hvm.snap b/tests/snapshots/run_file__match_str.hvm.snap index 9178c385..ec536e85 100644 --- a/tests/snapshots/run_file__match_str.hvm.snap +++ b/tests/snapshots/run_file__match_str.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/match_str.hvm --- Lazy mode: - [2, 2, 1, 0, 0, 0] Strict mode: - [2, 2, 1, 0, 0, 0] diff --git a/tests/snapshots/run_file__match_sup.hvm.snap b/tests/snapshots/run_file__match_sup.hvm.snap index c4bab1be..81b42f4d 100644 --- a/tests/snapshots/run_file__match_sup.hvm.snap +++ b/tests/snapshots/run_file__match_sup.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/match_sup.hvm --- Lazy mode: - #a{1 2} Strict mode: - #a{1 2} diff --git a/tests/snapshots/run_file__match_vars.hvm.snap b/tests/snapshots/run_file__match_vars.hvm.snap index 9b8f4de9..42120c47 100644 --- a/tests/snapshots/run_file__match_vars.hvm.snap +++ b/tests/snapshots/run_file__match_vars.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/match_vars.hvm --- Lazy mode: - 1 Strict mode: - 1 diff --git a/tests/snapshots/run_file__merge_sort.hvm.snap b/tests/snapshots/run_file__merge_sort.hvm.snap index d3b1fdbd..51b5c918 100644 --- a/tests/snapshots/run_file__merge_sort.hvm.snap +++ b/tests/snapshots/run_file__merge_sort.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/merge_sort.hvm --- Lazy mode: - 120 Strict mode: - 120 diff --git a/tests/snapshots/run_file__names_hyphen.hvm.snap b/tests/snapshots/run_file__names_hyphen.hvm.snap index bae51f71..24f00f0e 100644 --- a/tests/snapshots/run_file__names_hyphen.hvm.snap +++ b/tests/snapshots/run_file__names_hyphen.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/names_hyphen.hvm --- Lazy mode: - 1 Strict mode: - 1 diff --git a/tests/snapshots/run_file__names_hyphen_toplevel.hvm.snap b/tests/snapshots/run_file__names_hyphen_toplevel.hvm.snap index 1e3fa596..5e5b6930 100644 --- a/tests/snapshots/run_file__names_hyphen_toplevel.hvm.snap +++ b/tests/snapshots/run_file__names_hyphen_toplevel.hvm.snap @@ -3,6 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/names_hyphen_toplevel.hvm --- Lazy mode: +Errors: At tests/golden_tests/run_file/names_hyphen_toplevel.hvm:1:1: Names with '-' are not supported at top level.  1 | this-is-not-allowed = 1 At tests/golden_tests/run_file/names_hyphen_toplevel.hvm:3:6: Names with '-' are not supported at top level. @@ -11,8 +12,8 @@ At tests/golden_tests/run_file/names_hyphen_toplevel.hvm:3:16: Names with '-' ar  3 | data Foo-Bar = Baz-Qux - Strict mode: +Errors: At tests/golden_tests/run_file/names_hyphen_toplevel.hvm:1:1: Names with '-' are not supported at top level.  1 | this-is-not-allowed = 1 At tests/golden_tests/run_file/names_hyphen_toplevel.hvm:3:6: Names with '-' are not supported at top level. diff --git a/tests/snapshots/run_file__nested_let_tup.hvm.snap b/tests/snapshots/run_file__nested_let_tup.hvm.snap index 1e5de35b..f1e085bc 100644 --- a/tests/snapshots/run_file__nested_let_tup.hvm.snap +++ b/tests/snapshots/run_file__nested_let_tup.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/nested_let_tup.hvm --- Lazy mode: - 2 Strict mode: - 2 diff --git a/tests/snapshots/run_file__nested_list_and_string.hvm.snap b/tests/snapshots/run_file__nested_list_and_string.hvm.snap index b5d14954..56c01b64 100644 --- a/tests/snapshots/run_file__nested_list_and_string.hvm.snap +++ b/tests/snapshots/run_file__nested_list_and_string.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/nested_list_and_string.hvm --- Lazy mode: - λa [a, (*, 2), (String.cons [7, "1234", 9] (String.cons a (String.cons * "42")))] Strict mode: - λa [a, (*, 2), (String.cons [7, "1234", 9] (String.cons a (String.cons * "42")))] diff --git a/tests/snapshots/run_file__nested_str.hvm.snap b/tests/snapshots/run_file__nested_str.hvm.snap index 2dba54e8..5b694ffd 100644 --- a/tests/snapshots/run_file__nested_str.hvm.snap +++ b/tests/snapshots/run_file__nested_str.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/nested_str.hvm --- Lazy mode: - ((String.cons "a" String.nil), ((String.cons 97 (String.cons "bc" String.nil)), ((String.cons "ab" "c"), (String.cons "ab" (String.cons "cd" String.nil))))) Strict mode: - ((String.cons "a" String.nil), ((String.cons 97 (String.cons "bc" String.nil)), ((String.cons "ab" "c"), (String.cons "ab" (String.cons "cd" String.nil))))) diff --git a/tests/snapshots/run_file__num_match_missing_var.hvm.snap b/tests/snapshots/run_file__num_match_missing_var.hvm.snap index 0b121f2f..eb5a4fbe 100644 --- a/tests/snapshots/run_file__num_match_missing_var.hvm.snap +++ b/tests/snapshots/run_file__num_match_missing_var.hvm.snap @@ -3,7 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/num_match_missing_var.hvm --- Lazy mode: - +Errors: In definition 'if': Non-exhaustive pattern matching. Hint: Case '+' not covered. @@ -11,9 +11,8 @@ In definition 'if4': Expected a sequence of incrementing numbers ending with '1+', found '1'. - Strict mode: - +Errors: In definition 'if': Non-exhaustive pattern matching. Hint: Case '+' not covered. diff --git a/tests/snapshots/run_file__num_pred.hvm.snap b/tests/snapshots/run_file__num_pred.hvm.snap index 97fb181a..7a457ec8 100644 --- a/tests/snapshots/run_file__num_pred.hvm.snap +++ b/tests/snapshots/run_file__num_pred.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/num_pred.hvm --- Lazy mode: - 42 Strict mode: - 42 diff --git a/tests/snapshots/run_file__override_list_ctr.hvm.snap b/tests/snapshots/run_file__override_list_ctr.hvm.snap index 041fb08f..a61617b7 100644 --- a/tests/snapshots/run_file__override_list_ctr.hvm.snap +++ b/tests/snapshots/run_file__override_list_ctr.hvm.snap @@ -3,11 +3,12 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/override_list_ctr.hvm --- Lazy mode: +Errors: At tests/golden_tests/run_file/override_list_ctr.hvm:2:5: List.nil is a built-in constructor and should not be overridden.  2 | = List.nil - Strict mode: +Errors: At tests/golden_tests/run_file/override_list_ctr.hvm:2:5: List.nil is a built-in constructor and should not be overridden.  2 | = List.nil diff --git a/tests/snapshots/run_file__override_str_ctr.hvm.snap b/tests/snapshots/run_file__override_str_ctr.hvm.snap index bf2b3b94..57b8a6bf 100644 --- a/tests/snapshots/run_file__override_str_ctr.hvm.snap +++ b/tests/snapshots/run_file__override_str_ctr.hvm.snap @@ -3,11 +3,12 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/override_str_ctr.hvm --- Lazy mode: +Errors: At tests/golden_tests/run_file/override_str_ctr.hvm:2:5: String.cons is a built-in constructor and should not be overridden.  2 | = (String.cons any) - Strict mode: +Errors: At tests/golden_tests/run_file/override_str_ctr.hvm:2:5: String.cons is a built-in constructor and should not be overridden.  2 | = (String.cons any) diff --git a/tests/snapshots/run_file__pred.hvm.snap b/tests/snapshots/run_file__pred.hvm.snap index 31a8d81b..e76ff1b7 100644 --- a/tests/snapshots/run_file__pred.hvm.snap +++ b/tests/snapshots/run_file__pred.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/pred.hvm --- Lazy mode: - 2 Strict mode: - 2 diff --git a/tests/snapshots/run_file__print.hvm.snap b/tests/snapshots/run_file__print.hvm.snap index d62cde7c..6acfc3d2 100644 --- a/tests/snapshots/run_file__print.hvm.snap +++ b/tests/snapshots/run_file__print.hvm.snap @@ -3,11 +3,9 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/print.hvm --- Lazy mode: - hello world "goodbye world" Strict mode: - hello world "goodbye world" diff --git a/tests/snapshots/run_file__queue.hvm.snap b/tests/snapshots/run_file__queue.hvm.snap index ad1211c2..102f92c0 100644 --- a/tests/snapshots/run_file__queue.hvm.snap +++ b/tests/snapshots/run_file__queue.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/queue.hvm --- Lazy mode: - λa λ* (a 1 λb λ* (b 2 λc λ* (c 3 λ* λd d))) Strict mode: - λa λ* (a 1 λb λ* (b 2 λc λ* (c 3 λ* λd d))) diff --git a/tests/snapshots/run_file__radix_sort_ctr.hvm.snap b/tests/snapshots/run_file__radix_sort_ctr.hvm.snap index 1e11871d..8faab279 100644 --- a/tests/snapshots/run_file__radix_sort_ctr.hvm.snap +++ b/tests/snapshots/run_file__radix_sort_ctr.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/radix_sort_ctr.hvm --- Lazy mode: - 120 Strict mode: - 120 diff --git a/tests/snapshots/run_file__readback_hvm1_main.hvm.snap b/tests/snapshots/run_file__readback_hvm1_main.hvm.snap index 47c5990f..7893db11 100644 --- a/tests/snapshots/run_file__readback_hvm1_main.hvm.snap +++ b/tests/snapshots/run_file__readback_hvm1_main.hvm.snap @@ -3,13 +3,12 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/readback_hvm1_main.hvm --- Lazy mode: - +Errors: In definition 'Main': Main definition can't be referenced inside the program. - Strict mode: - +Errors: In definition 'Main': Main definition can't be referenced inside the program. diff --git a/tests/snapshots/run_file__readback_list_other_ctr.hvm.snap b/tests/snapshots/run_file__readback_list_other_ctr.hvm.snap index 876cae26..1bc6622f 100644 --- a/tests/snapshots/run_file__readback_list_other_ctr.hvm.snap +++ b/tests/snapshots/run_file__readback_list_other_ctr.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/readback_list_other_ctr.hvm --- Lazy mode: - (List.cons (String.cons 97 (pair 98 "c")) (List.cons 1 (pair 2 [3, 4]))) Strict mode: - (List.cons (String.cons 97 (pair 98 "c")) (List.cons 1 (pair 2 [3, 4]))) diff --git a/tests/snapshots/run_file__recursive_combinator.hvm.snap b/tests/snapshots/run_file__recursive_combinator.hvm.snap index 63cdee86..c4e09a18 100644 --- a/tests/snapshots/run_file__recursive_combinator.hvm.snap +++ b/tests/snapshots/run_file__recursive_combinator.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/recursive_combinator.hvm --- Lazy mode: - 0 Strict mode: - 0 diff --git a/tests/snapshots/run_file__recursive_combinator_nested.hvm.snap b/tests/snapshots/run_file__recursive_combinator_nested.hvm.snap index 5c9172ab..2107a213 100644 --- a/tests/snapshots/run_file__recursive_combinator_nested.hvm.snap +++ b/tests/snapshots/run_file__recursive_combinator_nested.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/recursive_combinator_nested.hvm --- Lazy mode: - #a{8 0} Strict mode: - #a{8 0} diff --git a/tests/snapshots/run_file__recursive_match_native.hvm.snap b/tests/snapshots/run_file__recursive_match_native.hvm.snap index 1e9c437f..895f8c88 100644 --- a/tests/snapshots/run_file__recursive_match_native.hvm.snap +++ b/tests/snapshots/run_file__recursive_match_native.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/recursive_match_native.hvm --- Lazy mode: - 512 Strict mode: - 512 diff --git a/tests/snapshots/run_file__ref_resolution.hvm.snap b/tests/snapshots/run_file__ref_resolution.hvm.snap index b5f19d5e..24f8f030 100644 --- a/tests/snapshots/run_file__ref_resolution.hvm.snap +++ b/tests/snapshots/run_file__ref_resolution.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/ref_resolution.hvm --- Lazy mode: - 42 Strict mode: - 42 diff --git a/tests/snapshots/run_file__repeated_name_truncation.hvm.snap b/tests/snapshots/run_file__repeated_name_truncation.hvm.snap index 9db6a304..98824445 100644 --- a/tests/snapshots/run_file__repeated_name_truncation.hvm.snap +++ b/tests/snapshots/run_file__repeated_name_truncation.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/repeated_name_truncation.hvm --- Lazy mode: - λ* 2 Strict mode: - λ* 2 diff --git a/tests/snapshots/run_file__scopeless_discard.hvm.snap b/tests/snapshots/run_file__scopeless_discard.hvm.snap index 17b8bb58..ceaa7e66 100644 --- a/tests/snapshots/run_file__scopeless_discard.hvm.snap +++ b/tests/snapshots/run_file__scopeless_discard.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/scopeless_discard.hvm --- Lazy mode: - (2, *) Strict mode: - (2, *) diff --git a/tests/snapshots/run_file__str_backtick.hvm.snap b/tests/snapshots/run_file__str_backtick.hvm.snap index edd821a9..94dc3aa2 100644 --- a/tests/snapshots/run_file__str_backtick.hvm.snap +++ b/tests/snapshots/run_file__str_backtick.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/str_backtick.hvm --- Lazy mode: - "abc369*`asdf\"asdf" Strict mode: - "abc369*`asdf\"asdf" diff --git a/tests/snapshots/run_file__str_concat.hvm.snap b/tests/snapshots/run_file__str_concat.hvm.snap index 4c156699..7f33a753 100644 --- a/tests/snapshots/run_file__str_concat.hvm.snap +++ b/tests/snapshots/run_file__str_concat.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/str_concat.hvm --- Lazy mode: - "hello world" Strict mode: - "hello world" diff --git a/tests/snapshots/run_file__str_inc.hvm.snap b/tests/snapshots/run_file__str_inc.hvm.snap index b27c5627..daaf9298 100644 --- a/tests/snapshots/run_file__str_inc.hvm.snap +++ b/tests/snapshots/run_file__str_inc.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/str_inc.hvm --- Lazy mode: - (11, #str λa (105, (102, (109, (109, (112, (33, (120, (112, (115, (109, (101, a)))))))))))) Strict mode: - (11, #str λa (105, (102, (109, (109, (112, (33, (120, (112, (115, (109, (101, a)))))))))))) diff --git a/tests/snapshots/run_file__str_inc_eta.hvm.snap b/tests/snapshots/run_file__str_inc_eta.hvm.snap index dbb75847..9c34e175 100644 --- a/tests/snapshots/run_file__str_inc_eta.hvm.snap +++ b/tests/snapshots/run_file__str_inc_eta.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/str_inc_eta.hvm --- Lazy mode: - (11, #str λa (105, (102, (109, (109, (112, (33, (120, (112, (115, (109, (101, a)))))))))))) Strict mode: - (11, #str λa (105, (102, (109, (109, (112, (33, (120, (112, (115, (109, (101, a)))))))))))) diff --git a/tests/snapshots/run_file__str_len.hvm.snap b/tests/snapshots/run_file__str_len.hvm.snap index 88717d8c..b764b561 100644 --- a/tests/snapshots/run_file__str_len.hvm.snap +++ b/tests/snapshots/run_file__str_len.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/str_len.hvm --- Lazy mode: - 4 Strict mode: - 4 diff --git a/tests/snapshots/run_file__sum_tree.hvm.snap b/tests/snapshots/run_file__sum_tree.hvm.snap index cdec2e62..81649f8d 100644 --- a/tests/snapshots/run_file__sum_tree.hvm.snap +++ b/tests/snapshots/run_file__sum_tree.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/sum_tree.hvm --- Lazy mode: - 256 Strict mode: - 256 diff --git a/tests/snapshots/run_file__sup_app.hvm.snap b/tests/snapshots/run_file__sup_app.hvm.snap index 034fd894..ee19851e 100644 --- a/tests/snapshots/run_file__sup_app.hvm.snap +++ b/tests/snapshots/run_file__sup_app.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/sup_app.hvm --- Lazy mode: - #id{3 3} Strict mode: - #id{3 3} diff --git a/tests/snapshots/run_file__sup_reconstruction.hvm.snap b/tests/snapshots/run_file__sup_reconstruction.hvm.snap index 9fa7676b..6a7dc441 100644 --- a/tests/snapshots/run_file__sup_reconstruction.hvm.snap +++ b/tests/snapshots/run_file__sup_reconstruction.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/sup_reconstruction.hvm --- Lazy mode: - λa a Strict mode: - λa a diff --git a/tests/snapshots/run_file__superposed_is_even.hvm.snap b/tests/snapshots/run_file__superposed_is_even.hvm.snap index 4a1842f1..1fd5ea5d 100644 --- a/tests/snapshots/run_file__superposed_is_even.hvm.snap +++ b/tests/snapshots/run_file__superposed_is_even.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/superposed_is_even.hvm --- Lazy mode: - #0{#1{T F} #2{T F}} Strict mode: - #0{#1{T F} #2{T F}} diff --git a/tests/snapshots/run_file__tagged_lam.hvm.snap b/tests/snapshots/run_file__tagged_lam.hvm.snap index e56cce42..2919b8fe 100644 --- a/tests/snapshots/run_file__tagged_lam.hvm.snap +++ b/tests/snapshots/run_file__tagged_lam.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/tagged_lam.hvm --- Lazy mode: - (3, 4) Strict mode: - (3, 4) diff --git a/tests/snapshots/run_file__tup_list_strings.hvm.snap b/tests/snapshots/run_file__tup_list_strings.hvm.snap index 7485b054..bb96a777 100644 --- a/tests/snapshots/run_file__tup_list_strings.hvm.snap +++ b/tests/snapshots/run_file__tup_list_strings.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/tup_list_strings.hvm --- Lazy mode: - ([("foo", 0), ("foo", 0), ("foo", 1)], 4) Strict mode: - ([("foo", 0), ("foo", 0), ("foo", 1)], 4) diff --git a/tests/snapshots/run_file__tup_reconstruction.hvm.snap b/tests/snapshots/run_file__tup_reconstruction.hvm.snap index 246254b7..72174a78 100644 --- a/tests/snapshots/run_file__tup_reconstruction.hvm.snap +++ b/tests/snapshots/run_file__tup_reconstruction.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/tup_reconstruction.hvm --- Lazy mode: - λa a Strict mode: - λa a diff --git a/tests/snapshots/run_file__tuple_rots.hvm.snap b/tests/snapshots/run_file__tuple_rots.hvm.snap index 1c816117..20dc7397 100644 --- a/tests/snapshots/run_file__tuple_rots.hvm.snap +++ b/tests/snapshots/run_file__tuple_rots.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/tuple_rots.hvm --- Lazy mode: - λa (a 5 6 7 8 1 2 3 4) Strict mode: - λa (a 5 6 7 8 1 2 3 4) diff --git a/tests/snapshots/run_file__unaplied_str.hvm.snap b/tests/snapshots/run_file__unaplied_str.hvm.snap index 6c0ead5b..c78b27ca 100644 --- a/tests/snapshots/run_file__unaplied_str.hvm.snap +++ b/tests/snapshots/run_file__unaplied_str.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/unaplied_str.hvm --- Lazy mode: - λa λb (String.cons a (String.cons 98 (String.cons 99 (String.cons b String.nil)))) Strict mode: - λa λb (String.cons a (String.cons 98 (String.cons 99 (String.cons b String.nil)))) diff --git a/tests/snapshots/run_file__unscoped_never_used.hvm.snap b/tests/snapshots/run_file__unscoped_never_used.hvm.snap index a828dd78..0f58c841 100644 --- a/tests/snapshots/run_file__unscoped_never_used.hvm.snap +++ b/tests/snapshots/run_file__unscoped_never_used.hvm.snap @@ -3,13 +3,12 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/unscoped_never_used.hvm --- Lazy mode: - +Errors: In definition 'main': Unscoped variable from lambda 'λ$x' is never used. - Strict mode: - +Errors: In definition 'main': Unscoped variable from lambda 'λ$x' is never used. diff --git a/tests/snapshots/run_file__unused_dup_var.hvm.snap b/tests/snapshots/run_file__unused_dup_var.hvm.snap index d0c559ca..fc034ce4 100644 --- a/tests/snapshots/run_file__unused_dup_var.hvm.snap +++ b/tests/snapshots/run_file__unused_dup_var.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/unused_dup_var.hvm --- Lazy mode: - λa (a λb b) Strict mode: - λa (a λb b) diff --git a/tests/snapshots/run_file__world.hvm.snap b/tests/snapshots/run_file__world.hvm.snap index 1110d01c..63807492 100644 --- a/tests/snapshots/run_file__world.hvm.snap +++ b/tests/snapshots/run_file__world.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/world.hvm --- Lazy mode: - "🌎" Strict mode: - "🌎" diff --git a/tests/snapshots/run_file__wrong_string.hvm.snap b/tests/snapshots/run_file__wrong_string.hvm.snap index 16c74b8f..970ef17c 100644 --- a/tests/snapshots/run_file__wrong_string.hvm.snap +++ b/tests/snapshots/run_file__wrong_string.hvm.snap @@ -3,9 +3,7 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/wrong_string.hvm --- Lazy mode: - (String.cons (*, 4) (String.cons * String.nil)) Strict mode: - (String.cons (*, 4) (String.cons * String.nil)) diff --git a/tests/snapshots/run_lazy__adt_match_wrong_tag.hvm.snap b/tests/snapshots/run_lazy__adt_match_wrong_tag.hvm.snap index 38969609..22701d72 100644 --- a/tests/snapshots/run_lazy__adt_match_wrong_tag.hvm.snap +++ b/tests/snapshots/run_lazy__adt_match_wrong_tag.hvm.snap @@ -2,7 +2,9 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_lazy/adt_match_wrong_tag.hvm --- -Readback Warning: -Unexpected tag found during Adt readback, expected '#Option', but found '#wrong_tag' -Invalid Adt Match +Warnings: +During readback: + Unexpected tag found during Adt readback, expected '#Option', but found '#wrong_tag'. + Invalid Adt Match. + λa match a { (Some Some.val): #Option (#wrong_tag λb b Some.val); (None): * } diff --git a/tests/snapshots/run_lazy__adt_wrong_tag.hvm.snap b/tests/snapshots/run_lazy__adt_wrong_tag.hvm.snap index 000c09de..c790c89e 100644 --- a/tests/snapshots/run_lazy__adt_wrong_tag.hvm.snap +++ b/tests/snapshots/run_lazy__adt_wrong_tag.hvm.snap @@ -2,7 +2,9 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_lazy/adt_wrong_tag.hvm --- -Readback Warning: -Unexpected tag found during Adt readback, expected '#Option', but found '#wrong_tag' -Invalid Adt Match +Warnings: +During readback: + Unexpected tag found during Adt readback, expected '#Option', but found '#wrong_tag'. + Invalid Adt Match. + λa match a { (Some Some.val): #Option (#wrong_tag λb b Some.val); (None): * }