From 12efbaabab9f6371a920147be7f5513679003d56 Mon Sep 17 00:00:00 2001 From: Manuel Raimann Date: Thu, 12 Feb 2026 16:00:05 +0100 Subject: [PATCH] fix(sampler): return None instead of panicking on parameter type mismatch in CompletedTrial::get() --- src/sampler/mod.rs | 18 ++++++------------ tests/study/workflow.rs | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/sampler/mod.rs b/src/sampler/mod.rs index a660d11..ff83bc6 100644 --- a/src/sampler/mod.rs +++ b/src/sampler/mod.rs @@ -121,13 +121,9 @@ impl CompletedTrial { /// Looks up the parameter by its unique id and casts the stored /// [`ParamValue`] to the parameter's typed value. /// - /// Returns `None` if the parameter was not used in this trial. - /// - /// # Panics - /// - /// Panics if the stored value is incompatible with the parameter type - /// (e.g., a `Float` value stored for an `IntParam`). This indicates - /// a bug in the program, not a runtime error. + /// Returns `None` if the parameter was not used in this trial or if + /// the stored value is incompatible with the parameter type (e.g., a + /// `Float` value stored for an `IntParam`). /// /// # Examples /// @@ -150,11 +146,9 @@ impl CompletedTrial { /// assert!((-10.0..=10.0).contains(&x_val)); /// ``` pub fn get(&self, param: &P) -> Option { - self.params.get(¶m.id()).map(|v| { - param - .cast_param_value(v) - .expect("parameter type mismatch: stored value incompatible with parameter") - }) + self.params + .get(¶m.id()) + .and_then(|v| param.cast_param_value(v).ok()) } /// Returns `true` if all constraints are satisfied (values <= 0.0). diff --git a/tests/study/workflow.rs b/tests/study/workflow.rs index a14bf11..98f1154 100644 --- a/tests/study/workflow.rs +++ b/tests/study/workflow.rs @@ -258,6 +258,28 @@ fn test_completed_trial_get() { assert!((1..=10).contains(&n_val)); } +#[test] +fn test_completed_trial_get_type_mismatch_returns_none() { + let study: Study = Study::new(Direction::Minimize); + let int_param = IntParam::new(1, 10).name("x"); + + study + .optimize(1, |trial: &mut optimizer::Trial| { + let n = int_param.suggest(trial)?; + Ok::<_, Error>(n as f64) + }) + .unwrap(); + + let best = study.best_trial().unwrap(); + + // The stored value is ParamValue::Int, but we query with a FloatParam. + let wrong_type = FloatParam::new(0.0, 100.0).name("x"); + assert!( + best.get(&wrong_type).is_none(), + "type mismatch should return None, not panic" + ); +} + #[test] fn test_single_value_int_range() { let param = IntParam::new(5, 5);