From 2f71946d21f0c9a2ef212be9a0483665fa5f46bb Mon Sep 17 00:00:00 2001 From: John Doty Date: Sun, 7 Jan 2024 08:53:32 -0800 Subject: [PATCH] [fine] Environment cycles are internal compiler errors Re-work the failure to add official ICE support, and extract the reporting from the tests into the semantics, so everybody benefits. --- fine/src/semantics.rs | 74 +++++++++++++++++++++++++++++++++---- fine/tests/example_tests.rs | 53 ++++---------------------- 2 files changed, 74 insertions(+), 53 deletions(-) diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index 8b2f2cdf..5df686ec 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -344,18 +344,16 @@ impl<'a> Semantics<'a> { pub fn environment_of(&self, t: TreeRef) -> EnvironmentRef { { - let state = &mut self.environments.borrow_mut()[t.index()]; + // I want to make sure that this borrow is dropped after this block. + let mut borrow = self.environments.borrow_mut(); + let state = &mut borrow[t.index()]; match state { Incremental::None => (), Incremental::Complete(e) => return e.clone(), Incremental::InProgress => { // eprintln!("environment_of circular => {t:?}"); - self.report_error_tree_ref( - t, - "INTERNAL COMPILER ERROR: Circular dependency detected: environment", - ); - *state = Incremental::Complete(self.empty_environment.clone()); - return self.empty_environment.clone(); + drop(borrow); + self.internal_compiler_error(Some(t), "circular environment dependency"); } } *state = Incremental::InProgress; @@ -759,4 +757,66 @@ impl<'a> Semantics<'a> { self.report_error_tree(tree, format!("cannot find value {id} here")); Some(Type::Error) } + + pub fn dump_compiler_state(&self, tr: Option) { + eprintln!("Parsed the tree as:"); + eprintln!("\n{}", self.syntax_tree.dump(true)); + + { + let errors = self.errors.borrow(); + if errors.len() == 0 { + eprintln!("There were no errors reported during checking.\n"); + } else { + eprintln!( + "{} error{} reported during checking:", + errors.len(), + if errors.len() == 1 { "" } else { "s" } + ); + for error in errors.iter() { + eprintln!(" Error: {error}"); + } + eprintln!(); + } + } + + if let Some(tr) = tr { + eprintln!("This is about the tree: {:?}", &self.syntax_tree[tr]); + eprintln!("The logical parent chain of the tree was:\n"); + let mut current = Some(tr); + while let Some(c) = current { + let t = &self.syntax_tree[c]; + eprintln!(" {:?} [{}-{})", t.kind, t.start_pos, t.end_pos); + current = self.logical_parents[c.index()]; + } + eprintln!("\nThe environment of the tree was:"); + let mut environment = Some(self.environment_of(tr)); + while let Some(env) = environment { + for (k, v) in env.declarations.iter() { + eprintln!(" {k}: {:?}", v.declaration_type); + } + environment = env.parent.clone(); + } + eprintln!(); + } + } + + fn internal_compiler_error(&self, tr: Option, message: &str) -> ! { + eprintln!("Internan compiler error: {message}!"); + self.dump_compiler_state(tr); + panic!("INTERNAL COMPILER ERROR: {message}") + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::parser::parse; + + #[test] + #[should_panic(expected = "INTERNAL COMPILER ERROR: oh no")] + pub fn ice() { + let (tree, lines) = parse("1 + 1"); + let semantics = Semantics::new(&tree, &lines); + semantics.internal_compiler_error(tree.root(), "oh no"); + } } diff --git a/fine/tests/example_tests.rs b/fine/tests/example_tests.rs index d41900e8..21aa523d 100644 --- a/fine/tests/example_tests.rs +++ b/fine/tests/example_tests.rs @@ -1,4 +1,4 @@ -use fine::parser::{SyntaxTree, TreeRef}; +use fine::parser::SyntaxTree; use fine::semantics::{Semantics, Type}; use fine::tokens::Lines; use pretty_assertions::assert_eq; @@ -85,52 +85,11 @@ fn assert_concrete(tree: &SyntaxTree, expected: &str, source_path: &str) { } } -fn report_semantic_error(semantics: &Semantics, tr: Option, message: &str) { - let tree = semantics.tree(); - - println!("{message}! Parsed the tree as:"); - println!("\n{}", tree.dump(true)); - - let errors = semantics.snapshot_errors(); - if errors.len() == 0 { - println!("There were no errors reported during checking.\n"); - } else { - println!( - "{} error{} reported during checking:", - errors.len(), - if errors.len() == 1 { "" } else { "s" } - ); - for error in &errors { - println!(" Error: {error}"); - } - println!(); - } - - if let Some(tr) = tr { - println!("About the tree: {:?}", &tree[tr]); - println!("The logical parent chain of the tree was:\n"); - let mut current = Some(tr); - while let Some(c) = current { - let t = &tree[c]; - println!(" {:?} [{}-{})", t.kind, t.start_pos, t.end_pos); - current = semantics.logical_parent(c); - } - println!("\nThe environment of the tree was:"); - let mut environment = Some(semantics.environment_of(tr)); - while let Some(env) = environment { - for (k, v) in env.declarations.iter() { - println!(" {k}: {:?}", v.declaration_type); - } - environment = env.parent.clone(); - } - println!(); - } -} - macro_rules! semantic_panic { ($semantics:expr, $tr:expr, $($t:tt)*) => {{ let message = format!($($t)*); - report_semantic_error($semantics, $tr, &message); + eprintln!("{message}!"); + $semantics.dump_compiler_state($tr); panic!("{message}"); }}; } @@ -139,7 +98,8 @@ macro_rules! semantic_assert { ($semantics:expr, $tr:expr, $pred:expr, $($t:tt)*) => {{ if !$pred { let message = format!($($t)*); - report_semantic_error($semantics, $tr, &message); + eprintln!("{message}!"); + $semantics.dump_compiler_state($tr); panic!("{message}"); } }}; @@ -151,7 +111,8 @@ macro_rules! semantic_assert_eq { let rr = $right; if ll != rr { let message = format!($($t)*); - report_semantic_error($semantics, $tr, &message); + eprintln!("{message}!"); + $semantics.dump_compiler_state($tr); assert_eq!(ll, rr, "{}", message); } }};