mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 11:20:54 +00:00
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.
This commit is contained in:
parent
3d00e247dd
commit
adcf699ea3
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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(),
|
||||
};
|
||||
|
@ -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]
|
||||
|
@ -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 },
|
||||
)
|
||||
|
@ -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()?;
|
||||
|
@ -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 }
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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,
|
||||
)));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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) 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();
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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 => {
|
||||
|
112
crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs
Normal file
112
crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs
Normal file
@ -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
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
92
crates/ide-diagnostics/src/handlers/missing_lifetime.rs
Normal file
92
crates/ide-diagnostics/src/handlers/missing_lifetime.rs
Normal file
@ -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
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user