Fix lifetime elision handling for Fn-style trait bounds

Two fixes were needed:

 1. Previously, we enabled elision for the generic args of `Fn` itself, instead of for generic args of paths within it.
 2. In lowering in the new solver the `Output` parameter did not have elision set correctly, I don't know why. In the old lowering it was done correctly.
This commit is contained in:
Chayim Refael Friedman 2025-09-22 16:53:20 +03:00
parent e7d7cb415a
commit ad9422da1a
3 changed files with 55 additions and 25 deletions

View File

@ -603,7 +603,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
explicit_self_ty: Option<Ty>,
lowering_assoc_type_generics: bool,
) -> Substitution {
let mut lifetime_elision = self.ctx.lifetime_elision.clone();
let old_lifetime_elision = self.ctx.lifetime_elision.clone();
if let Some(args) = self.current_or_prev_segment.args_and_bindings
&& args.parenthesized != GenericArgsParentheses::No
@ -633,19 +633,21 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
}
// `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
lifetime_elision =
self.ctx.lifetime_elision =
LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
}
self.substs_from_args_and_bindings(
let result = self.substs_from_args_and_bindings(
self.current_or_prev_segment.args_and_bindings,
def,
infer_args,
explicit_self_ty,
PathGenericsSource::Segment(self.current_segment_u32()),
lowering_assoc_type_generics,
lifetime_elision,
)
self.ctx.lifetime_elision.clone(),
);
self.ctx.lifetime_elision = old_lifetime_elision;
result
}
pub(super) fn substs_from_args_and_bindings(

View File

@ -616,7 +616,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
explicit_self_ty: Option<Ty<'db>>,
lowering_assoc_type_generics: bool,
) -> crate::next_solver::GenericArgs<'db> {
let mut lifetime_elision = self.ctx.lifetime_elision.clone();
let old_lifetime_elision = self.ctx.lifetime_elision.clone();
if let Some(args) = self.current_or_prev_segment.args_and_bindings
&& args.parenthesized != GenericArgsParentheses::No
@ -646,19 +646,21 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
}
// `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
lifetime_elision =
self.ctx.lifetime_elision =
LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
}
self.substs_from_args_and_bindings(
let result = self.substs_from_args_and_bindings(
self.current_or_prev_segment.args_and_bindings,
def,
infer_args,
explicit_self_ty,
PathGenericsSource::Segment(self.current_segment_u32()),
lowering_assoc_type_generics,
lifetime_elision,
)
self.ctx.lifetime_elision.clone(),
);
self.ctx.lifetime_elision = old_lifetime_elision;
result
}
pub(super) fn substs_from_args_and_bindings(
@ -915,22 +917,36 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
);
if let Some(type_ref) = binding.type_ref {
match (&self.ctx.store[type_ref], self.ctx.impl_trait_mode.mode) {
(TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
(_, ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque) => {
let ty = self.ctx.lower_ty(type_ref);
let pred = Clause(Predicate::new(
interner,
Binder::dummy(rustc_type_ir::PredicateKind::Clause(
rustc_type_ir::ClauseKind::Projection(ProjectionPredicate {
projection_term,
term: ty.into(),
}),
)),
));
predicates.push(pred);
let lifetime_elision =
if args_and_bindings.parenthesized == GenericArgsParentheses::ParenSugar {
// `Fn()`-style generics are elided like functions. This is `Output` (we lower to it in hir-def).
LifetimeElisionKind::for_fn_ret(self.ctx.interner)
} else {
self.ctx.lifetime_elision.clone()
};
self.with_lifetime_elision(lifetime_elision, |this| {
match (&this.ctx.store[type_ref], this.ctx.impl_trait_mode.mode) {
(TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
(
_,
ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque,
) => {
let ty = this.ctx.lower_ty(type_ref);
let pred = Clause(Predicate::new(
interner,
Binder::dummy(rustc_type_ir::PredicateKind::Clause(
rustc_type_ir::ClauseKind::Projection(
ProjectionPredicate {
projection_term,
term: ty.into(),
},
),
)),
));
predicates.push(pred);
}
}
}
})
}
for bound in binding.bounds.iter() {
predicates.extend(self.ctx.lower_type_bound(

View File

@ -88,4 +88,16 @@ fn bar<const F: Foo>() {}
"#,
);
}
#[test]
fn fn_traits() {
check_diagnostics(
r#"
//- minicore: fn
struct WithLifetime<'a>(&'a ());
fn foo<T: Fn(WithLifetime) -> WithLifetime>() {}
"#,
);
}
}