Unnamed repository; edit this file 'description' to name the repository.
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.
| -rw-r--r-- | crates/hir-def/src/hir/type_ref.rs | 8 | ||||
| -rw-r--r-- | crates/hir-ty/src/chalk_db.rs | 12 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 111 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/closure.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/diagnostics.rs | 15 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/expr.rs | 22 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/path.rs | 11 | ||||
| -rw-r--r-- | crates/hir-ty/src/lib.rs | 8 | ||||
| -rw-r--r-- | crates/hir-ty/src/lower.rs | 292 | ||||
| -rw-r--r-- | crates/hir-ty/src/lower/diagnostics.rs | 18 | ||||
| -rw-r--r-- | crates/hir-ty/src/lower/path.rs | 317 | ||||
| -rw-r--r-- | crates/hir/src/diagnostics.rs | 44 | ||||
| -rw-r--r-- | crates/hir/src/source_analyzer.rs | 16 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs | 112 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/missing_lifetime.rs | 92 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/lib.rs | 4 |
16 files changed, 858 insertions, 226 deletions
diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs index 1fd878ab9b..6b7f03ec00 100644 --- a/crates/hir-def/src/hir/type_ref.rs +++ b/crates/hir-def/src/hir/type_ref.rs @@ -106,6 +106,14 @@ pub struct FnType { 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 bf16e08c37..2aa9401eef 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -27,6 +27,7 @@ use crate::{ 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 @@ pub(crate) fn associated_ty_data_query( 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 cad2e3ce99..38807b6f72 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -34,8 +34,8 @@ use chalk_ir::{ }; 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 @@ use crate::{ 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 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer 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 @@ impl<'a> InferenceContext<'a> { 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 @@ impl<'a> InferenceContext<'a> { } 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 @@ impl<'a> InferenceContext<'a> { 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 @@ impl<'a> InferenceContext<'a> { 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 @@ impl<'a> InferenceContext<'a> { &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 @@ impl<'a> InferenceContext<'a> { &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 @@ impl<'a> InferenceContext<'a> { 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 @@ impl<'a> InferenceContext<'a> { } 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 @@ impl<'a> InferenceContext<'a> { &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 @@ impl<'a> InferenceContext<'a> { 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 @@ impl<'a> InferenceContext<'a> { }; 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 @@ impl<'a> InferenceContext<'a> { 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 59ec3adcc4..e7b776a356 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -440,6 +440,8 @@ impl InferenceContext<'_> { // 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 2c633a03c5..e3c4f5562d 100644 --- a/crates/hir-ty/src/infer/diagnostics.rs +++ b/crates/hir-ty/src/infer/diagnostics.rs @@ -12,7 +12,7 @@ use hir_def::expr_store::path::Path; 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 @@ impl<'a> InferenceTyLoweringContext<'a> { 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 @@ impl<'a> InferenceTyLoweringContext<'a> { &'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 @@ impl<'a> InferenceTyLoweringContext<'a> { .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 @@ impl<'a> InferenceTyLoweringContext<'a> { }), 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 2980549c23..643587e8af 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -37,7 +37,7 @@ use crate::{ }, 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 @@ impl InferenceContext<'_> { } } } + + 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 @@ impl InferenceContext<'_> { 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 0e1d23b694..bdaec615ac 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -16,7 +16,7 @@ use crate::{ 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 @@ impl InferenceContext<'_> { }; 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 @@ impl InferenceContext<'_> { &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 2cb977b634..128569d55d 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -94,8 +94,8 @@ pub use infer::{ }; 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 @@ pub type PolyFnSig = Binders<CallableSig>; 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 073a584d8d..eecca32240 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -25,8 +25,8 @@ use chalk_ir::{ 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 @@ use hir_def::{ 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 @@ impl ImplTraitLoweringState { 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 @@ pub struct TyLoweringContext<'a> { /// 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 @@ impl<'a> TyLoweringContext<'a> { 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 @@ impl<'a> TyLoweringContext<'a> { type_param_mode, unsized_types: FxHashSet::default(), diagnostics: Vec::new(), - in_fn_signature: false, + lifetime_elision, } } @@ -167,6 +217,17 @@ impl<'a> TyLoweringContext<'a> { 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 @@ impl<'a> TyLoweringContext<'a> { 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 @@ impl<'a> TyLoweringContext<'a> { 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 @@ pub(crate) fn field_types_with_diagnostics_query( }; 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 @@ pub(crate) fn generic_predicates_for_param_query( ) -> 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 @@ pub(crate) fn trait_environment_query( ) -> 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 @@ where { 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 @@ pub(crate) fn generic_defaults_with_diagnostics_query( } 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 @@ pub(crate) fn generic_defaults_with_diagnostics_cycle_result( 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 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> { 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_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> { 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 type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Option<Bi } 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 @@ pub(crate) fn type_for_type_alias_with_diagnostics_query( } 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 @@ pub(crate) fn impl_self_ty_with_diagnostics_query( 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 @@ pub(crate) fn const_param_ty_with_diagnostics_query( 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 @@ pub(crate) fn impl_trait_with_diagnostics_query( ) -> 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 @@ pub(crate) fn return_type_impl_traits( // 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 @@ pub(crate) fn type_alias_impl_traits( ) -> 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 a5a13d64e0..009f047109 100644 --- a/crates/hir-ty/src/lower/diagnostics.rs +++ b/crates/hir-ty/src/lower/diagnostics.rs @@ -63,6 +63,24 @@ pub enum PathLoweringDiagnostic { /// 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 c89aad87f7..d3ca438d6e 100644 --- a/crates/hir-ty/src/lower/path.rs +++ b/crates/hir-ty/src/lower/path.rs @@ -27,8 +27,8 @@ use crate::{ 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 @@ pub(crate) struct PathLoweringContext<'a, 'b> { 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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { 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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { segments, current_segment_idx: 0, current_or_prev_segment: first_segment, - position, } } @@ -122,6 +119,19 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { .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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { } } - 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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { associated_ty.into(), false, None, + true, ); let substitution = Substitution::from_iter( Interner, @@ -511,7 +506,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { // 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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { 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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { // 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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { 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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { 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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { infer_args, explicit_self_ty, PathGenericsSource::Segment(self.current_segment_u32()), + lowering_assoc_type_generics, + lifetime_elision, ) } @@ -637,6 +655,8 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { 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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { 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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { 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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { 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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { 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 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { 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, + ))); + } } - } - } - for bound in binding.bounds.iter() { - predicates.extend(self.ctx.lower_type_bound( - bound, - TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(Interner), - false, - )); + }); } + + 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, + ), + ); + } + }); + predicates }) }) @@ -868,6 +947,17 @@ pub(crate) enum TypeLikeConst<'a> { } 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 @@ fn check_generic_args_len( 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 @@ fn check_generic_args_len( } } - // 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 @@ pub(crate) fn substs_from_args_and_bindings( 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 @@ pub(crate) fn substs_from_args_and_bindings( 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 @@ pub(crate) fn substs_from_args_and_bindings( (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 d8bcaa0e74..b6e3002ed5 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -118,6 +118,8 @@ diagnostics![ BadRtn, IncorrectGenericsLen, IncorrectGenericsOrder, + MissingLifetime, + ElidedLifetimesInPath, ]; #[derive(Debug)] @@ -440,6 +442,23 @@ pub struct IncorrectGenericsLen { 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 @@ impl AnyDiagnostic { 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 108c8f0e18..00e67fbd74 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -34,8 +34,8 @@ use hir_expand::{ 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 @@ impl SourceAnalyzer { 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 @@ fn resolve_hir_path_( 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 @@ fn resolve_hir_path_qualifier( 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 0000000000..438dd2fdcb --- /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 0000000000..8cdbb6384f --- /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 ddaef57b53..11efedd8a5 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -27,6 +27,7 @@ mod handlers { 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 @@ mod handlers { 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 @@ pub fn semantic_diagnostics( 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) } |