Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/generics.rs5
-rw-r--r--crates/hir-ty/src/db.rs30
-rw-r--r--crates/hir-ty/src/generics.rs16
-rw-r--r--crates/hir-ty/src/lib.rs3
-rw-r--r--crates/hir-ty/src/lower.rs213
-rw-r--r--crates/hir/src/diagnostics.rs59
-rw-r--r--crates/hir/src/lib.rs198
-rw-r--r--crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs200
8 files changed, 621 insertions, 103 deletions
diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs
index fdcb10e998..7b3f1d06d2 100644
--- a/crates/hir-def/src/generics.rs
+++ b/crates/hir-def/src/generics.rs
@@ -225,6 +225,11 @@ impl GenericParams {
}
#[inline]
+ pub fn no_predicates(&self) -> bool {
+ self.where_predicates.is_empty()
+ }
+
+ #[inline]
pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> {
self.where_predicates.iter()
}
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 3a3a05c369..6856eaa3e0 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -22,7 +22,7 @@ use crate::{
consteval::ConstEvalError,
dyn_compatibility::DynCompatibilityViolation,
layout::{Layout, LayoutError},
- lower::{GenericDefaults, GenericPredicates},
+ lower::{Diagnostics, GenericDefaults, GenericPredicates},
method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
mir::{BorrowckResult, MirBody, MirLowerError},
Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner,
@@ -115,21 +115,35 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[ra_salsa::cycle(crate::lower::ty_recover)]
fn ty(&self, def: TyDefId) -> Binders<Ty>;
+ #[ra_salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)]
+ fn type_for_type_alias_with_diagnostics(&self, def: TypeAliasId) -> (Binders<Ty>, Diagnostics);
+
/// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is
/// a `StructId` or `EnumVariantId` with a record constructor.
#[ra_salsa::invoke(crate::lower::value_ty_query)]
fn value_ty(&self, def: ValueTyDefId) -> Option<Binders<Ty>>;
+ #[ra_salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)]
+ #[ra_salsa::cycle(crate::lower::impl_self_ty_with_diagnostics_recover)]
+ fn impl_self_ty_with_diagnostics(&self, def: ImplId) -> (Binders<Ty>, Diagnostics);
#[ra_salsa::invoke(crate::lower::impl_self_ty_query)]
- #[ra_salsa::cycle(crate::lower::impl_self_ty_recover)]
fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
+ #[ra_salsa::invoke(crate::lower::const_param_ty_with_diagnostics_query)]
+ fn const_param_ty_with_diagnostics(&self, def: ConstParamId) -> (Ty, Diagnostics);
#[ra_salsa::invoke(crate::lower::const_param_ty_query)]
fn const_param_ty(&self, def: ConstParamId) -> Ty;
+ #[ra_salsa::invoke(crate::lower::impl_trait_with_diagnostics_query)]
+ fn impl_trait_with_diagnostics(&self, def: ImplId) -> Option<(Binders<TraitRef>, Diagnostics)>;
#[ra_salsa::invoke(crate::lower::impl_trait_query)]
fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
+ #[ra_salsa::invoke(crate::lower::field_types_with_diagnostics_query)]
+ fn field_types_with_diagnostics(
+ &self,
+ var: VariantId,
+ ) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics);
#[ra_salsa::invoke(crate::lower::field_types_query)]
fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;
@@ -154,6 +168,11 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[ra_salsa::invoke(crate::lower::generic_predicates_query)]
fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates;
+ #[ra_salsa::invoke(crate::lower::generic_predicates_without_parent_with_diagnostics_query)]
+ fn generic_predicates_without_parent_with_diagnostics(
+ &self,
+ def: GenericDefId,
+ ) -> (GenericPredicates, Diagnostics);
#[ra_salsa::invoke(crate::lower::generic_predicates_without_parent_query)]
fn generic_predicates_without_parent(&self, def: GenericDefId) -> GenericPredicates;
@@ -164,8 +183,13 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[ra_salsa::invoke(crate::lower::trait_environment_query)]
fn trait_environment(&self, def: GenericDefId) -> Arc<TraitEnvironment>;
+ #[ra_salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)]
+ #[ra_salsa::cycle(crate::lower::generic_defaults_with_diagnostics_recover)]
+ fn generic_defaults_with_diagnostics(
+ &self,
+ def: GenericDefId,
+ ) -> (GenericDefaults, Diagnostics);
#[ra_salsa::invoke(crate::lower::generic_defaults_query)]
- #[ra_salsa::cycle(crate::lower::generic_defaults_recover)]
fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults;
#[ra_salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs
index c094bc3951..fe7541d237 100644
--- a/crates/hir-ty/src/generics.rs
+++ b/crates/hir-ty/src/generics.rs
@@ -55,6 +55,10 @@ impl Generics {
self.def
}
+ pub(crate) fn self_types_map(&self) -> &TypesMap {
+ &self.params.types_map
+ }
+
pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
self.iter_self_id().chain(self.iter_parent_id())
}
@@ -86,15 +90,13 @@ impl Generics {
self.iter_self().chain(self.iter_parent())
}
- pub(crate) fn iter_with_types_map(
+ pub(crate) fn iter_parents_with_types_map(
&self,
) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &TypesMap)> + '_ {
- self.iter_self().zip(std::iter::repeat(&self.params.types_map)).chain(
- self.iter_parent().zip(
- self.parent_generics()
- .into_iter()
- .flat_map(|it| std::iter::repeat(&it.params.types_map)),
- ),
+ self.iter_parent().zip(
+ self.parent_generics()
+ .into_iter()
+ .flat_map(|it| std::iter::repeat(&it.params.types_map)),
)
}
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 77ae295cee..8bb90ca31e 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -90,7 +90,8 @@ pub use infer::{
pub use interner::Interner;
pub use lower::{
associated_type_shorthand_candidates, GenericArgsProhibitedReason, ImplTraitLoweringMode,
- ParamLoweringMode, TyDefId, TyLoweringContext, TyLoweringDiagnosticKind, ValueTyDefId,
+ ParamLoweringMode, TyDefId, TyLoweringContext, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
+ ValueTyDefId,
};
pub use mapping::{
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index b73967be71..b23f2749ab 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -48,7 +48,7 @@ use rustc_pattern_analysis::Captures;
use smallvec::SmallVec;
use stdx::{impl_from, never};
use syntax::ast;
-use triomphe::Arc;
+use triomphe::{Arc, ThinArc};
use crate::{
all_super_traits,
@@ -1652,11 +1652,24 @@ fn named_associated_type_shorthand_candidates<R>(
}
}
-/// Build the type of all specific fields of a struct or enum variant.
+pub(crate) type Diagnostics = Option<ThinArc<(), TyLoweringDiagnostic>>;
+
+fn create_diagnostics(diagnostics: Vec<TyLoweringDiagnostic>) -> Diagnostics {
+ (!diagnostics.is_empty()).then(|| ThinArc::from_header_and_iter((), diagnostics.into_iter()))
+}
+
pub(crate) fn field_types_query(
db: &dyn HirDatabase,
variant_id: VariantId,
) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> {
+ db.field_types_with_diagnostics(variant_id).0
+}
+
+/// Build the type of all specific fields of a struct or enum variant.
+pub(crate) fn field_types_with_diagnostics_query(
+ db: &dyn HirDatabase,
+ variant_id: VariantId,
+) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics) {
let var_data = variant_id.variant_data(db.upcast());
let (resolver, def): (_, GenericDefId) = match variant_id {
VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()),
@@ -1672,7 +1685,7 @@ pub(crate) fn field_types_query(
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)));
}
- Arc::new(res)
+ (Arc::new(res), create_diagnostics(ctx.diagnostics))
}
/// This query exists only to be used when resolving short-hand associated types
@@ -1873,15 +1886,22 @@ pub(crate) fn generic_predicates_query(
db: &dyn HirDatabase,
def: GenericDefId,
) -> GenericPredicates {
- generic_predicates_filtered_by(db, def, |_, _| true)
+ generic_predicates_filtered_by(db, def, |_, _| true).0
}
-/// Resolve the where clause(s) of an item with generics,
-/// except the ones inherited from the parent
pub(crate) fn generic_predicates_without_parent_query(
db: &dyn HirDatabase,
def: GenericDefId,
) -> GenericPredicates {
+ db.generic_predicates_without_parent_with_diagnostics(def).0
+}
+
+/// Resolve the where clause(s) of an item with generics,
+/// except the ones inherited from the parent
+pub(crate) fn generic_predicates_without_parent_with_diagnostics_query(
+ db: &dyn HirDatabase,
+ def: GenericDefId,
+) -> (GenericPredicates, Diagnostics) {
generic_predicates_filtered_by(db, def, |_, d| *d == def)
}
@@ -1891,7 +1911,7 @@ fn generic_predicates_filtered_by<F>(
db: &dyn HirDatabase,
def: GenericDefId,
filter: F,
-) -> GenericPredicates
+) -> (GenericPredicates, Diagnostics)
where
F: Fn(&WherePredicate, &GenericDefId) -> bool,
{
@@ -1932,7 +1952,10 @@ where
);
};
}
- GenericPredicates(predicates.is_empty().not().then(|| predicates.into()))
+ (
+ GenericPredicates(predicates.is_empty().not().then(|| predicates.into())),
+ create_diagnostics(ctx.diagnostics),
+ )
}
/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
@@ -1985,75 +2008,110 @@ impl ops::Deref for GenericDefaults {
}
}
-/// Resolve the default type params from generics
pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults {
+ db.generic_defaults_with_diagnostics(def).0
+}
+
+/// Resolve the default type params from generics.
+///
+/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents).
+pub(crate) fn generic_defaults_with_diagnostics_query(
+ db: &dyn HirDatabase,
+ def: GenericDefId,
+) -> (GenericDefaults, Diagnostics) {
let generic_params = generics(db.upcast(), def);
if generic_params.len() == 0 {
- return GenericDefaults(None);
+ return (GenericDefaults(None), None);
}
let resolver = def.resolver(db.upcast());
let parent_start_idx = generic_params.len_self();
- let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
- .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
- .with_type_param_mode(ParamLoweringMode::Variable);
- GenericDefaults(Some(Arc::from_iter(generic_params.iter_with_types_map().enumerate().map(
- |(idx, ((id, p), types_map))| {
- ctx.types_map = types_map;
- 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, parent_start_idx)
- });
- crate::make_binders(db, &generic_params, ty.cast(Interner))
- }
- GenericParamDataRef::ConstParamData(p) => {
- let GenericParamId::ConstParamId(id) = id else {
- unreachable!("Unexpected lifetime or type argument")
- };
+ let mut ctx =
+ TyLoweringContext::new(db, &resolver, generic_params.self_types_map(), def.into())
+ .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
+ .with_type_param_mode(ParamLoweringMode::Variable);
+ let mut idx = 0;
+ let mut defaults = generic_params
+ .iter_self()
+ .map(|(id, p)| {
+ let result =
+ handle_generic_param(&mut ctx, idx, id, p, parent_start_idx, &generic_params);
+ idx += 1;
+ result
+ })
+ .collect::<Vec<_>>();
+ let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics));
+ defaults.extend(generic_params.iter_parents_with_types_map().map(|((id, p), types_map)| {
+ ctx.types_map = types_map;
+ let result = handle_generic_param(&mut ctx, idx, id, p, parent_start_idx, &generic_params);
+ idx += 1;
+ result
+ }));
+ let defaults = GenericDefaults(Some(Arc::from_iter(defaults)));
+ return (defaults, diagnostics);
+
+ fn handle_generic_param(
+ ctx: &mut TyLoweringContext<'_>,
+ idx: usize,
+ id: GenericParamId,
+ p: GenericParamDataRef<'_>,
+ parent_start_idx: usize,
+ generic_params: &Generics,
+ ) -> Binders<crate::GenericArg> {
+ 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, parent_start_idx)
+ });
+ crate::make_binders(ctx.db, generic_params, ty.cast(Interner))
+ }
+ GenericParamDataRef::ConstParamData(p) => {
+ let GenericParamId::ConstParamId(id) = id else {
+ unreachable!("Unexpected lifetime or type argument")
+ };
- let mut val = p.default.as_ref().map_or_else(
- || unknown_const_as_generic(db.const_param_ty(id)),
- |c| {
- let param_ty = ctx.lower_ty(p.ty);
- let c = ctx.lower_const(c, param_ty);
- c.cast(Interner)
- },
- );
- // Each default can only refer to previous parameters, see above.
- val = fallback_bound_vars(val, idx, parent_start_idx);
- make_binders(db, &generic_params, val)
- }
- GenericParamDataRef::LifetimeParamData(_) => {
- make_binders(db, &generic_params, error_lifetime().cast(Interner))
- }
+ let mut val = p.default.as_ref().map_or_else(
+ || unknown_const_as_generic(ctx.db.const_param_ty(id)),
+ |c| {
+ let param_ty = ctx.lower_ty(p.ty);
+ let c = ctx.lower_const(c, param_ty);
+ c.cast(Interner)
+ },
+ );
+ // Each default can only refer to previous parameters, see above.
+ val = fallback_bound_vars(val, idx, parent_start_idx);
+ make_binders(ctx.db, generic_params, val)
}
- },
- ))))
+ GenericParamDataRef::LifetimeParamData(_) => {
+ make_binders(ctx.db, generic_params, error_lifetime().cast(Interner))
+ }
+ }
+ }
}
-pub(crate) fn generic_defaults_recover(
+pub(crate) fn generic_defaults_with_diagnostics_recover(
db: &dyn HirDatabase,
_cycle: &Cycle,
def: &GenericDefId,
-) -> GenericDefaults {
+) -> (GenericDefaults, Diagnostics) {
let generic_params = generics(db.upcast(), *def);
if generic_params.len() == 0 {
- return GenericDefaults(None);
+ return (GenericDefaults(None), None);
}
// FIXME: this code is not covered in tests.
// we still need one default per parameter
- GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| {
+ 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)
}
fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
@@ -2196,7 +2254,10 @@ fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
make_binders(db, &generics, ty)
}
-fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
+pub(crate) fn type_for_type_alias_with_diagnostics_query(
+ db: &dyn HirDatabase,
+ t: TypeAliasId,
+) -> (Binders<Ty>, Diagnostics) {
let generics = generics(db.upcast(), t.into());
let resolver = t.resolver(db.upcast());
let type_alias_data = db.type_alias_data(t);
@@ -2211,7 +2272,7 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
.map(|type_ref| ctx.lower_ty(type_ref))
.unwrap_or_else(|| TyKind::Error.intern(Interner))
};
- make_binders(db, &generics, inner)
+ (make_binders(db, &generics, inner), create_diagnostics(ctx.diagnostics))
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -2254,7 +2315,7 @@ pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> {
match def {
TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)),
TyDefId::AdtId(it) => type_for_adt(db, it),
- TyDefId::TypeAliasId(it) => type_for_type_alias(db, it),
+ TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0,
}
}
@@ -2279,47 +2340,73 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Option<
}
pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders<Ty> {
+ db.impl_self_ty_with_diagnostics(impl_id).0
+}
+
+pub(crate) fn impl_self_ty_with_diagnostics_query(
+ db: &dyn HirDatabase,
+ impl_id: ImplId,
+) -> (Binders<Ty>, Diagnostics) {
let impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast());
let generics = generics(db.upcast(), impl_id.into());
let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
.with_type_param_mode(ParamLoweringMode::Variable);
- make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty))
+ (
+ make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)),
+ create_diagnostics(ctx.diagnostics),
+ )
}
-// returns None if def is a type arg
pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
+ db.const_param_ty_with_diagnostics(def).0
+}
+
+// returns None if def is a type arg
+pub(crate) fn const_param_ty_with_diagnostics_query(
+ db: &dyn HirDatabase,
+ def: ConstParamId,
+) -> (Ty, Diagnostics) {
let parent_data = db.generic_params(def.parent());
let data = &parent_data[def.local_id()];
let resolver = def.parent().resolver(db.upcast());
let mut ctx =
TyLoweringContext::new(db, &resolver, &parent_data.types_map, def.parent().into());
- match data {
+ let ty = match data {
TypeOrConstParamData::TypeParamData(_) => {
never!();
Ty::new(Interner, TyKind::Error)
}
TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty),
- }
+ };
+ (ty, create_diagnostics(ctx.diagnostics))
}
-pub(crate) fn impl_self_ty_recover(
+pub(crate) fn impl_self_ty_with_diagnostics_recover(
db: &dyn HirDatabase,
_cycle: &Cycle,
impl_id: &ImplId,
-) -> Binders<Ty> {
+) -> (Binders<Ty>, Diagnostics) {
let generics = generics(db.upcast(), (*impl_id).into());
- make_binders(db, &generics, TyKind::Error.intern(Interner))
+ (make_binders(db, &generics, TyKind::Error.intern(Interner)), None)
}
pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
+ db.impl_trait_with_diagnostics(impl_id).map(|it| it.0)
+}
+
+pub(crate) fn impl_trait_with_diagnostics_query(
+ db: &dyn HirDatabase,
+ impl_id: ImplId,
+) -> Option<(Binders<TraitRef>, Diagnostics)> {
let impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast());
let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
.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()?;
- Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?))
+ let trait_ref = Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?);
+ Some((trait_ref, create_diagnostics(ctx.diagnostics)))
}
pub(crate) fn return_type_impl_traits(
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 3657cf5e16..612c6adb20 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -15,7 +15,8 @@ use hir_expand::{name::Name, HirFileId, InFile};
use hir_ty::{
db::HirDatabase,
diagnostics::{BodyValidationDiagnostic, UnsafetyReason},
- CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnosticKind,
+ CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic,
+ TyLoweringDiagnosticKind,
};
use syntax::{
ast::{self, HasGenericArgs},
@@ -402,7 +403,7 @@ pub struct InvalidCast {
#[derive(Debug)]
pub struct GenericArgsProhibited {
- pub args: InFile<AstPtr<Either<ast::GenericArgList, ast::ParamList>>>,
+ pub args: InFile<AstPtr<Either<ast::GenericArgList, ast::ParenthesizedArgList>>>,
pub reason: GenericArgsProhibitedReason,
}
@@ -664,30 +665,38 @@ impl AnyDiagnostic {
InferenceTyDiagnosticSource::Body => &source_map.types,
InferenceTyDiagnosticSource::Signature => outer_types_source_map,
};
- let source = match diag.source {
- Either::Left(type_ref_id) => {
- let Ok(source) = source_map.type_syntax(type_ref_id) else {
- stdx::never!("error on synthetic type syntax");
- return None;
- };
- source
- }
- Either::Right(source) => source,
+ Self::ty_diagnostic(diag, source_map, db)?
+ }
+ })
+ }
+
+ pub(crate) fn ty_diagnostic(
+ diag: &TyLoweringDiagnostic,
+ source_map: &TypesSourceMap,
+ db: &dyn HirDatabase,
+ ) -> Option<AnyDiagnostic> {
+ let source = match diag.source {
+ Either::Left(type_ref_id) => {
+ let Ok(source) = source_map.type_syntax(type_ref_id) else {
+ stdx::never!("error on synthetic type syntax");
+ return None;
};
- let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id));
- match diag.kind {
- TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => {
- let ast::Type::PathType(syntax) = syntax() else { return None };
- let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?;
- let args = if let Some(generics) = segment.generic_arg_list() {
- AstPtr::new(&generics).wrap_left()
- } else {
- AstPtr::new(&segment.param_list()?).wrap_right()
- };
- let args = source.with_value(args);
- GenericArgsProhibited { args, reason }.into()
- }
- }
+ source
+ }
+ Either::Right(source) => source,
+ };
+ let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id));
+ Some(match diag.kind {
+ TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => {
+ let ast::Type::PathType(syntax) = syntax() else { return None };
+ let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?;
+ let args = if let Some(generics) = segment.generic_arg_list() {
+ AstPtr::new(&generics).wrap_left()
+ } else {
+ AstPtr::new(&segment.parenthesized_arg_list()?).wrap_right()
+ };
+ let args = source.with_value(args);
+ GenericArgsProhibited { args, reason }.into()
}
})
}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index cd46276747..10365ba002 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -76,8 +76,8 @@ use hir_ty::{
traits::FnTrait,
AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
- TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId,
- WhereClause,
+ TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyLoweringDiagnostic,
+ ValueTyDefId, WhereClause,
};
use itertools::Itertools;
use nameres::diagnostics::DefDiagnosticKind;
@@ -89,7 +89,7 @@ use syntax::{
ast::{self, HasAttrs as _, HasGenericParams, HasName},
format_smolstr, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ToSmolStr, T,
};
-use triomphe::Arc;
+use triomphe::{Arc, ThinArc};
use crate::db::{DefDatabase, HirDatabase};
@@ -411,6 +411,10 @@ impl ModuleDef {
}
}
+ if let Some(def) = self.as_self_generic_def() {
+ def.diagnostics(db, &mut acc);
+ }
+
acc
}
@@ -431,6 +435,23 @@ impl ModuleDef {
}
}
+ /// Returns only defs that have generics from themselves, not their parent.
+ pub fn as_self_generic_def(self) -> Option<GenericDef> {
+ match self {
+ ModuleDef::Function(it) => Some(it.into()),
+ ModuleDef::Adt(it) => Some(it.into()),
+ ModuleDef::Trait(it) => Some(it.into()),
+ ModuleDef::TraitAlias(it) => Some(it.into()),
+ ModuleDef::TypeAlias(it) => Some(it.into()),
+ ModuleDef::Module(_)
+ | ModuleDef::Variant(_)
+ | ModuleDef::Static(_)
+ | ModuleDef::Const(_)
+ | ModuleDef::BuiltinType(_)
+ | ModuleDef::Macro(_) => None,
+ }
+ }
+
pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
Some(match self {
ModuleDef::Module(it) => it.attrs(db),
@@ -605,17 +626,42 @@ impl Module {
ModuleDef::Adt(adt) => {
match adt {
Adt::Struct(s) => {
+ let tree_id = s.id.lookup(db.upcast()).id;
+ let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1;
+ push_ty_diagnostics(
+ db,
+ acc,
+ db.field_types_with_diagnostics(s.id.into()).1,
+ tree_source_maps.strukt(tree_id.value).item(),
+ );
for diag in db.struct_data_with_diagnostics(s.id).1.iter() {
emit_def_diagnostic(db, acc, diag, edition);
}
}
Adt::Union(u) => {
+ let tree_id = u.id.lookup(db.upcast()).id;
+ let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1;
+ push_ty_diagnostics(
+ db,
+ acc,
+ db.field_types_with_diagnostics(u.id.into()).1,
+ tree_source_maps.union(tree_id.value).item(),
+ );
for diag in db.union_data_with_diagnostics(u.id).1.iter() {
emit_def_diagnostic(db, acc, diag, edition);
}
}
Adt::Enum(e) => {
for v in e.variants(db) {
+ let tree_id = v.id.lookup(db.upcast()).id;
+ let tree_source_maps =
+ tree_id.item_tree_with_source_map(db.upcast()).1;
+ push_ty_diagnostics(
+ db,
+ acc,
+ db.field_types_with_diagnostics(v.id.into()).1,
+ tree_source_maps.variant(tree_id.value),
+ );
acc.extend(ModuleDef::Variant(v).diagnostics(db, style_lints));
for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() {
emit_def_diagnostic(db, acc, diag, edition);
@@ -626,6 +672,17 @@ impl Module {
acc.extend(def.diagnostics(db, style_lints))
}
ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m),
+ ModuleDef::TypeAlias(type_alias) => {
+ let tree_id = type_alias.id.lookup(db.upcast()).id;
+ let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1;
+ push_ty_diagnostics(
+ db,
+ acc,
+ db.type_for_type_alias_with_diagnostics(type_alias.id).1,
+ tree_source_maps.type_alias(tree_id.value).item(),
+ );
+ acc.extend(def.diagnostics(db, style_lints));
+ }
_ => acc.extend(def.diagnostics(db, style_lints)),
}
}
@@ -635,8 +692,11 @@ impl Module {
let mut impl_assoc_items_scratch = vec![];
for impl_def in self.impl_defs(db) {
+ GenericDef::Impl(impl_def).diagnostics(db, acc);
+
let loc = impl_def.id.lookup(db.upcast());
- let tree = loc.id.item_tree(db.upcast());
+ let (tree, tree_source_maps) = loc.id.item_tree_with_source_map(db.upcast());
+ let source_map = tree_source_maps.impl_(loc.id.value).item();
let node = &tree[loc.id.value];
let file_id = loc.id.file_id();
if file_id.macro_file().map_or(false, |it| it.is_builtin_derive(db.upcast())) {
@@ -771,6 +831,19 @@ impl Module {
impl_assoc_items_scratch.clear();
}
+ push_ty_diagnostics(
+ db,
+ acc,
+ db.impl_self_ty_with_diagnostics(impl_def.id).1,
+ source_map,
+ );
+ push_ty_diagnostics(
+ db,
+ acc,
+ db.impl_trait_with_diagnostics(impl_def.id).and_then(|it| it.1),
+ source_map,
+ );
+
for &item in db.impl_data(impl_def.id).items.iter() {
AssocItem::from(item).diagnostics(db, acc, style_lints);
}
@@ -3350,12 +3423,22 @@ impl AssocItem {
) {
match self {
AssocItem::Function(func) => {
+ GenericDef::Function(func).diagnostics(db, acc);
DefWithBody::from(func).diagnostics(db, acc, style_lints);
}
AssocItem::Const(const_) => {
DefWithBody::from(const_).diagnostics(db, acc, style_lints);
}
AssocItem::TypeAlias(type_alias) => {
+ GenericDef::TypeAlias(type_alias).diagnostics(db, acc);
+ let tree_id = type_alias.id.lookup(db.upcast()).id;
+ let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1;
+ push_ty_diagnostics(
+ db,
+ acc,
+ db.type_for_type_alias_with_diagnostics(type_alias.id).1,
+ tree_source_maps.type_alias(tree_id.value).item(),
+ );
for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) {
acc.push(diag.into());
}
@@ -3442,6 +3525,97 @@ impl GenericDef {
})
.collect()
}
+
+ fn id(self) -> GenericDefId {
+ match self {
+ GenericDef::Function(it) => it.id.into(),
+ GenericDef::Adt(it) => it.into(),
+ GenericDef::Trait(it) => it.id.into(),
+ GenericDef::TraitAlias(it) => it.id.into(),
+ GenericDef::TypeAlias(it) => it.id.into(),
+ GenericDef::Impl(it) => it.id.into(),
+ GenericDef::Const(it) => it.id.into(),
+ }
+ }
+
+ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
+ let def = self.id();
+
+ let item_tree_source_maps;
+ let (generics, generics_source_map) = db.generic_params_with_source_map(def);
+
+ if generics.is_empty() && generics.no_predicates() {
+ return;
+ }
+
+ let source_map = match &generics_source_map {
+ Some(it) => it,
+ None => match def {
+ GenericDefId::FunctionId(it) => {
+ let id = it.lookup(db.upcast()).id;
+ item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+ item_tree_source_maps.function(id.value).generics()
+ }
+ GenericDefId::AdtId(AdtId::EnumId(it)) => {
+ let id = it.lookup(db.upcast()).id;
+ item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+ item_tree_source_maps.enum_generic(id.value)
+ }
+ GenericDefId::AdtId(AdtId::StructId(it)) => {
+ let id = it.lookup(db.upcast()).id;
+ item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+ item_tree_source_maps.strukt(id.value).generics()
+ }
+ GenericDefId::AdtId(AdtId::UnionId(it)) => {
+ let id = it.lookup(db.upcast()).id;
+ item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+ item_tree_source_maps.union(id.value).generics()
+ }
+ GenericDefId::TraitId(it) => {
+ let id = it.lookup(db.upcast()).id;
+ item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+ item_tree_source_maps.trait_generic(id.value)
+ }
+ GenericDefId::TraitAliasId(it) => {
+ let id = it.lookup(db.upcast()).id;
+ item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+ item_tree_source_maps.trait_alias_generic(id.value)
+ }
+ GenericDefId::TypeAliasId(it) => {
+ let id = it.lookup(db.upcast()).id;
+ item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+ item_tree_source_maps.type_alias(id.value).generics()
+ }
+ GenericDefId::ImplId(it) => {
+ let id = it.lookup(db.upcast()).id;
+ item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+ item_tree_source_maps.impl_(id.value).generics()
+ }
+ GenericDefId::ConstId(_) => return,
+ },
+ };
+
+ push_ty_diagnostics(db, acc, db.generic_defaults_with_diagnostics(def).1, source_map);
+ push_ty_diagnostics(
+ db,
+ acc,
+ db.generic_predicates_without_parent_with_diagnostics(def).1,
+ source_map,
+ );
+ for (param_id, param) in generics.iter_type_or_consts() {
+ if let TypeOrConstParamData::ConstParamData(_) = param {
+ push_ty_diagnostics(
+ db,
+ acc,
+ db.const_param_ty_with_diagnostics(ConstParamId::from_unchecked(
+ TypeOrConstParamId { parent: def, local_id: param_id },
+ ))
+ .1,
+ source_map,
+ );
+ }
+ }
+ }
}
/// A single local definition.
@@ -5825,3 +5999,19 @@ pub enum DocLinkDef {
Field(Field),
SelfType(Trait),
}
+
+fn push_ty_diagnostics(
+ db: &dyn HirDatabase,
+ acc: &mut Vec<AnyDiagnostic>,
+ diagnostics: Option<ThinArc<(), TyLoweringDiagnostic>>,
+ source_map: &TypesSourceMap,
+) {
+ if let Some(diagnostics) = diagnostics {
+ acc.extend(
+ diagnostics
+ .slice
+ .iter()
+ .filter_map(|diagnostic| AnyDiagnostic::ty_diagnostic(diagnostic, source_map, db)),
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs b/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
index c3ad6704b6..a319a0bcf6 100644
--- a/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
+++ b/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
@@ -68,6 +68,9 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::GenericArgsProhibited) -> Option
#[cfg(test)]
mod tests {
+ // This diagnostic was the first to be emitted in ty lowering, so the tests here also test
+ // diagnostics in ty lowering in general (which is why there are so many of them).
+
use crate::tests::{check_diagnostics, check_fix};
#[test]
@@ -239,4 +242,201 @@ fn foo() {
}"#,
);
}
+
+ #[test]
+ fn in_fields() {
+ check_diagnostics(
+ r#"
+struct A(bool<i32>);
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+struct B { v: bool<(), 1> }
+ // ^^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+union C {
+ a: bool<i32>,
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+ b: i32<bool>,
+ // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+ }
+enum D {
+ A(bool<i32>),
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+ B { v: i32<bool> },
+ // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+ "#,
+ );
+ }
+
+ #[test]
+ fn in_generics() {
+ check_diagnostics(
+ r#"
+mod foo {
+ pub trait Trait {}
+}
+
+struct A<A: foo::<()>::Trait>(A)
+ // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+ where bool<i32>: foo::Trait;
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+union B<A: foo::<()>::Trait>
+ // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+ where bool<i32>: foo::Trait
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+{ a: A }
+enum C<A: foo::<()>::Trait>
+ // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+ where bool<i32>: foo::Trait
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+{}
+
+fn f<A: foo::<()>::Trait>()
+ // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+ where bool<i32>: foo::Trait
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+{}
+
+type D<A: foo::<()>::Trait> = A
+ // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+ where bool<i32>: foo::Trait;
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+
+trait E<A: foo::<()>::Trait>
+ // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+ where bool<i32>: foo::Trait
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+{
+ fn f<B: foo::<()>::Trait>()
+ // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+ where bool<i32>: foo::Trait
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+ {}
+
+ type D<B: foo::<()>::Trait> = A
+ // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+ where bool<i32>: foo::Trait;
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+
+impl<A: foo::<()>::Trait> E for ()
+ // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+ where bool<i32>: foo::Trait
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+{
+ fn f<B: foo::<()>::Trait>()
+ // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+ where bool<i32>: foo::Trait
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+ {}
+
+ type D<B: foo::<()>::Trait> = A
+ // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+ where bool<i32>: foo::Trait;
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+ "#,
+ );
+ }
+
+ #[test]
+ fn assoc_items() {
+ check_diagnostics(
+ r#"
+struct Foo;
+
+trait Trait {
+ fn f() -> bool<i32> { true }
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+ type T = i32<bool>;
+ // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+
+impl Trait for Foo {
+ fn f() -> bool<i32> { true }
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+ type T = i32<bool>;
+ // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+
+impl Foo {
+ fn f() -> bool<i32> { true }
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+ type T = i32<bool>;
+ // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+ "#,
+ );
+ }
+
+ #[test]
+ fn const_param_ty() {
+ check_diagnostics(
+ r#"
+fn foo<
+ const A: bool<i32>,
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+ B,
+ C,
+ const D: bool<i32>,
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+ const E: bool<i32>,
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+>() {}
+ "#,
+ );
+ }
+
+ #[test]
+ fn generic_defaults() {
+ check_diagnostics(
+ r#"
+struct Foo<A = bool<i32>>(A);
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+ "#,
+ );
+ }
+
+ #[test]
+ fn impl_self_ty() {
+ check_diagnostics(
+ r#"
+struct Foo<A>(A);
+trait Trait {}
+impl Foo<bool<i32>> {}
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+impl Trait for Foo<bool<i32>> {}
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+ "#,
+ );
+ }
+
+ #[test]
+ fn impl_trait() {
+ check_diagnostics(
+ r#"
+mod foo {
+ pub trait Trait {}
+}
+impl foo::<()>::Trait for () {}
+ // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+ "#,
+ );
+ }
+
+ #[test]
+ fn type_alias() {
+ check_diagnostics(
+ r#"
+pub trait Trait {
+ type Assoc;
+}
+type T = bool<i32>;
+ // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+impl Trait for () {
+ type Assoc = i32<bool>;
+ // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+ "#,
+ );
+ }
}