Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/lower.rs51
-rw-r--r--crates/hir-ty/src/lower/path.rs8
-rw-r--r--crates/ide-diagnostics/src/handlers/missing_lifetime.rs15
3 files changed, 47 insertions, 27 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index a97d768716..9befca11b3 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -27,8 +27,8 @@ use hir_def::{
resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs},
signatures::{FunctionSignature, TraitFlags, TypeAliasFlags},
type_ref::{
- ConstRef, LifetimeRefId, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound,
- TypeRef, TypeRefId,
+ ConstRef, FnType, LifetimeRefId, PathId, TraitBoundModifier, TraitRef as HirTraitRef,
+ TypeBound, TypeRef, TypeRefId,
},
};
use hir_expand::name::Name;
@@ -98,7 +98,7 @@ impl ImplTraitLoweringState {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Copy)]
pub enum LifetimeElisionKind<'db> {
/// Create a new anonymous lifetime parameter and reference it.
///
@@ -437,26 +437,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
Ty::new_ref(interner, lifetime, inner_ty, lower_mutability(ref_.mutability))
}
TypeRef::Placeholder => Ty::new_error(interner, ErrorGuaranteed),
- TypeRef::Fn(fn_) => {
- let substs = self.with_shifted_in(
- DebruijnIndex::from_u32(1),
- |ctx: &mut TyLoweringContext<'_, '_>| {
- Tys::new_from_iter(
- interner,
- fn_.params.iter().map(|&(_, tr)| ctx.lower_ty(tr)),
- )
- },
- );
- Ty::new_fn_ptr(
- interner,
- Binder::dummy(FnSig {
- abi: fn_.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
- safety: if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe },
- c_variadic: fn_.is_varargs,
- inputs_and_output: substs,
- }),
- )
- }
+ TypeRef::Fn(fn_) => self.lower_fn_ptr(fn_),
TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
TypeRef::ImplTrait(bounds) => {
match self.impl_trait_mode.mode {
@@ -517,6 +498,30 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
(ty, res)
}
+ fn lower_fn_ptr(&mut self, fn_: &FnType) -> Ty<'db> {
+ let interner = self.interner;
+ let (params, ret_ty) = fn_.split_params_and_ret();
+ let old_lifetime_elision = self.lifetime_elision;
+ let mut args = Vec::with_capacity(fn_.params.len());
+ self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx: &mut TyLoweringContext<'_, '_>| {
+ ctx.lifetime_elision =
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
+ args.extend(params.iter().map(|&(_, tr)| ctx.lower_ty(tr)));
+ ctx.lifetime_elision = LifetimeElisionKind::for_fn_ret(interner);
+ args.push(ctx.lower_ty(ret_ty));
+ });
+ self.lifetime_elision = old_lifetime_elision;
+ Ty::new_fn_ptr(
+ interner,
+ Binder::dummy(FnSig {
+ abi: fn_.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
+ safety: if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe },
+ c_variadic: fn_.is_varargs,
+ inputs_and_output: Tys::new_from_slice(&args),
+ }),
+ )
+ }
+
/// This is only for `generic_predicates_for_param`, where we can't just
/// lower the self types of the predicates since that could lead to cycles.
/// So we just check here if the `type_ref` resolves to a generic param, and which.
diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs
index b77aeab62d..f3d0de1227 100644
--- a/crates/hir-ty/src/lower/path.rs
+++ b/crates/hir-ty/src/lower/path.rs
@@ -599,7 +599,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
explicit_self_ty: Option<Ty<'db>>,
lowering_assoc_type_generics: bool,
) -> GenericArgs<'db> {
- let old_lifetime_elision = self.ctx.lifetime_elision.clone();
+ let old_lifetime_elision = self.ctx.lifetime_elision;
if let Some(args) = self.current_or_prev_segment.args_and_bindings
&& args.parenthesized != GenericArgsParentheses::No
@@ -640,7 +640,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
explicit_self_ty,
PathGenericsSource::Segment(self.current_segment_u32()),
lowering_assoc_type_generics,
- self.ctx.lifetime_elision.clone(),
+ self.ctx.lifetime_elision,
);
self.ctx.lifetime_elision = old_lifetime_elision;
result
@@ -884,7 +884,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
assoc_type: binding_idx as u32,
},
false,
- this.ctx.lifetime_elision.clone(),
+ this.ctx.lifetime_elision,
)
});
let args = GenericArgs::new_from_iter(
@@ -902,7 +902,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
// `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.ctx.lifetime_elision
};
self.with_lifetime_elision(lifetime_elision, |this| {
match (&this.ctx.store[type_ref], this.ctx.impl_trait_mode.mode) {
diff --git a/crates/ide-diagnostics/src/handlers/missing_lifetime.rs b/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
index b07f9e68f6..5cb710b66b 100644
--- a/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
@@ -100,4 +100,19 @@ fn foo<T: Fn(WithLifetime) -> WithLifetime>() {}
"#,
);
}
+
+ #[test]
+ fn regression_21430() {
+ check_diagnostics(
+ r#"
+struct S {
+ f: fn(A<()>),
+}
+
+struct A<'a, T> {
+ a: &'a T,
+}
+ "#,
+ );
+ }
}