From f706742e9507821507b6706cef7439f08859baff Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sun, 19 Apr 2020 10:18:24 +0100 Subject: [PATCH] Add integration test for unwind safety --- tests/integration/mod.rs | 1 + tests/integration/panic.rs | 160 +++++++++++++++++++++++++++++++++++++ tests/lib.rs | 2 + tests/test_util.rs | 28 ++++++- 4 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 tests/integration/mod.rs create mode 100644 tests/integration/panic.rs diff --git a/tests/integration/mod.rs b/tests/integration/mod.rs new file mode 100644 index 00000000000..2dabf71e941 --- /dev/null +++ b/tests/integration/mod.rs @@ -0,0 +1 @@ +mod panic; diff --git a/tests/integration/panic.rs b/tests/integration/panic.rs new file mode 100644 index 00000000000..087b507971f --- /dev/null +++ b/tests/integration/panic.rs @@ -0,0 +1,160 @@ +use chalk_integration::db::ChalkDatabase; +use chalk_integration::query::LoweringDatabase; +use chalk_ir::interner::ChalkIr; +use chalk_ir::AssocTypeId; +use chalk_ir::Goal; +use chalk_ir::ImplId; +use chalk_ir::InEnvironment; +use chalk_ir::OpaqueTyId; +use chalk_ir::Parameter; +use chalk_ir::ProgramClause; +use chalk_ir::StructId; +use chalk_ir::TraitId; +use chalk_ir::TypeName; +use chalk_ir::UCanonical; +use chalk_rust_ir::AssociatedTyDatum; +use chalk_rust_ir::AssociatedTyValue; +use chalk_rust_ir::AssociatedTyValueId; +use chalk_rust_ir::ImplDatum; +use chalk_rust_ir::OpaqueTyDatum; +use chalk_rust_ir::StructDatum; +use chalk_rust_ir::TraitDatum; +use chalk_rust_ir::WellKnownTrait; +use chalk_solve::RustIrDatabase; +use chalk_solve::Solution; +use chalk_solve::SolverChoice; +use std::sync::Arc; + +#[derive(Debug, Default)] +struct MockDatabase { + chalk_db: ChalkDatabase, + panic: bool, +} + +impl MockDatabase { + pub fn with(program_text: &str, solver_choice: SolverChoice) -> Self { + Self { + chalk_db: ChalkDatabase::with(program_text, solver_choice), + panic: false, + } + } + + pub fn solve( + &self, + goal: &UCanonical>>, + ) -> Option> { + let solver = self.chalk_db.solver(); + let solution = solver.lock().unwrap().solve(self, goal); + solution + } +} + +impl RustIrDatabase for MockDatabase { + fn custom_clauses(&self) -> Vec> { + if self.panic { + unimplemented!() + } else { + self.chalk_db.custom_clauses() + } + } + + fn associated_ty_data(&self, ty: AssocTypeId) -> Arc> { + self.chalk_db.associated_ty_data(ty) + } + + fn trait_datum(&self, id: TraitId) -> Arc> { + self.chalk_db.trait_datum(id) + } + + fn impl_datum(&self, id: ImplId) -> Arc> { + self.chalk_db.impl_datum(id) + } + + fn associated_ty_value( + &self, + id: AssociatedTyValueId, + ) -> Arc> { + self.chalk_db.associated_ty_value(id) + } + + fn opaque_ty_data(&self, id: OpaqueTyId) -> Arc> { + self.chalk_db.opaque_ty_data(id) + } + + fn struct_datum(&self, id: StructId) -> Arc> { + self.chalk_db.struct_datum(id) + } + + fn as_struct_id(&self, type_name: &TypeName) -> Option> { + self.chalk_db.as_struct_id(type_name) + } + + fn impls_for_trait( + &self, + trait_id: TraitId, + parameters: &[Parameter], + ) -> Vec> { + self.chalk_db.impls_for_trait(trait_id, parameters) + } + + fn local_impls_to_coherence_check(&self, trait_id: TraitId) -> Vec> { + self.chalk_db.local_impls_to_coherence_check(trait_id) + } + + fn impl_provided_for( + &self, + auto_trait_id: TraitId, + struct_id: StructId, + ) -> bool { + self.chalk_db.impl_provided_for(auto_trait_id, struct_id) + } + + fn well_known_trait_id(&self, well_known_trait: WellKnownTrait) -> Option> { + self.chalk_db.well_known_trait_id(well_known_trait) + } + + fn interner(&self) -> &ChalkIr { + &ChalkIr + } +} + +#[test] +fn unwind_safety() { + use self::MockDatabase; + use chalk_integration::lowering::LowerGoal; + use chalk_integration::query::LoweringDatabase; + use chalk_solve::ext::GoalExt; + use std::panic; + + // lower program + let mut db = lower_program_with_db! { + program { + struct Foo { } + trait Bar { } + impl Bar for Foo { } + } + database MockDatabase + }; + + let program = db.chalk_db.checked_program().unwrap(); + + // lower goal + let goal = lower_goal! { + goal { + Foo: Bar + } + program &*program + }; + let peeled_goal = goal.into_peeled_goal(db.interner()); + + // solve goal but this will panic + db.panic = true; + let result = panic::catch_unwind(|| { + db.solve(&peeled_goal); + }); + assert!(result.is_err() == true); + + // solve again but without panicking this time + db.panic = false; + assert!(db.solve(&peeled_goal).is_some()); +} diff --git a/tests/lib.rs b/tests/lib.rs index ad3223630e4..e28bac2f0e3 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -4,3 +4,5 @@ mod test_util; mod test; mod lowering; + +mod integration; diff --git a/tests/test_util.rs b/tests/test_util.rs index 9419b0e7452..05b79c0f01e 100644 --- a/tests/test_util.rs +++ b/tests/test_util.rs @@ -1,15 +1,35 @@ #![allow(unused_macros)] -macro_rules! lowering_success { - (program $program:tt) => { +macro_rules! lower_program_with_db { + (program $program:tt database $database:ty) => {{ let program_text = stringify!($program); assert!(program_text.starts_with("{")); assert!(program_text.ends_with("}")); - let result = chalk_integration::db::ChalkDatabase::with( + <$database>::with( &program_text[1..program_text.len() - 1], chalk_solve::SolverChoice::default(), ) - .checked_program(); + }}; +} + +macro_rules! lower_goal { + (goal $goal:tt program $program:expr) => {{ + let goal_text = stringify!($goal); + assert!(goal_text.starts_with("{")); + assert!(goal_text.ends_with("}")); + chalk_parse::parse_goal(&goal_text[1..goal_text.len() - 1]) + .unwrap() + .lower($program) + .unwrap() + }}; +} + +macro_rules! lowering_success { + (program $program:tt) => { + let result = lower_program_with_db!( + program $program + database chalk_integration::db::ChalkDatabase + ).checked_program(); if let Err(ref e) = result { println!("lowering error: {}", e); }