Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lower.rs')
-rw-r--r--crates/hir-ty/src/lower.rs172
1 files changed, 67 insertions, 105 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 57849ff913..ea42c59296 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -28,10 +28,7 @@ use hir_def::{
FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, LocalFieldId, Lookup, StaticId,
StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId,
builtin_type::BuiltinType,
- expr_store::{
- ExpressionStore,
- path::{GenericArg, Path},
- },
+ expr_store::{ExpressionStore, path::Path},
hir::generics::{
GenericParamDataRef, TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget,
},
@@ -55,9 +52,9 @@ use triomphe::{Arc, ThinArc};
use crate::{
AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig,
FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData,
- LifetimeOutlives, ParamKind, PolyFnSig, ProgramClause, QuantifiedWhereClause,
- QuantifiedWhereClauses, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder,
- TyKind, WhereClause, all_super_traits,
+ LifetimeOutlives, PolyFnSig, ProgramClause, QuantifiedWhereClause, QuantifiedWhereClauses,
+ Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
+ all_super_traits,
consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic},
db::HirDatabase,
error_lifetime,
@@ -70,6 +67,7 @@ use crate::{
mapping::{ToChalk, from_chalk_trait_id, lt_to_placeholder_idx},
static_lifetime, to_chalk_trait_id, to_placeholder_idx,
utils::all_super_trait_refs,
+ variable_kinds_from_iter,
};
#[derive(Debug, Default)]
@@ -89,6 +87,22 @@ 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,
+}
+
#[derive(Debug)]
pub struct TyLoweringContext<'a> {
pub db: &'a dyn HirDatabase,
@@ -106,6 +120,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,
}
impl<'a> TyLoweringContext<'a> {
@@ -129,6 +144,7 @@ impl<'a> TyLoweringContext<'a> {
type_param_mode,
unsized_types: FxHashSet::default(),
diagnostics: Vec::new(),
+ in_fn_signature: false,
}
}
@@ -415,6 +431,11 @@ 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
+ },
)
}
@@ -1172,22 +1193,30 @@ pub(crate) fn generic_defaults_with_diagnostics_query(
.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
- .iter_self()
- .map(|(id, p)| {
- let result = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
+ .iter_parents_with_store()
+ .map(|((id, p), store)| {
+ ctx.store = store;
+ let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
+ has_any_default |= has_default;
idx += 1;
result
})
.collect::<Vec<_>>();
- let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics));
- defaults.extend(generic_params.iter_parents_with_store().map(|((id, p), store)| {
- ctx.store = store;
- let result = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
+ ctx.diagnostics.clear(); // Don't include diagnostics from the parent.
+ defaults.extend(generic_params.iter_self().map(|(id, p)| {
+ let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
+ has_any_default |= has_default;
idx += 1;
result
}));
- let defaults = GenericDefaults(Some(Arc::from_iter(defaults)));
+ let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics));
+ let defaults = if has_any_default {
+ GenericDefaults(Some(Arc::from_iter(defaults)))
+ } else {
+ GenericDefaults(None)
+ };
return (defaults, diagnostics);
fn handle_generic_param(
@@ -1196,16 +1225,20 @@ pub(crate) fn generic_defaults_with_diagnostics_query(
id: GenericParamId,
p: GenericParamDataRef<'_>,
generic_params: &Generics,
- ) -> Binders<crate::GenericArg> {
+ ) -> (Binders<crate::GenericArg>, bool) {
+ let binders = variable_kinds_from_iter(ctx.db, generic_params.iter_id().take(idx));
match p {
GenericParamDataRef::TypeParamData(p) => {
- let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| {
- // Each default can only refer to previous parameters.
- // Type variable default referring to parameter coming
- // after it is forbidden (FIXME: report diagnostic)
- fallback_bound_vars(ctx.lower_ty(*ty), idx, 0)
- });
- crate::make_binders(ctx.db, generic_params, ty.cast(Interner))
+ let ty = p.default.as_ref().map_or_else(
+ || TyKind::Error.intern(Interner),
+ |ty| {
+ // Each default can only refer to previous parameters.
+ // Type variable default referring to parameter coming
+ // after it is forbidden (FIXME: report diagnostic)
+ fallback_bound_vars(ctx.lower_ty(*ty), idx)
+ },
+ );
+ (Binders::new(binders, ty.cast(Interner)), p.default.is_some())
}
GenericParamDataRef::ConstParamData(p) => {
let GenericParamId::ConstParamId(id) = id else {
@@ -1221,36 +1254,22 @@ pub(crate) fn generic_defaults_with_diagnostics_query(
},
);
// Each default can only refer to previous parameters, see above.
- val = fallback_bound_vars(val, idx, 0);
- make_binders(ctx.db, generic_params, val)
+ val = fallback_bound_vars(val, idx);
+ (Binders::new(binders, val), p.default.is_some())
}
GenericParamDataRef::LifetimeParamData(_) => {
- make_binders(ctx.db, generic_params, error_lifetime().cast(Interner))
+ (Binders::new(binders, error_lifetime().cast(Interner)), false)
}
}
}
}
pub(crate) fn generic_defaults_with_diagnostics_recover(
- db: &dyn HirDatabase,
+ _db: &dyn HirDatabase,
_cycle: &Cycle,
- def: GenericDefId,
+ _def: GenericDefId,
) -> (GenericDefaults, Diagnostics) {
- let generic_params = generics(db, def);
- if generic_params.len() == 0 {
- return (GenericDefaults(None), None);
- }
- // FIXME: this code is not covered in tests.
- // we still need one default per parameter
- let defaults = GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| {
- let val = match id {
- GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
- GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)),
- GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
- };
- crate::make_binders(db, &generic_params, val)
- }))));
- (defaults, None)
+ (GenericDefaults(None), None)
}
fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
@@ -1258,6 +1277,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
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 params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
let ret = match data.ret_type {
@@ -1265,6 +1285,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
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;
ctx_ret.lower_ty(ret_type)
}
None => TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
@@ -1612,73 +1633,14 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut
}
}
-/// Checks if the provided generic arg matches its expected kind, then lower them via
-/// provided closures. Use unknown if there was kind mismatch.
-///
-pub(crate) fn generic_arg_to_chalk<'a, T>(
- db: &dyn HirDatabase,
- kind_id: GenericParamId,
- arg: &'a GenericArg,
- this: &mut T,
- store: &ExpressionStore,
- for_type: impl FnOnce(&mut T, TypeRefId) -> Ty + 'a,
- for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a,
- for_const_ty_path_fallback: impl FnOnce(&mut T, &Path, Ty) -> Const + 'a,
- for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a,
-) -> crate::GenericArg {
- let kind = match kind_id {
- GenericParamId::TypeParamId(_) => ParamKind::Type,
- GenericParamId::ConstParamId(id) => {
- let ty = db.const_param_ty(id);
- ParamKind::Const(ty)
- }
- GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
- };
- match (arg, kind) {
- (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, *type_ref).cast(Interner),
- (GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner),
- (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => {
- for_lifetime(this, lifetime_ref).cast(Interner)
- }
- (GenericArg::Const(_), ParamKind::Type) => TyKind::Error.intern(Interner).cast(Interner),
- (GenericArg::Lifetime(_), ParamKind::Type) => TyKind::Error.intern(Interner).cast(Interner),
- (GenericArg::Type(t), ParamKind::Const(c_ty)) => match &store[*t] {
- TypeRef::Path(p) => for_const_ty_path_fallback(this, p, c_ty).cast(Interner),
- _ => unknown_const_as_generic(c_ty),
- },
- (GenericArg::Lifetime(_), ParamKind::Const(c_ty)) => unknown_const_as_generic(c_ty),
- (GenericArg::Type(_), ParamKind::Lifetime) => error_lifetime().cast(Interner),
- (GenericArg::Const(_), ParamKind::Lifetime) => error_lifetime().cast(Interner),
- }
-}
-
/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic
-/// parameter whose index is `param_index`. A `BoundVar` is free when it is or (syntactically)
-/// appears after the generic parameter of `param_index`.
+/// parameter whose index is `param_index`. A `BoundVar` is free when it appears after the
+/// generic parameter of `param_index`.
fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
s: T,
param_index: usize,
- parent_start: usize,
) -> T {
- // Keep in mind that parent generic parameters, if any, come *after* those of the item in
- // question. In the diagrams below, `c*` and `p*` represent generic parameters of the item and
- // its parent respectively.
- let is_allowed = |index| {
- if param_index < parent_start {
- // The parameter of `param_index` is one from the item in question. Any parent generic
- // parameters or the item's generic parameters that come before `param_index` is
- // allowed.
- // [c1, .., cj, .., ck, p1, .., pl] where cj is `param_index`
- // ^^^^^^ ^^^^^^^^^^ these are allowed
- !(param_index..parent_start).contains(&index)
- } else {
- // The parameter of `param_index` is one from the parent generics. Only parent generic
- // parameters that come before `param_index` are allowed.
- // [c1, .., ck, p1, .., pj, .., pl] where pj is `param_index`
- // ^^^^^^ these are allowed
- (parent_start..param_index).contains(&index)
- }
- };
+ let is_allowed = |index| (0..param_index).contains(&index);
crate::fold_free_vars(
s,