From 6ef5add5dc07237e3db83d19770bba3c2bf6d386 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 20 Aug 2026 06:33:11 +0000 Subject: [PATCH] Close non-last parameter types of function templates `FunctionTemplateTypeBuilder::build` gave a non-last parameter's type the scope of the parameters before it. Nothing in that type carries a template except an enum's type arguments, which `TemplateTypeBuilder::build` refines via `build_refined`; for a parameter whose type contains a generic enum the scope therefore leaked into the resulting type and left it open. `BasicBlockType::params` holds the enclosing function's arguments, and `analyze::basic_block` instantiates each of them against the caller's variable through `assert_closed`. A generic enum in any parameter but the last one thus aborted with "unexpected variable" as soon as the body had a block needing its own precondition. Build such a parameter without the scope, as the last parameter's own type is already built inside `build_refined`. Fixes #235 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01T3XpZ2MXjgs3JoodCr8iA9 --- src/refine/template.rs | 4 ++-- tests/ui/fail/option_param_order.rs | 15 +++++++++++++++ tests/ui/pass/option_param_order.rs | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 tests/ui/fail/option_param_order.rs create mode 100644 tests/ui/pass/option_param_order.rs diff --git a/src/refine/template.rs b/src/refine/template.rs index 3419ae67..246688cc 100644 --- a/src/refine/template.rs +++ b/src/refine/template.rs @@ -625,8 +625,8 @@ where rty::RefinedType::unrefined( self.inner .for_template(self.registry) - .with_scope(&builder) - .build(param_ty.ty), + .build(param_ty.ty) + .vacuous(), ) } }); diff --git a/tests/ui/fail/option_param_order.rs b/tests/ui/fail/option_param_order.rs new file mode 100644 index 00000000..ff668922 --- /dev/null +++ b/tests/ui/fail/option_param_order.rs @@ -0,0 +1,15 @@ +//@error-in-other-file: Unsat +//@compile-flags: -C debug-assertions=off + +fn get_or(o: Option, d: i64) -> i64 { + match o { + Some(x) => x, + None => d, + } +} + +fn main() { + assert!(get_or(Some(1), 9) == 1); + // `get_or` returns the default in the `None` case, so this assertion does not hold + assert!(get_or(None, 9) == 1); +} diff --git a/tests/ui/pass/option_param_order.rs b/tests/ui/pass/option_param_order.rs new file mode 100644 index 00000000..468f5b8f --- /dev/null +++ b/tests/ui/pass/option_param_order.rs @@ -0,0 +1,14 @@ +//@check-pass +//@compile-flags: -C debug-assertions=off + +fn get_or(o: Option, d: i64) -> i64 { + match o { + Some(x) => x, + None => d, + } +} + +fn main() { + assert!(get_or(Some(1), 9) == 1); + assert!(get_or(None, 9) == 9); +}