From 5894e7260f668548f92d8b7a25379847f88a89d4 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 24 Oct 2026 21:52:20 +0000 Subject: [PATCH] Don't re-instantiate the already-instantiated signature in precompute_callable_param_contracts The signature passed in is built from the body, which generic_args has already instantiated. Instantiating its inputs again with the same args reinterpreted the impl's own parameters as indices into the trait method's args, so an impl with a lifetime parameter (impl<'a> Get for R<'a>) of a specified trait method panicked in rustc's binder. Fixes #354 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017R2xbmrztzZ35Qy7MPCymp --- src/analyze/local_def.rs | 4 +-- tests/ui/fail/trait_impl_lifetime_param.rs | 33 ++++++++++++++++++++++ tests/ui/pass/trait_impl_lifetime_param.rs | 33 ++++++++++++++++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 tests/ui/fail/trait_impl_lifetime_param.rs create mode 100644 tests/ui/pass/trait_impl_lifetime_param.rs diff --git a/src/analyze/local_def.rs b/src/analyze/local_def.rs index 6a9cdf1b5..366eaf853 100644 --- a/src/analyze/local_def.rs +++ b/src/analyze/local_def.rs @@ -232,11 +232,9 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> { // `def_ty_with_args` directly. fn precompute_callable_param_contracts(&mut self, sig: &mir_ty::FnSig<'tcx>) { for input_ty in sig.inputs() { - let inst = - mir_ty::EarlyBinder::bind(*input_ty).instantiate(self.tcx, self.generic_args); let inst = self .tcx - .normalize_erasing_regions(mir_ty::TypingEnv::fully_monomorphized(), inst); + .normalize_erasing_regions(mir_ty::TypingEnv::fully_monomorphized(), *input_ty); let (fn_def_id, fn_args) = match inst.kind() { mir_ty::TyKind::Closure(def_id, args) => { (*def_id, self.tcx.mk_args(args.as_closure().parent_args())) diff --git a/tests/ui/fail/trait_impl_lifetime_param.rs b/tests/ui/fail/trait_impl_lifetime_param.rs new file mode 100644 index 000000000..bafe10a89 --- /dev/null +++ b/tests/ui/fail/trait_impl_lifetime_param.rs @@ -0,0 +1,33 @@ +//@error-in-other-file: Unsat +//@compile-flags: -C debug-assertions=off + +#[thrust_macros::context] +trait Get { + #[thrust_macros::requires(true)] + #[thrust_macros::ensures(result >= 0)] + fn get(&self) -> i64; +} + +struct R<'a> { + r: &'a i64, +} + +impl<'a> thrust_models::Model for R<'a> { + type Ty = Self; +} + +impl<'a> Get for R<'a> { + fn get(&self) -> i64 { + if *self.r >= 0 { + *self.r + } else { + -1 + } + } +} + +fn main() { + let x = 5; + let r = R { r: &x }; + assert!(r.get() >= 0); +} diff --git a/tests/ui/pass/trait_impl_lifetime_param.rs b/tests/ui/pass/trait_impl_lifetime_param.rs new file mode 100644 index 000000000..9f86f7b1f --- /dev/null +++ b/tests/ui/pass/trait_impl_lifetime_param.rs @@ -0,0 +1,33 @@ +//@check-pass +//@compile-flags: -C debug-assertions=off + +#[thrust_macros::context] +trait Get { + #[thrust_macros::requires(true)] + #[thrust_macros::ensures(result >= 0)] + fn get(&self) -> i64; +} + +struct R<'a> { + r: &'a i64, +} + +impl<'a> thrust_models::Model for R<'a> { + type Ty = Self; +} + +impl<'a> Get for R<'a> { + fn get(&self) -> i64 { + if *self.r >= 0 { + *self.r + } else { + 0 + } + } +} + +fn main() { + let x = 5; + let r = R { r: &x }; + assert!(r.get() >= 0); +}