Properly handle lifetimes when checking generic arguments len
And also, prepare for correct lowering of lifetime. We still don't handle most lifetimes correctly, but a bit more of the foundation to lifetime elision is now implemented.
diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs
index 1fd878a..6b7f03e 100644
--- a/crates/hir-def/src/hir/type_ref.rs
+++ b/crates/hir-def/src/hir/type_ref.rs
@@ -106,6 +106,14 @@
pub abi: Option<Symbol>,
}
+impl FnType {
+ #[inline]
+ pub fn split_params_and_ret(&self) -> (&[(Option<Name>, TypeRefId)], TypeRefId) {
+ let (ret, params) = self.params.split_last().expect("should have at least return type");
+ (params, ret.1)
+ }
+}
+
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct ArrayType {
pub ty: TypeRefId,
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index bf16e08..2aa9401 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -27,6 +27,7 @@
db::{HirDatabase, InternedCoroutine},
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
generics::generics,
+ lower::LifetimeElisionKind,
make_binders, make_single_type_binders,
mapping::{ToChalk, TypeAliasAsValue, from_chalk},
method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TraitImpls, TyFingerprint},
@@ -632,9 +633,14 @@
let type_alias_data = db.type_alias_signature(type_alias);
let generic_params = generics(db, type_alias.into());
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db);
- let mut ctx =
- crate::TyLoweringContext::new(db, &resolver, &type_alias_data.store, type_alias.into())
- .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
+ let mut ctx = crate::TyLoweringContext::new(
+ db,
+ &resolver,
+ &type_alias_data.store,
+ type_alias.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ )
+ .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
.fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0)
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index cad2e3c..38807b6 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -34,8 +34,8 @@
};
use either::Either;
use hir_def::{
- AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, GenericDefId, GenericParamId, ImplId,
- ItemContainerId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
+ AdtId, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, GenericParamId,
+ ImplId, ItemContainerId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
expr_store::{Body, ExpressionStore, HygieneId, path::Path},
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
@@ -67,9 +67,9 @@
expr::ExprIsRead,
unify::InferenceTable,
},
- lower::{GenericArgsPosition, ImplTraitLoweringMode, diagnostics::TyLoweringDiagnostic},
+ lower::{ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic},
mir::MirSpan,
- to_assoc_type_id,
+ static_lifetime, to_assoc_type_id,
traits::FnTrait,
utils::UnevaluatedConstEvaluatorFolder,
};
@@ -96,7 +96,7 @@
DefWithBodyId::FunctionId(f) => {
ctx.collect_fn(f);
}
- DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_signature(c)),
+ DefWithBodyId::ConstId(c) => ctx.collect_const(c, &db.const_signature(c)),
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_signature(s)),
DefWithBodyId::VariantId(v) => {
ctx.return_ty = TyBuilder::builtin(
@@ -899,9 +899,13 @@
result
}
- fn collect_const(&mut self, data: &ConstSignature) {
- let return_ty =
- self.make_ty(data.type_ref, &data.store, InferenceTyDiagnosticSource::Signature);
+ fn collect_const(&mut self, id: ConstId, data: &ConstSignature) {
+ let return_ty = self.make_ty(
+ data.type_ref,
+ &data.store,
+ InferenceTyDiagnosticSource::Signature,
+ LifetimeElisionKind::for_const(id.loc(self.db).container),
+ );
// Constants might be defining usage sites of TAITs.
self.make_tait_coercion_table(iter::once(&return_ty));
@@ -910,8 +914,12 @@
}
fn collect_static(&mut self, data: &StaticSignature) {
- let return_ty =
- self.make_ty(data.type_ref, &data.store, InferenceTyDiagnosticSource::Signature);
+ let return_ty = self.make_ty(
+ data.type_ref,
+ &data.store,
+ InferenceTyDiagnosticSource::Signature,
+ LifetimeElisionKind::Elided(static_lifetime()),
+ );
// Statics might be defining usage sites of TAITs.
self.make_tait_coercion_table(iter::once(&return_ty));
@@ -921,12 +929,15 @@
fn collect_fn(&mut self, func: FunctionId) {
let data = self.db.function_signature(func);
- let mut param_tys =
- self.with_ty_lowering(&data.store, InferenceTyDiagnosticSource::Signature, |ctx| {
+ let mut param_tys = self.with_ty_lowering(
+ &data.store,
+ InferenceTyDiagnosticSource::Signature,
+ LifetimeElisionKind::for_fn_params(&data),
+ |ctx| {
ctx.type_param_mode(ParamLoweringMode::Placeholder);
- ctx.in_fn_signature = true;
data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>()
- });
+ },
+ );
// Check if function contains a va_list, if it does then we append it to the parameter types
// that are collected from the function data
@@ -967,10 +978,10 @@
let return_ty = self.with_ty_lowering(
&data.store,
InferenceTyDiagnosticSource::Signature,
+ LifetimeElisionKind::for_fn_ret(),
|ctx| {
ctx.type_param_mode(ParamLoweringMode::Placeholder)
.impl_trait_mode(ImplTraitLoweringMode::Opaque);
- ctx.in_fn_signature = true;
ctx.lower_ty(return_ty)
},
);
@@ -1304,6 +1315,7 @@
&mut self,
store: &ExpressionStore,
types_source: InferenceTyDiagnosticSource,
+ lifetime_elision: LifetimeElisionKind,
f: impl FnOnce(&mut TyLoweringContext<'_>) -> R,
) -> R {
let mut ctx = TyLoweringContext::new(
@@ -1313,12 +1325,18 @@
&self.diagnostics,
types_source,
self.generic_def,
+ lifetime_elision,
);
f(&mut ctx)
}
fn with_body_ty_lowering<R>(&mut self, f: impl FnOnce(&mut TyLoweringContext<'_>) -> R) -> R {
- self.with_ty_lowering(self.body, InferenceTyDiagnosticSource::Body, f)
+ self.with_ty_lowering(
+ self.body,
+ InferenceTyDiagnosticSource::Body,
+ LifetimeElisionKind::Infer,
+ f,
+ )
}
fn make_ty(
@@ -1326,29 +1344,46 @@
type_ref: TypeRefId,
store: &ExpressionStore,
type_source: InferenceTyDiagnosticSource,
+ lifetime_elision: LifetimeElisionKind,
) -> Ty {
- let ty = self.with_ty_lowering(store, type_source, |ctx| ctx.lower_ty(type_ref));
+ let ty = self
+ .with_ty_lowering(store, type_source, lifetime_elision, |ctx| ctx.lower_ty(type_ref));
let ty = self.insert_type_vars(ty);
self.normalize_associated_types_in(ty)
}
fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty {
- self.make_ty(type_ref, self.body, InferenceTyDiagnosticSource::Body)
+ self.make_ty(
+ type_ref,
+ self.body,
+ InferenceTyDiagnosticSource::Body,
+ LifetimeElisionKind::Infer,
+ )
}
fn make_body_const(&mut self, const_ref: ConstRef, ty: Ty) -> Const {
- let const_ = self.with_ty_lowering(self.body, InferenceTyDiagnosticSource::Body, |ctx| {
- ctx.type_param_mode = ParamLoweringMode::Placeholder;
- ctx.lower_const(&const_ref, ty)
- });
+ let const_ = self.with_ty_lowering(
+ self.body,
+ InferenceTyDiagnosticSource::Body,
+ LifetimeElisionKind::Infer,
+ |ctx| {
+ ctx.type_param_mode = ParamLoweringMode::Placeholder;
+ ctx.lower_const(&const_ref, ty)
+ },
+ );
self.insert_type_vars(const_)
}
fn make_path_as_body_const(&mut self, path: &Path, ty: Ty) -> Const {
- let const_ = self.with_ty_lowering(self.body, InferenceTyDiagnosticSource::Body, |ctx| {
- ctx.type_param_mode = ParamLoweringMode::Placeholder;
- ctx.lower_path_as_const(path, ty)
- });
+ let const_ = self.with_ty_lowering(
+ self.body,
+ InferenceTyDiagnosticSource::Body,
+ LifetimeElisionKind::Infer,
+ |ctx| {
+ ctx.type_param_mode = ParamLoweringMode::Placeholder;
+ ctx.lower_path_as_const(path, ty)
+ },
+ );
self.insert_type_vars(const_)
}
@@ -1357,9 +1392,12 @@
}
fn make_body_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime {
- let lt = self.with_ty_lowering(self.body, InferenceTyDiagnosticSource::Body, |ctx| {
- ctx.lower_lifetime(lifetime_ref)
- });
+ let lt = self.with_ty_lowering(
+ self.body,
+ InferenceTyDiagnosticSource::Body,
+ LifetimeElisionKind::Infer,
+ |ctx| ctx.lower_lifetime(lifetime_ref),
+ );
self.insert_type_vars(lt)
}
@@ -1529,8 +1567,9 @@
&self.diagnostics,
InferenceTyDiagnosticSource::Body,
self.generic_def,
+ LifetimeElisionKind::Infer,
);
- let mut path_ctx = ctx.at_path(path, node, GenericArgsPosition::Value);
+ let mut path_ctx = ctx.at_path(path, node);
let (resolution, unresolved) = if value_ns {
let Some(res) = path_ctx.resolve_path_in_value_ns(HygieneId::ROOT) else {
return (self.err_ty(), None);
@@ -1538,14 +1577,14 @@
match res {
ResolveValueResult::ValueNs(value, _) => match value {
ValueNs::EnumVariantId(var) => {
- let substs = path_ctx.substs_from_path(var.into(), true);
+ let substs = path_ctx.substs_from_path(var.into(), true, false);
drop(ctx);
let ty = self.db.ty(var.lookup(self.db).parent.into());
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
return (ty, Some(var.into()));
}
ValueNs::StructId(strukt) => {
- let substs = path_ctx.substs_from_path(strukt.into(), true);
+ let substs = path_ctx.substs_from_path(strukt.into(), true, false);
drop(ctx);
let ty = self.db.ty(strukt.into());
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
@@ -1567,21 +1606,21 @@
};
return match resolution {
TypeNs::AdtId(AdtId::StructId(strukt)) => {
- let substs = path_ctx.substs_from_path(strukt.into(), true);
+ let substs = path_ctx.substs_from_path(strukt.into(), true, false);
drop(ctx);
let ty = self.db.ty(strukt.into());
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
}
TypeNs::AdtId(AdtId::UnionId(u)) => {
- let substs = path_ctx.substs_from_path(u.into(), true);
+ let substs = path_ctx.substs_from_path(u.into(), true, false);
drop(ctx);
let ty = self.db.ty(u.into());
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
forbid_unresolved_segments((ty, Some(u.into())), unresolved)
}
TypeNs::EnumVariantId(var) => {
- let substs = path_ctx.substs_from_path(var.into(), true);
+ let substs = path_ctx.substs_from_path(var.into(), true, false);
drop(ctx);
let ty = self.db.ty(var.lookup(self.db).parent.into());
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
@@ -1665,7 +1704,7 @@
never!("resolver should always resolve lang item paths");
return (self.err_ty(), None);
};
- let substs = path_ctx.substs_from_path_segment(it.into(), true, None);
+ let substs = path_ctx.substs_from_path_segment(it.into(), true, None, false);
drop(ctx);
let ty = self.db.ty(it.into());
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 59ec3ad..e7b776a 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -440,6 +440,8 @@
// collect explicitly written argument types
for arg_type in arg_types.iter() {
let arg_ty = match arg_type {
+ // FIXME: I think rustc actually lowers closure params with `LifetimeElisionKind::AnonymousCreateParameter`
+ // (but the return type with infer).
Some(type_ref) => self.make_body_ty(*type_ref),
None => self.table.new_type_var(),
};
diff --git a/crates/hir-ty/src/infer/diagnostics.rs b/crates/hir-ty/src/infer/diagnostics.rs
index 2c633a0..e3c4f55 100644
--- a/crates/hir-ty/src/infer/diagnostics.rs
+++ b/crates/hir-ty/src/infer/diagnostics.rs
@@ -12,7 +12,7 @@
use hir_def::{hir::ExprOrPatId, resolver::Resolver};
use la_arena::{Idx, RawIdx};
-use crate::lower::GenericArgsPosition;
+use crate::lower::LifetimeElisionKind;
use crate::{
InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringContext, TyLoweringDiagnostic,
db::HirDatabase,
@@ -66,8 +66,13 @@
diagnostics: &'a Diagnostics,
source: InferenceTyDiagnosticSource,
generic_def: GenericDefId,
+ lifetime_elision: LifetimeElisionKind,
) -> Self {
- Self { ctx: TyLoweringContext::new(db, resolver, store, generic_def), diagnostics, source }
+ Self {
+ ctx: TyLoweringContext::new(db, resolver, store, generic_def, lifetime_elision),
+ diagnostics,
+ source,
+ }
}
#[inline]
@@ -75,7 +80,6 @@
&'b mut self,
path: &'b Path,
node: ExprOrPatId,
- position: GenericArgsPosition,
) -> PathLoweringContext<'b, 'a> {
let on_diagnostic = PathDiagnosticCallback {
data: Either::Right(PathDiagnosticCallbackData { diagnostics: self.diagnostics, node }),
@@ -85,14 +89,13 @@
.push(InferenceDiagnostic::PathDiagnostic { node: data.node, diag });
},
};
- PathLoweringContext::new(&mut self.ctx, on_diagnostic, path, position)
+ PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
}
#[inline]
pub(super) fn at_path_forget_diagnostics<'b>(
&'b mut self,
path: &'b Path,
- position: GenericArgsPosition,
) -> PathLoweringContext<'b, 'a> {
let on_diagnostic = PathDiagnosticCallback {
data: Either::Right(PathDiagnosticCallbackData {
@@ -101,7 +104,7 @@
}),
callback: |_data, _, _diag| {},
};
- PathLoweringContext::new(&mut self.ctx, on_diagnostic, path, position)
+ PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
}
#[inline]
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 2980549..643587e 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -37,7 +37,7 @@
},
lang_items::lang_items_for_bin_op,
lower::{
- GenericArgsPosition, ParamLoweringMode, lower_to_chalk_mutability,
+ LifetimeElisionKind, ParamLoweringMode, lower_to_chalk_mutability,
path::{GenericArgsLowerer, TypeLikeConst, substs_from_args_and_bindings},
},
mapping::{ToChalk, from_chalk},
@@ -2162,6 +2162,23 @@
}
}
}
+
+ fn report_elided_lifetimes_in_path(
+ &mut self,
+ _def: GenericDefId,
+ _expected_count: u32,
+ _hard_error: bool,
+ ) {
+ unreachable!("we set `LifetimeElisionKind::Infer`")
+ }
+
+ fn report_elision_failure(&mut self, _def: GenericDefId, _expected_count: u32) {
+ unreachable!("we set `LifetimeElisionKind::Infer`")
+ }
+
+ fn report_missing_lifetime(&mut self, _def: GenericDefId, _expected_count: u32) {
+ unreachable!("we set `LifetimeElisionKind::Infer`")
+ }
}
substs_from_args_and_bindings(
@@ -2170,7 +2187,8 @@
generic_args,
def,
true,
- GenericArgsPosition::MethodCall,
+ LifetimeElisionKind::Infer,
+ false,
None,
&mut LowererCtx { ctx: self, expr },
)
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 0e1d23b..bdaec61 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -16,7 +16,7 @@
consteval, error_lifetime,
generics::generics,
infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
- lower::GenericArgsPosition,
+ lower::LifetimeElisionKind,
method_resolution::{self, VisibleFromModule},
to_chalk_trait_id,
};
@@ -96,12 +96,12 @@
};
let substs = self.with_body_ty_lowering(|ctx| {
- let mut path_ctx = ctx.at_path(path, id, GenericArgsPosition::Value);
+ let mut path_ctx = ctx.at_path(path, id);
let last_segment = path.segments().len().checked_sub(1);
if let Some(last_segment) = last_segment {
path_ctx.set_current_segment(last_segment)
}
- path_ctx.substs_from_path(value_def, true)
+ path_ctx.substs_from_path(value_def, true, false)
});
let substs = substs.as_slice(Interner);
@@ -162,11 +162,12 @@
&self.diagnostics,
InferenceTyDiagnosticSource::Body,
self.generic_def,
+ LifetimeElisionKind::Infer,
);
let mut path_ctx = if no_diagnostics {
- ctx.at_path_forget_diagnostics(path, GenericArgsPosition::Value)
+ ctx.at_path_forget_diagnostics(path)
} else {
- ctx.at_path(path, id, GenericArgsPosition::Value)
+ ctx.at_path(path, id)
};
let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
let last = path.segments().last()?;
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 2cb977b..128569d 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -94,8 +94,8 @@
};
pub use interner::Interner;
pub use lower::{
- ImplTraitLoweringMode, ParamLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId,
- associated_type_shorthand_candidates, diagnostics::*,
+ ImplTraitLoweringMode, LifetimeElisionKind, ParamLoweringMode, TyDefId, TyLoweringContext,
+ ValueTyDefId, associated_type_shorthand_candidates, diagnostics::*,
};
pub use mapping::{
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
@@ -529,13 +529,13 @@
impl CallableSig {
pub fn from_params_and_return(
- params: impl ExactSizeIterator<Item = Ty>,
+ params: impl Iterator<Item = Ty>,
ret: Ty,
is_varargs: bool,
safety: Safety,
abi: FnAbi,
) -> CallableSig {
- let mut params_and_return = Vec::with_capacity(params.len() + 1);
+ let mut params_and_return = Vec::with_capacity(params.size_hint().0 + 1);
params_and_return.extend(params);
params_and_return.push(ret);
CallableSig { params_and_return: params_and_return.into(), is_varargs, safety, abi }
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 073a584..eecca32 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -25,8 +25,8 @@
use either::Either;
use hir_def::{
AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
- FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, LocalFieldId, Lookup, StaticId,
- StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId,
+ FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId,
+ Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId,
builtin_type::BuiltinType,
expr_store::{ExpressionStore, path::Path},
hir::generics::{
@@ -35,7 +35,7 @@
item_tree::FieldsShape,
lang_item::LangItem,
resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
- signatures::{TraitFlags, TypeAliasFlags},
+ signatures::{FunctionSignature, TraitFlags, TypeAliasFlags},
type_ref::{
ConstRef, LifetimeRef, LiteralConstRef, PathId, TraitBoundModifier,
TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId,
@@ -86,21 +86,70 @@
pub(crate) struct PathDiagnosticCallbackData(TypeRefId);
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(crate) enum GenericArgsPosition {
- Type,
- /// E.g. functions.
- Value,
- MethodCall,
- // FIXME: This is a temporary variant we need to work around the lack of lifetime elision.
- // The reason for its existence is that in `check_generic_args_len()`, without this, we will
- // not infer elide lifetimes.
- // They indeed should not be inferred - they should be elided - but we won't elide them either,
- // emitting an error instead. rustc elides them in late resolve, and the generics it passes
- // to lowering already include them. We probably can't do that, but we will still need to
- // account for them when we properly implement lifetime elision.
- FnSignature,
- OtherSignature,
+#[derive(Debug, Clone)]
+pub enum LifetimeElisionKind {
+ /// Create a new anonymous lifetime parameter and reference it.
+ ///
+ /// If `report_in_path`, report an error when encountering lifetime elision in a path:
+ /// ```compile_fail
+ /// struct Foo<'a> { x: &'a () }
+ /// async fn foo(x: Foo) {}
+ /// ```
+ ///
+ /// Note: the error should not trigger when the elided lifetime is in a pattern or
+ /// expression-position path:
+ /// ```
+ /// struct Foo<'a> { x: &'a () }
+ /// async fn foo(Foo { x: _ }: Foo<'_>) {}
+ /// ```
+ AnonymousCreateParameter { report_in_path: bool },
+
+ /// Replace all anonymous lifetimes by provided lifetime.
+ Elided(Lifetime),
+
+ /// Give a hard error when either `&` or `'_` is written. Used to
+ /// rule out things like `where T: Foo<'_>`. Does not imply an
+ /// error on default object bounds (e.g., `Box<dyn Foo>`).
+ AnonymousReportError,
+
+ /// Resolves elided lifetimes to `'static` if there are no other lifetimes in scope,
+ /// otherwise give a warning that the previous behavior of introducing a new early-bound
+ /// lifetime is a bug and will be removed (if `only_lint` is enabled).
+ StaticIfNoLifetimeInScope { only_lint: bool },
+
+ /// Signal we cannot find which should be the anonymous lifetime.
+ ElisionFailure,
+
+ /// Infer all elided lifetimes.
+ Infer,
+}
+
+impl LifetimeElisionKind {
+ #[inline]
+ pub(crate) fn for_const(const_parent: ItemContainerId) -> LifetimeElisionKind {
+ match const_parent {
+ ItemContainerId::ExternBlockId(_) | ItemContainerId::ModuleId(_) => {
+ LifetimeElisionKind::Elided(static_lifetime())
+ }
+ ItemContainerId::ImplId(_) => {
+ LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: true }
+ }
+ ItemContainerId::TraitId(_) => {
+ LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: false }
+ }
+ }
+ }
+
+ #[inline]
+ pub(crate) fn for_fn_params(data: &FunctionSignature) -> LifetimeElisionKind {
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: data.is_async() }
+ }
+
+ #[inline]
+ pub(crate) fn for_fn_ret() -> LifetimeElisionKind {
+ // FIXME: We should use the elided lifetime here, or `ElisionFailure`.
+ LifetimeElisionKind::Elided(error_lifetime())
+ }
}
#[derive(Debug)]
@@ -120,7 +169,7 @@
/// Tracks types with explicit `?Sized` bounds.
pub(crate) unsized_types: FxHashSet<Ty>,
pub(crate) diagnostics: Vec<TyLoweringDiagnostic>,
- pub(crate) in_fn_signature: bool,
+ lifetime_elision: LifetimeElisionKind,
}
impl<'a> TyLoweringContext<'a> {
@@ -129,6 +178,7 @@
resolver: &'a Resolver,
store: &'a ExpressionStore,
def: GenericDefId,
+ lifetime_elision: LifetimeElisionKind,
) -> Self {
let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed);
let type_param_mode = ParamLoweringMode::Placeholder;
@@ -144,7 +194,7 @@
type_param_mode,
unsized_types: FxHashSet::default(),
diagnostics: Vec::new(),
- in_fn_signature: false,
+ lifetime_elision,
}
}
@@ -167,6 +217,17 @@
self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f)
}
+ fn with_lifetime_elision<T>(
+ &mut self,
+ lifetime_elision: LifetimeElisionKind,
+ f: impl FnOnce(&mut TyLoweringContext<'_>) -> T,
+ ) -> T {
+ let old_lifetime_elision = mem::replace(&mut self.lifetime_elision, lifetime_elision);
+ let result = f(self);
+ self.lifetime_elision = old_lifetime_elision;
+ result
+ }
+
pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self }
}
@@ -318,10 +379,18 @@
TypeRef::Placeholder => TyKind::Error.intern(Interner),
TypeRef::Fn(fn_) => {
let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
- Substitution::from_iter(
- Interner,
- fn_.params.iter().map(|&(_, tr)| ctx.lower_ty(tr)),
- )
+ let (params, ret) = fn_.split_params_and_ret();
+ let mut subst = Vec::with_capacity(fn_.params.len());
+ ctx.with_lifetime_elision(
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false },
+ |ctx| {
+ subst.extend(params.iter().map(|&(_, tr)| ctx.lower_ty(tr)));
+ },
+ );
+ ctx.with_lifetime_elision(LifetimeElisionKind::for_fn_ret(), |ctx| {
+ subst.push(ctx.lower_ty(ret));
+ });
+ Substitution::from_iter(Interner, subst)
});
TyKind::Function(FnPointer {
num_binders: 0, // FIXME lower `for<'a> fn()` correctly
@@ -431,11 +500,6 @@
self,
Self::on_path_diagnostic_callback(path_id.type_ref()),
&self.store[path_id],
- if self.in_fn_signature {
- GenericArgsPosition::FnSignature
- } else {
- GenericArgsPosition::Type
- },
)
}
@@ -855,8 +919,14 @@
};
let generics = generics(db, def);
let mut res = ArenaMap::default();
- let mut ctx = TyLoweringContext::new(db, &resolver, &var_data.store, def)
- .with_type_param_mode(ParamLoweringMode::Variable);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &var_data.store,
+ def,
+ LifetimeElisionKind::AnonymousReportError,
+ )
+ .with_type_param_mode(ParamLoweringMode::Variable);
for (field_id, field_data) in var_data.fields().iter() {
res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref)));
}
@@ -879,8 +949,14 @@
) -> GenericPredicates {
let generics = generics(db, def);
let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(db, &resolver, generics.store(), def)
- .with_type_param_mode(ParamLoweringMode::Variable);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ generics.store(),
+ def,
+ LifetimeElisionKind::AnonymousReportError,
+ )
+ .with_type_param_mode(ParamLoweringMode::Variable);
// we have to filter out all other predicates *first*, before attempting to lower them
let predicate = |pred: &_, generics: &Generics, ctx: &mut TyLoweringContext<'_>| match pred {
@@ -987,8 +1063,14 @@
) -> Arc<TraitEnvironment> {
let generics = generics(db, def);
let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(db, &resolver, generics.store(), def)
- .with_type_param_mode(ParamLoweringMode::Placeholder);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ generics.store(),
+ def,
+ LifetimeElisionKind::AnonymousReportError,
+ )
+ .with_type_param_mode(ParamLoweringMode::Placeholder);
let mut traits_in_scope = Vec::new();
let mut clauses = Vec::new();
for maybe_parent_generics in
@@ -1086,8 +1168,14 @@
{
let generics = generics(db, def);
let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(db, &resolver, generics.store(), def)
- .with_type_param_mode(ParamLoweringMode::Variable);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ generics.store(),
+ def,
+ LifetimeElisionKind::AnonymousReportError,
+ )
+ .with_type_param_mode(ParamLoweringMode::Variable);
let mut predicates = Vec::new();
for maybe_parent_generics in
@@ -1188,9 +1276,15 @@
}
let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(db, &resolver, generic_params.store(), def)
- .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
- .with_type_param_mode(ParamLoweringMode::Variable);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ generic_params.store(),
+ def,
+ LifetimeElisionKind::AnonymousReportError,
+ )
+ .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
+ .with_type_param_mode(ParamLoweringMode::Variable);
let mut idx = 0;
let mut has_any_default = false;
let mut defaults = generic_params
@@ -1273,17 +1367,27 @@
fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
let data = db.function_signature(def);
let resolver = def.resolver(db);
- let mut ctx_params = TyLoweringContext::new(db, &resolver, &data.store, def.into())
- .with_type_param_mode(ParamLoweringMode::Variable);
- ctx_params.in_fn_signature = true;
+ let mut ctx_params = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::for_fn_params(&data),
+ )
+ .with_type_param_mode(ParamLoweringMode::Variable);
let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
let ret = match data.ret_type {
Some(ret_type) => {
- let mut ctx_ret = TyLoweringContext::new(db, &resolver, &data.store, def.into())
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
- .with_type_param_mode(ParamLoweringMode::Variable);
- ctx_ret.in_fn_signature = true;
+ let mut ctx_ret = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::for_fn_ret(),
+ )
+ .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
+ .with_type_param_mode(ParamLoweringMode::Variable);
ctx_ret.lower_ty(ret_type)
}
None => TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
@@ -1316,8 +1420,15 @@
let data = db.const_signature(def);
let generics = generics(db, def.into());
let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(db, &resolver, &data.store, def.into())
- .with_type_param_mode(ParamLoweringMode::Variable);
+ let parent = def.loc(db).container;
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::for_const(parent),
+ )
+ .with_type_param_mode(ParamLoweringMode::Variable);
make_binders(db, &generics, ctx.lower_ty(data.type_ref))
}
@@ -1326,18 +1437,20 @@
fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> {
let data = db.static_signature(def);
let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(db, &resolver, &data.store, def.into());
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::Elided(static_lifetime()),
+ );
Binders::empty(Interner, ctx.lower_ty(data.type_ref))
}
fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig {
- let struct_data = db.variant_fields(def.into());
- let fields = struct_data.fields();
- let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(db, &resolver, &struct_data.store, def.into())
- .with_type_param_mode(ParamLoweringMode::Variable);
- let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref));
+ let field_tys = db.field_types(def.into());
+ let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone());
let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
Binders::new(
binders,
@@ -1364,13 +1477,9 @@
}
fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> PolyFnSig {
- let var_data = db.variant_fields(def.into());
- let fields = var_data.fields();
- let resolver = def.resolver(db);
+ let field_tys = db.field_types(def.into());
+ let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone());
let parent = def.lookup(db).parent;
- let mut ctx = TyLoweringContext::new(db, &resolver, &var_data.store, parent.into())
- .with_type_param_mode(ParamLoweringMode::Variable);
- let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref));
let (ret, binders) = type_for_adt(db, parent.into()).into_value_and_skipped_binders();
Binders::new(
binders,
@@ -1429,9 +1538,15 @@
} else {
let resolver = t.resolver(db);
let alias = db.type_alias_signature(t);
- let mut ctx = TyLoweringContext::new(db, &resolver, &alias.store, t.into())
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
- .with_type_param_mode(ParamLoweringMode::Variable);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &alias.store,
+ t.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ )
+ .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
+ .with_type_param_mode(ParamLoweringMode::Variable);
let res = alias
.ty
.map(|type_ref| ctx.lower_ty(type_ref))
@@ -1517,8 +1632,14 @@
let impl_data = db.impl_signature(impl_id);
let resolver = impl_id.resolver(db);
let generics = generics(db, impl_id.into());
- let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.store, impl_id.into())
- .with_type_param_mode(ParamLoweringMode::Variable);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &impl_data.store,
+ impl_id.into(),
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
+ )
+ .with_type_param_mode(ParamLoweringMode::Variable);
(
make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)),
create_diagnostics(ctx.diagnostics),
@@ -1537,7 +1658,13 @@
let (parent_data, store) = db.generic_params_and_store(def.parent());
let data = &parent_data[def.local_id()];
let resolver = def.parent().resolver(db);
- let mut ctx = TyLoweringContext::new(db, &resolver, &store, def.parent());
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &store,
+ def.parent(),
+ LifetimeElisionKind::AnonymousReportError,
+ );
let ty = match data {
TypeOrConstParamData::TypeParamData(_) => {
never!();
@@ -1566,8 +1693,14 @@
) -> Option<(Binders<TraitRef>, Diagnostics)> {
let impl_data = db.impl_signature(impl_id);
let resolver = impl_id.resolver(db);
- let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.store, impl_id.into())
- .with_type_param_mode(ParamLoweringMode::Variable);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &impl_data.store,
+ impl_id.into(),
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
+ )
+ .with_type_param_mode(ParamLoweringMode::Variable);
let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
let target_trait = impl_data.target_trait.as_ref()?;
let trait_ref = Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?);
@@ -1581,9 +1714,10 @@
// FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
let data = db.function_signature(def);
let resolver = def.resolver(db);
- let mut ctx_ret = TyLoweringContext::new(db, &resolver, &data.store, def.into())
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
- .with_type_param_mode(ParamLoweringMode::Variable);
+ let mut ctx_ret =
+ TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer)
+ .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
+ .with_type_param_mode(ParamLoweringMode::Variable);
if let Some(ret_type) = data.ret_type {
let _ret = ctx_ret.lower_ty(ret_type);
}
@@ -1603,9 +1737,15 @@
) -> Option<Arc<Binders<ImplTraits>>> {
let data = db.type_alias_signature(def);
let resolver = def.resolver(db);
- let mut ctx = TyLoweringContext::new(db, &resolver, &data.store, def.into())
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
- .with_type_param_mode(ParamLoweringMode::Variable);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &data.store,
+ def.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ )
+ .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
+ .with_type_param_mode(ParamLoweringMode::Variable);
if let Some(type_ref) = data.ty {
let _ty = ctx.lower_ty(type_ref);
}
diff --git a/crates/hir-ty/src/lower/diagnostics.rs b/crates/hir-ty/src/lower/diagnostics.rs
index a5a13d6..009f047 100644
--- a/crates/hir-ty/src/lower/diagnostics.rs
+++ b/crates/hir-ty/src/lower/diagnostics.rs
@@ -63,6 +63,24 @@
/// Whether the `GenericArgs` contains a `Self` arg.
has_self_arg: bool,
},
+ ElidedLifetimesInPath {
+ generics_source: PathGenericsSource,
+ def: GenericDefId,
+ expected_count: u32,
+ hard_error: bool,
+ },
+ /// An elided lifetimes was used (either implicitly, by not specifying lifetimes, or explicitly, by using `'_`),
+ /// but lifetime elision could not find a lifetime to replace it with.
+ ElisionFailure {
+ generics_source: PathGenericsSource,
+ def: GenericDefId,
+ expected_count: u32,
+ },
+ MissingLifetime {
+ generics_source: PathGenericsSource,
+ def: GenericDefId,
+ expected_count: u32,
+ },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs
index c89aad8..d3ca438 100644
--- a/crates/hir-ty/src/lower/path.rs
+++ b/crates/hir-ty/src/lower/path.rs
@@ -27,8 +27,8 @@
db::HirDatabase,
error_lifetime,
generics::{Generics, generics},
- lower::{GenericArgsPosition, named_associated_type_shorthand_candidates},
- to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
+ lower::{LifetimeElisionKind, named_associated_type_shorthand_candidates},
+ static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
utils::associated_type_by_name_including_super_traits,
};
@@ -52,7 +52,6 @@
current_segment_idx: usize,
/// Contains the previous segment if `current_segment_idx == segments.len()`
current_or_prev_segment: PathSegment<'a>,
- position: GenericArgsPosition,
}
impl<'a, 'b> PathLoweringContext<'a, 'b> {
@@ -61,7 +60,6 @@
ctx: &'a mut TyLoweringContext<'b>,
on_diagnostic: PathDiagnosticCallback<'a>,
path: &'a Path,
- position: GenericArgsPosition,
) -> Self {
let segments = path.segments();
let first_segment = segments.first().unwrap_or(PathSegment::MISSING);
@@ -72,7 +70,6 @@
segments,
current_segment_idx: 0,
current_or_prev_segment: first_segment,
- position,
}
}
@@ -122,6 +119,19 @@
.expect("invalid segment passed to PathLoweringContext::set_current_segment()");
}
+ #[inline]
+ fn with_lifetime_elision<T>(
+ &mut self,
+ lifetime_elision: LifetimeElisionKind,
+ f: impl FnOnce(&mut PathLoweringContext<'_, '_>) -> T,
+ ) -> T {
+ let old_lifetime_elision =
+ std::mem::replace(&mut self.ctx.lifetime_elision, lifetime_elision);
+ let result = f(self);
+ self.ctx.lifetime_elision = old_lifetime_elision;
+ result
+ }
+
pub(crate) fn lower_ty_relative_path(
&mut self,
ty: Ty,
@@ -141,22 +151,6 @@
}
}
- fn prohibit_parenthesized_generic_args(&mut self) -> bool {
- if let Some(generic_args) = self.current_or_prev_segment.args_and_bindings {
- match generic_args.parenthesized {
- GenericArgsParentheses::No => {}
- GenericArgsParentheses::ReturnTypeNotation | GenericArgsParentheses::ParenSugar => {
- let segment = self.current_segment_u32();
- self.on_diagnostic(
- PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
- );
- return true;
- }
- }
- }
- false
- }
-
// When calling this, the current segment is the resolved segment (we don't advance it yet).
pub(crate) fn lower_partly_resolved_path(
&mut self,
@@ -189,6 +183,7 @@
associated_ty.into(),
false,
None,
+ true,
);
let substitution = Substitution::from_iter(
Interner,
@@ -511,7 +506,7 @@
// generic params. It's inefficient to splice the `Substitution`s, so we may want
// that method to optionally take parent `Substitution` as we already know them at
// this point (`t.substitution`).
- let substs = self.substs_from_path_segment(associated_ty.into(), false, None);
+ let substs = self.substs_from_path_segment(associated_ty.into(), false, None, true);
let substs = Substitution::from_iter(
Interner,
@@ -539,7 +534,7 @@
TyDefId::AdtId(it) => it.into(),
TyDefId::TypeAliasId(it) => it.into(),
};
- let substs = self.substs_from_path_segment(generic_def, infer_args, None);
+ let substs = self.substs_from_path_segment(generic_def, infer_args, None, false);
self.ctx.db.ty(typeable).substitute(Interner, &substs)
}
@@ -552,6 +547,7 @@
// special-case enum variants
resolved: ValueTyDefId,
infer_args: bool,
+ lowering_assoc_type_generics: bool,
) -> Substitution {
let prev_current_segment_idx = self.current_segment_idx;
let prev_current_segment = self.current_or_prev_segment;
@@ -588,7 +584,12 @@
var.lookup(self.ctx.db).parent.into()
}
};
- let result = self.substs_from_path_segment(generic_def, infer_args, None);
+ let result = self.substs_from_path_segment(
+ generic_def,
+ infer_args,
+ None,
+ lowering_assoc_type_generics,
+ );
self.current_segment_idx = prev_current_segment_idx;
self.current_or_prev_segment = prev_current_segment;
result
@@ -599,26 +600,41 @@
def: GenericDefId,
infer_args: bool,
explicit_self_ty: Option<Ty>,
+ lowering_assoc_type_generics: bool,
) -> Substitution {
- let prohibit_parens = match def {
- GenericDefId::TraitId(trait_) => {
- // RTN is prohibited anyways if we got here.
- let is_rtn =
- self.current_or_prev_segment.args_and_bindings.is_some_and(|generics| {
- generics.parenthesized == GenericArgsParentheses::ReturnTypeNotation
- });
- let is_fn_trait = !self
- .ctx
- .db
- .trait_signature(trait_)
- .flags
- .contains(TraitFlags::RUSTC_PAREN_SUGAR);
- is_rtn || is_fn_trait
+ let mut lifetime_elision = self.ctx.lifetime_elision.clone();
+
+ if let Some(args) = self.current_or_prev_segment.args_and_bindings {
+ if args.parenthesized != GenericArgsParentheses::No {
+ let prohibit_parens = match def {
+ GenericDefId::TraitId(trait_) => {
+ // RTN is prohibited anyways if we got here.
+ let is_rtn =
+ args.parenthesized == GenericArgsParentheses::ReturnTypeNotation;
+ let is_fn_trait = self
+ .ctx
+ .db
+ .trait_signature(trait_)
+ .flags
+ .contains(TraitFlags::RUSTC_PAREN_SUGAR);
+ is_rtn || !is_fn_trait
+ }
+ _ => true,
+ };
+
+ if prohibit_parens {
+ let segment = self.current_segment_u32();
+ self.on_diagnostic(
+ PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
+ );
+
+ return TyBuilder::unknown_subst(self.ctx.db, def);
+ }
+
+ // `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
+ lifetime_elision =
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
}
- _ => true,
- };
- if prohibit_parens && self.prohibit_parenthesized_generic_args() {
- return TyBuilder::unknown_subst(self.ctx.db, def);
}
self.substs_from_args_and_bindings(
@@ -627,6 +643,8 @@
infer_args,
explicit_self_ty,
PathGenericsSource::Segment(self.current_segment_u32()),
+ lowering_assoc_type_generics,
+ lifetime_elision,
)
}
@@ -637,6 +655,8 @@
infer_args: bool,
explicit_self_ty: Option<Ty>,
generics_source: PathGenericsSource,
+ lowering_assoc_type_generics: bool,
+ lifetime_elision: LifetimeElisionKind,
) -> Substitution {
struct LowererCtx<'a, 'b, 'c> {
ctx: &'a mut PathLoweringContext<'b, 'c>,
@@ -761,6 +781,36 @@
GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
}
}
+
+ fn report_elided_lifetimes_in_path(
+ &mut self,
+ def: GenericDefId,
+ expected_count: u32,
+ hard_error: bool,
+ ) {
+ self.ctx.on_diagnostic(PathLoweringDiagnostic::ElidedLifetimesInPath {
+ generics_source: self.generics_source,
+ def,
+ expected_count,
+ hard_error,
+ });
+ }
+
+ fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32) {
+ self.ctx.on_diagnostic(PathLoweringDiagnostic::ElisionFailure {
+ generics_source: self.generics_source,
+ def,
+ expected_count,
+ });
+ }
+
+ fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32) {
+ self.ctx.on_diagnostic(PathLoweringDiagnostic::MissingLifetime {
+ generics_source: self.generics_source,
+ def,
+ expected_count,
+ });
+ }
}
substs_from_args_and_bindings(
@@ -769,7 +819,8 @@
args_and_bindings,
def,
infer_args,
- self.position,
+ lifetime_elision,
+ lowering_assoc_type_generics,
explicit_self_ty,
&mut LowererCtx { ctx: self, generics_source },
)
@@ -789,7 +840,7 @@
resolved: TraitId,
explicit_self_ty: Ty,
) -> Substitution {
- self.substs_from_path_segment(resolved.into(), false, Some(explicit_self_ty))
+ self.substs_from_path_segment(resolved.into(), false, Some(explicit_self_ty), false)
}
pub(super) fn assoc_type_bindings_from_type_bound<'c>(
@@ -807,20 +858,25 @@
None => return SmallVec::new(),
Some(t) => t,
};
- // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
- // generic params. It's inefficient to splice the `Substitution`s, so we may want
- // that method to optionally take parent `Substitution` as we already know them at
- // this point (`super_trait_ref.substitution`).
- let substitution = self.substs_from_args_and_bindings(
- binding.args.as_ref(),
- associated_ty.into(),
- false, // this is not relevant
- Some(super_trait_ref.self_type_parameter(Interner)),
- PathGenericsSource::AssocType {
- segment: self.current_segment_u32(),
- assoc_type: binding_idx as u32,
- },
- );
+ let substitution =
+ self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| {
+ // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+ // generic params. It's inefficient to splice the `Substitution`s, so we may want
+ // that method to optionally take parent `Substitution` as we already know them at
+ // this point (`super_trait_ref.substitution`).
+ this.substs_from_args_and_bindings(
+ binding.args.as_ref(),
+ associated_ty.into(),
+ false, // this is not relevant
+ Some(super_trait_ref.self_type_parameter(Interner)),
+ PathGenericsSource::AssocType {
+ segment: this.current_segment_u32(),
+ assoc_type: binding_idx as u32,
+ },
+ false,
+ this.ctx.lifetime_elision.clone(),
+ )
+ });
let substitution = Substitution::from_iter(
Interner,
super_trait_ref.substitution.iter(Interner).chain(
@@ -836,25 +892,48 @@
let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
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 alias_eq =
- AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
- predicates
- .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
+ 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()
+ } 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 alias_eq = AliasEq {
+ alias: AliasTy::Projection(projection_ty.clone()),
+ ty,
+ };
+ predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(
+ alias_eq,
+ )));
+ }
}
+ });
+ }
+
+ self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| {
+ for bound in binding.bounds.iter() {
+ predicates.extend(
+ this.ctx.lower_type_bound(
+ bound,
+ TyKind::Alias(AliasTy::Projection(projection_ty.clone()))
+ .intern(Interner),
+ false,
+ ),
+ );
}
- }
- for bound in binding.bounds.iter() {
- predicates.extend(self.ctx.lower_type_bound(
- bound,
- TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(Interner),
- false,
- ));
- }
+ });
+
predicates
})
})
@@ -868,6 +947,17 @@
}
pub(crate) trait GenericArgsLowerer {
+ fn report_elided_lifetimes_in_path(
+ &mut self,
+ def: GenericDefId,
+ expected_count: u32,
+ hard_error: bool,
+ );
+
+ fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32);
+
+ fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32);
+
fn report_len_mismatch(
&mut self,
def: GenericDefId,
@@ -905,7 +995,8 @@
def: GenericDefId,
def_generics: &Generics,
infer_args: bool,
- position: GenericArgsPosition,
+ lifetime_elision: &LifetimeElisionKind,
+ lowering_assoc_type_generics: bool,
ctx: &mut impl GenericArgsLowerer,
) -> bool {
let mut had_error = false;
@@ -921,19 +1012,37 @@
}
}
- // FIXME: Function signature lifetime elision has to be considered here once we have it
- let infer_lifetimes =
- position != GenericArgsPosition::OtherSignature && provided_lifetimes_count == 0;
-
- let max_expected_lifetime_args = def_generics.len_lifetimes_self();
- let min_expected_lifetime_args = if infer_lifetimes { 0 } else { max_expected_lifetime_args };
- if provided_lifetimes_count < min_expected_lifetime_args
- || max_expected_lifetime_args < provided_lifetimes_count
- {
+ let lifetime_args_len = def_generics.len_lifetimes_self();
+ if provided_lifetimes_count == 0 && lifetime_args_len > 0 && !lowering_assoc_type_generics {
+ // In generic associated types, we never allow inferring the lifetimes.
+ match lifetime_elision {
+ &LifetimeElisionKind::AnonymousCreateParameter { report_in_path } => {
+ ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, report_in_path);
+ had_error |= report_in_path;
+ }
+ LifetimeElisionKind::AnonymousReportError => {
+ ctx.report_missing_lifetime(def, lifetime_args_len as u32);
+ had_error = true
+ }
+ LifetimeElisionKind::ElisionFailure => {
+ ctx.report_elision_failure(def, lifetime_args_len as u32);
+ had_error = true;
+ }
+ LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
+ // FIXME: Check there are other lifetimes in scope, and error/lint.
+ }
+ LifetimeElisionKind::Elided(_) => {
+ ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, false);
+ }
+ LifetimeElisionKind::Infer => {
+ // Allow eliding lifetimes.
+ }
+ }
+ } else if lifetime_args_len != provided_lifetimes_count {
ctx.report_len_mismatch(
def,
provided_lifetimes_count as u32,
- max_expected_lifetime_args as u32,
+ lifetime_args_len as u32,
IncorrectGenericsLenKind::Lifetimes,
);
had_error = true;
@@ -974,7 +1083,8 @@
args_and_bindings: Option<&GenericArgs>,
def: GenericDefId,
mut infer_args: bool,
- position: GenericArgsPosition,
+ lifetime_elision: LifetimeElisionKind,
+ lowering_assoc_type_generics: bool,
explicit_self_ty: Option<Ty>,
ctx: &mut impl GenericArgsLowerer,
) -> Substitution {
@@ -991,8 +1101,15 @@
args_slice.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_)));
infer_args &= !has_non_lifetime_args;
- let had_count_error =
- check_generic_args_len(args_and_bindings, def, &def_generics, infer_args, position, ctx);
+ let had_count_error = check_generic_args_len(
+ args_and_bindings,
+ def,
+ &def_generics,
+ infer_args,
+ &lifetime_elision,
+ lowering_assoc_type_generics,
+ ctx,
+ );
let mut substs = Vec::with_capacity(def_generics.len());
@@ -1120,7 +1237,29 @@
(None, Some(&(param_id, param))) => {
// If there are fewer arguments than parameters, it means we're inferring the remaining arguments.
- substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs));
+ let param = if let GenericParamId::LifetimeParamId(_) = param_id {
+ match &lifetime_elision {
+ LifetimeElisionKind::ElisionFailure
+ | LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }
+ | LifetimeElisionKind::AnonymousReportError => {
+ assert!(had_count_error);
+ ctx.inferred_kind(def, param_id, param, infer_args, &substs)
+ }
+ LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
+ static_lifetime().cast(Interner)
+ }
+ LifetimeElisionKind::Elided(lifetime) => lifetime.clone().cast(Interner),
+ LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }
+ | LifetimeElisionKind::Infer => {
+ // FIXME: With `AnonymousCreateParameter`, we need to create a new lifetime parameter here
+ // (but this will probably be done in hir-def lowering instead).
+ ctx.inferred_kind(def, param_id, param, infer_args, &substs)
+ }
+ }
+ } else {
+ ctx.inferred_kind(def, param_id, param, infer_args, &substs)
+ };
+ substs.push(param);
params.next();
}
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index d8bcaa0..b6e3002 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -118,6 +118,8 @@
BadRtn,
IncorrectGenericsLen,
IncorrectGenericsOrder,
+ MissingLifetime,
+ ElidedLifetimesInPath,
];
#[derive(Debug)]
@@ -440,6 +442,23 @@
pub def: GenericDef,
}
+#[derive(Debug)]
+pub struct MissingLifetime {
+ /// Points at the name if there are no generics.
+ pub generics_or_segment: InFile<AstPtr<Either<ast::GenericArgList, ast::NameRef>>>,
+ pub expected: u32,
+ pub def: GenericDef,
+}
+
+#[derive(Debug)]
+pub struct ElidedLifetimesInPath {
+ /// Points at the name if there are no generics.
+ pub generics_or_segment: InFile<AstPtr<Either<ast::GenericArgList, ast::NameRef>>>,
+ pub expected: u32,
+ pub def: GenericDef,
+ pub hard_error: bool,
+}
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GenericArgKind {
Lifetime,
@@ -861,6 +880,31 @@
let expected_kind = GenericArgKind::from_id(param_id);
IncorrectGenericsOrder { provided_arg, expected_kind }.into()
}
+ PathLoweringDiagnostic::MissingLifetime { generics_source, expected_count, def }
+ | PathLoweringDiagnostic::ElisionFailure { generics_source, expected_count, def } => {
+ let generics_or_segment =
+ path_generics_source_to_ast(&path.value, generics_source)?;
+ let generics_or_segment = path.with_value(AstPtr::new(&generics_or_segment));
+ MissingLifetime { generics_or_segment, expected: expected_count, def: def.into() }
+ .into()
+ }
+ PathLoweringDiagnostic::ElidedLifetimesInPath {
+ generics_source,
+ expected_count,
+ def,
+ hard_error,
+ } => {
+ let generics_or_segment =
+ path_generics_source_to_ast(&path.value, generics_source)?;
+ let generics_or_segment = path.with_value(AstPtr::new(&generics_or_segment));
+ ElidedLifetimesInPath {
+ generics_or_segment,
+ expected: expected_count,
+ def: def.into(),
+ hard_error,
+ }
+ .into()
+ }
})
}
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 108c8f0..00e67fb 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -34,8 +34,8 @@
name::{AsName, Name},
};
use hir_ty::{
- Adjustment, AliasTy, InferenceResult, Interner, ProjectionTy, Substitution, TraitEnvironment,
- Ty, TyExt, TyKind, TyLoweringContext,
+ Adjustment, AliasTy, InferenceResult, Interner, LifetimeElisionKind, ProjectionTy,
+ Substitution, TraitEnvironment, Ty, TyExt, TyKind, TyLoweringContext,
diagnostics::{
InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields,
unsafe_operations,
@@ -261,11 +261,15 @@
pub(crate) fn type_of_type(&self, db: &dyn HirDatabase, ty: &ast::Type) -> Option<Type> {
let type_ref = self.type_id(ty)?;
- let ty = hir_ty::TyLoweringContext::new(
+ let ty = TyLoweringContext::new(
db,
&self.resolver,
self.store()?,
self.resolver.generic_def()?,
+ // FIXME: Is this correct here? Anyway that should impact mostly diagnostics, which we don't emit here
+ // (this can impact the lifetimes generated, e.g. in `const` they won't be `'static`, but this seems like a
+ // small problem).
+ LifetimeElisionKind::Infer,
)
.lower_ty(type_ref);
Some(Type::new_with_resolver(db, &self.resolver, ty))
@@ -1553,7 +1557,8 @@
let (ty, unresolved) = match path.type_anchor() {
Some(type_ref) => resolver.generic_def().and_then(|def| {
let (_, res) =
- TyLoweringContext::new(db, resolver, store?, def).lower_ty_ext(type_ref);
+ TyLoweringContext::new(db, resolver, store?, def, LifetimeElisionKind::Infer)
+ .lower_ty_ext(type_ref);
res.map(|ty_ns| (ty_ns, path.segments().first()))
}),
None => {
@@ -1681,7 +1686,8 @@
let (ty, unresolved) = match path.type_anchor() {
Some(type_ref) => resolver.generic_def().and_then(|def| {
let (_, res) =
- TyLoweringContext::new(db, resolver, store, def).lower_ty_ext(type_ref);
+ TyLoweringContext::new(db, resolver, store, def, LifetimeElisionKind::Infer)
+ .lower_ty_ext(type_ref);
res.map(|ty_ns| (ty_ns, path.segments().first()))
}),
None => {
diff --git a/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs b/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs
new file mode 100644
index 0000000..438dd2f
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs
@@ -0,0 +1,112 @@
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: elided-lifetimes-in-path
+//
+// This diagnostic is triggered when lifetimes are elided in paths. It is a lint only for some cases,
+// and a hard error for others.
+pub(crate) fn elided_lifetimes_in_path(
+ ctx: &DiagnosticsContext<'_>,
+ d: &hir::ElidedLifetimesInPath,
+) -> Diagnostic {
+ if d.hard_error {
+ Diagnostic::new_with_syntax_node_ptr(
+ ctx,
+ DiagnosticCode::RustcHardError("E0726"),
+ "implicit elided lifetime not allowed here",
+ d.generics_or_segment.map(Into::into),
+ )
+ .experimental()
+ } else {
+ Diagnostic::new_with_syntax_node_ptr(
+ ctx,
+ DiagnosticCode::RustcLint("elided_lifetimes_in_paths"),
+ "hidden lifetime parameters in types are deprecated",
+ d.generics_or_segment.map(Into::into),
+ )
+ .experimental()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_diagnostics;
+
+ #[test]
+ fn fn_() {
+ check_diagnostics(
+ r#"
+#![warn(elided_lifetimes_in_paths)]
+
+struct Foo<'a>(&'a ());
+
+fn foo(_: Foo) {}
+ // ^^^ warn: hidden lifetime parameters in types are deprecated
+ "#,
+ );
+ check_diagnostics(
+ r#"
+#![warn(elided_lifetimes_in_paths)]
+
+struct Foo<'a>(&'a ());
+
+fn foo(_: Foo<'_>) -> Foo { loop {} }
+ // ^^^ warn: hidden lifetime parameters in types are deprecated
+ "#,
+ );
+ }
+
+ #[test]
+ fn async_fn() {
+ check_diagnostics(
+ r#"
+struct Foo<'a>(&'a ());
+
+async fn foo(_: Foo) {}
+ // ^^^ error: implicit elided lifetime not allowed here
+ "#,
+ );
+ check_diagnostics(
+ r#"
+#![warn(elided_lifetimes_in_paths)]
+
+struct Foo<'a>(&'a ());
+
+fn foo(_: Foo<'_>) -> Foo { loop {} }
+ // ^^^ warn: hidden lifetime parameters in types are deprecated
+ "#,
+ );
+ }
+
+ #[test]
+ fn no_error_when_explicitly_elided() {
+ check_diagnostics(
+ r#"
+#![warn(elided_lifetimes_in_paths)]
+
+struct Foo<'a>(&'a ());
+trait Trait<'a> {}
+
+fn foo(_: Foo<'_>) -> Foo<'_> { loop {} }
+async fn bar(_: Foo<'_>) -> Foo<'_> { loop {} }
+impl Foo<'_> {}
+impl Trait<'_> for Foo<'_> {}
+ "#,
+ );
+ }
+
+ #[test]
+ fn impl_() {
+ check_diagnostics(
+ r#"
+struct Foo<'a>(&'a ());
+trait Trait<'a> {}
+
+impl Foo {}
+ // ^^^ error: implicit elided lifetime not allowed here
+
+impl Trait for Foo<'_> {}
+ // ^^^^^ error: implicit elided lifetime not allowed here
+ "#,
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/handlers/missing_lifetime.rs b/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
new file mode 100644
index 0000000..8cdbb63
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
@@ -0,0 +1,92 @@
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: missing-lifetime
+//
+// This diagnostic is triggered when a lifetime argument is missing.
+pub(crate) fn missing_lifetime(
+ ctx: &DiagnosticsContext<'_>,
+ d: &hir::MissingLifetime,
+) -> Diagnostic {
+ Diagnostic::new_with_syntax_node_ptr(
+ ctx,
+ DiagnosticCode::RustcHardError("E0106"),
+ "missing lifetime specifier",
+ d.generics_or_segment.map(Into::into),
+ )
+ .experimental()
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_diagnostics;
+
+ #[test]
+ fn in_fields() {
+ check_diagnostics(
+ r#"
+struct Foo<'a>(&'a ());
+struct Bar(Foo);
+ // ^^^ error: missing lifetime specifier
+ "#,
+ );
+ }
+
+ #[test]
+ fn bounds() {
+ check_diagnostics(
+ r#"
+struct Foo<'a, T>(&'a T);
+trait Trait<'a> {
+ type Assoc;
+}
+
+fn foo<'a, T: Trait>(
+ // ^^^^^ error: missing lifetime specifier
+ _: impl Trait<'a, Assoc: Trait>,
+ // ^^^^^ error: missing lifetime specifier
+)
+where
+ Foo<T>: Trait<'a>,
+ // ^^^ error: missing lifetime specifier
+{
+}
+ "#,
+ );
+ }
+
+ #[test]
+ fn generic_defaults() {
+ check_diagnostics(
+ r#"
+struct Foo<'a>(&'a ());
+
+struct Bar<T = Foo>(T);
+ // ^^^ error: missing lifetime specifier
+ "#,
+ );
+ }
+
+ #[test]
+ fn type_alias_type() {
+ check_diagnostics(
+ r#"
+struct Foo<'a>(&'a ());
+
+type Bar = Foo;
+ // ^^^ error: missing lifetime specifier
+ "#,
+ );
+ }
+
+ #[test]
+ fn const_param_ty() {
+ check_diagnostics(
+ r#"
+struct Foo<'a>(&'a ());
+
+fn bar<const F: Foo>() {}
+ // ^^^ error: missing lifetime specifier
+ "#,
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index ddaef57..11efedd 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -27,6 +27,7 @@
pub(crate) mod await_outside_of_async;
pub(crate) mod bad_rtn;
pub(crate) mod break_outside_of_loop;
+ pub(crate) mod elided_lifetimes_in_path;
pub(crate) mod expected_function;
pub(crate) mod generic_args_prohibited;
pub(crate) mod inactive_code;
@@ -40,6 +41,7 @@
pub(crate) mod malformed_derive;
pub(crate) mod mismatched_arg_count;
pub(crate) mod missing_fields;
+ pub(crate) mod missing_lifetime;
pub(crate) mod missing_match_arms;
pub(crate) mod missing_unsafe;
pub(crate) mod moved_out_of_ref;
@@ -503,6 +505,8 @@
AnyDiagnostic::BadRtn(d) => handlers::bad_rtn::bad_rtn(&ctx, &d),
AnyDiagnostic::IncorrectGenericsLen(d) => handlers::incorrect_generics_len::incorrect_generics_len(&ctx, &d),
AnyDiagnostic::IncorrectGenericsOrder(d) => handlers::incorrect_generics_order::incorrect_generics_order(&ctx, &d),
+ AnyDiagnostic::MissingLifetime(d) => handlers::missing_lifetime::missing_lifetime(&ctx, &d),
+ AnyDiagnostic::ElidedLifetimesInPath(d) => handlers::elided_lifetimes_in_path::elided_lifetimes_in_path(&ctx, &d),
};
res.push(d)
}