diff --git a/compiler/qsc/src/interpret/tests.rs b/compiler/qsc/src/interpret/tests.rs index 06e2f294a1..3e55266801 100644 --- a/compiler/qsc/src/interpret/tests.rs +++ b/compiler/qsc/src/interpret/tests.rs @@ -1522,6 +1522,27 @@ mod given_interpreter { is_unit_with_output_eval_entry(&result, &output, "hello there..."); } + #[test] + fn invalid_partial_application_should_fail_not_panic() { + // Found via fuzzing, see #2363 + let source = "operation e(oracle:(w=>)){oracle=i(_)"; + let sources = SourceMap::new([("test".into(), source.into())], None); + let (std_id, store) = + crate::compile::package_store_with_stdlib(TargetCapabilityFlags::all()); + assert!( + Interpreter::new( + sources, + PackageType::Exe, + TargetCapabilityFlags::all(), + LanguageFeatures::default(), + store, + &[(std_id, None)], + ) + .is_err(), + "interpreter should fail with error" + ); + } + #[test] fn errors_returned_if_sources_do_not_match_profile() { let source = indoc! { r#" diff --git a/compiler/qsc_hir/src/ty.rs b/compiler/qsc_hir/src/ty.rs index 47ec6f7d9b..873210a7f1 100644 --- a/compiler/qsc_hir/src/ty.rs +++ b/compiler/qsc_hir/src/ty.rs @@ -537,12 +537,12 @@ impl FunctorSet { /// /// # Panics /// - /// Panics if this set is not a value. + /// Panics if this set does not have a value. #[must_use] pub fn expect_value(self, msg: &str) -> FunctorSetValue { match self { - Self::Value(value) => value, - Self::Param(_, _) | Self::Infer(_) => panic!("{msg}"), + Self::Value(value) | Self::Param(_, value) => value, + Self::Infer(_) => panic!("{msg}"), } } } diff --git a/compiler/qsc_passes/src/spec_gen/adj_gen.rs b/compiler/qsc_passes/src/spec_gen/adj_gen.rs index ac459cefc7..74c694ca7a 100644 --- a/compiler/qsc_passes/src/spec_gen/adj_gen.rs +++ b/compiler/qsc_passes/src/spec_gen/adj_gen.rs @@ -7,7 +7,7 @@ use qsc_data_structures::span::Span; use qsc_hir::{ hir::{CallableKind, Expr, ExprKind, Functor, NodeId, UnOp}, mut_visit::{walk_expr, MutVisitor}, - ty::{FunctorSet, Ty}, + ty::Ty, }; use thiserror::Error; @@ -33,12 +33,10 @@ impl MutVisitor for AdjDistrib { ExprKind::Call(op, _) => { match &op.ty { Ty::Arrow(arrow) if arrow.kind == CallableKind::Operation => { - let functors = match *arrow.functors.borrow() { - FunctorSet::Value(functors) | FunctorSet::Param(_, functors) => { - functors - } - FunctorSet::Infer(_) => panic!("arrow type should have known functors"), - }; + let functors = arrow + .functors + .borrow() + .expect_value("arrow type should have known functors"); if functors.contains(&Functor::Adj) { *op = Box::new(Expr {