diff --git a/src/analyze/basic_block.rs b/src/analyze/basic_block.rs index 97ae3ec0..35ab10d5 100644 --- a/src/analyze/basic_block.rs +++ b/src/analyze/basic_block.rs @@ -920,12 +920,25 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> { } } + /// Analyzes the body of the implementation a call dispatches to. + /// + /// A call typed by a trait method's spec never asks for the implementing method's type, and + /// an implementation with generic parameters is analyzed only when its type is asked for. + fn analyze_resolved_impl_body(&mut self, def_id: DefId, args: mir_ty::GenericArgsRef<'tcx>) { + let (impl_def_id, impl_args) = self.resolve_fn_def(def_id, args); + if impl_def_id == def_id { + return; + } + let _ = self.ctx.def_ty_with_args(impl_def_id, impl_args); + } + fn fn_def_ty( &mut self, def_id: DefId, args: mir_ty::GenericArgsRef<'tcx>, ) -> rty::Type { if let Some(def_ty) = self.ctx.def_ty_with_args(def_id, args) { + self.analyze_resolved_impl_body(def_id, args); return def_ty.ty; } diff --git a/src/analyze/local_def.rs b/src/analyze/local_def.rs index a98eb1ce..f4b51a6e 100644 --- a/src/analyze/local_def.rs +++ b/src/analyze/local_def.rs @@ -45,6 +45,7 @@ pub struct Analyzer<'tcx, 'ctx> { local_def_id: LocalDefId, body: Body<'tcx>, + /// the instantiation of the def's generic parameters being analyzed, also used /// to substitute HIR types during translation in [`crate::analyze::annot_fn`] generic_args: mir_ty::GenericArgsRef<'tcx>, drop_points: HashMap, @@ -198,7 +199,11 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> { return None; } - let trait_ref = self.tcx.impl_trait_ref(impl_did)?.instantiate_identity(); + // an associated method's generic arguments start with those of its impl + let trait_ref = self + .tcx + .impl_trait_ref(impl_did)? + .instantiate(self.tcx, self.generic_args); let trait_item_did = self .tcx .associated_item(self.local_def_id.to_def_id()) @@ -1115,7 +1120,7 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> { let body = tcx.optimized_mir(local_def_id.to_def_id()).clone(); let drop_points = Default::default(); let type_builder = TypeBuilder::new(tcx, ctx.def_ids(), local_def_id.to_def_id()); - let generic_args = tcx.mk_args(&[]); + let generic_args = mir_ty::GenericArgs::identity_for_item(tcx, local_def_id); Self { ctx, tcx, diff --git a/tests/ui/fail/trait_generic_impl.rs b/tests/ui/fail/trait_generic_impl.rs new file mode 100644 index 00000000..0f9430a8 --- /dev/null +++ b/tests/ui/fail/trait_generic_impl.rs @@ -0,0 +1,29 @@ +//@error-in-other-file: Unsat +//@compile-flags: -C debug-assertions=off + +#[thrust_macros::context] +trait Tr { + #[thrust_macros::requires(true)] + #[thrust_macros::ensures(result > 0)] + fn m(&self) -> i32; +} + +struct W(T); + +impl thrust_models::Model for W +where + T: thrust_models::Model, +{ + type Ty = Self; +} + +impl Tr for W { + fn m(&self) -> i32 { + -1 + } +} + +fn main() { + let w = W(0i32); + assert!(w.m() > 0); +} diff --git a/tests/ui/pass/trait_generic_impl.rs b/tests/ui/pass/trait_generic_impl.rs new file mode 100644 index 00000000..b8a4abee --- /dev/null +++ b/tests/ui/pass/trait_generic_impl.rs @@ -0,0 +1,29 @@ +//@check-pass +//@compile-flags: -C debug-assertions=off + +#[thrust_macros::context] +trait Tr { + #[thrust_macros::requires(true)] + #[thrust_macros::ensures(result > 0)] + fn m(&self) -> i32; +} + +struct W(T); + +impl thrust_models::Model for W +where + T: thrust_models::Model, +{ + type Ty = Self; +} + +impl Tr for W { + fn m(&self) -> i32 { + 1 + } +} + +fn main() { + let w = W(0i32); + assert!(w.m() > 0); +}