Complete diagnostics in ty lowering groundwork

Implement diagnostics in all places left: generics (predicates, defaults, const params' types), fields, and type aliases.

Unfortunately this results in a 20mb addition in `analysis-stats .` due to many type methods returning an addition diagnostics result now (even if it's `None` in most cases). I'm not sure if this can be improved.

An alternative strategy that can prevent the memory usage growth is to never produce diagnostics in hir-ty methods. Instead, lower all types in the hir crate when computing diagnostics from scratch (with diagnostics this time). But this has two serious disadvantages:
 1. This can cause code duplication (although it can probably be not that bad, it will still mean a lot more code).
 2. I believe we eventually want to compute diagnostics for the *entire* workspace (either on-type or on-save or something alike), so users can know when they have diagnostics even in inactive files. Choosing this approach will mean we lose all precomputed salsa queries. For one file this is fine, for the whole workspace this will be very slow.
This commit is contained in:
Chayim Refael Friedman 2024-11-21 02:21:16 +02:00
parent 5f25ae3d1b
commit 21ad3b5b87
8 changed files with 621 additions and 103 deletions

View file

@ -224,6 +224,11 @@ impl GenericParams {
self.len() == 0 self.len() == 0
} }
#[inline]
pub fn no_predicates(&self) -> bool {
self.where_predicates.is_empty()
}
#[inline] #[inline]
pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> { pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> {
self.where_predicates.iter() self.where_predicates.iter()

View file

@ -22,7 +22,7 @@ use crate::{
consteval::ConstEvalError, consteval::ConstEvalError,
dyn_compatibility::DynCompatibilityViolation, dyn_compatibility::DynCompatibilityViolation,
layout::{Layout, LayoutError}, layout::{Layout, LayoutError},
lower::{GenericDefaults, GenericPredicates}, lower::{Diagnostics, GenericDefaults, GenericPredicates},
method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
mir::{BorrowckResult, MirBody, MirLowerError}, mir::{BorrowckResult, MirBody, MirLowerError},
Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner, 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)] #[ra_salsa::cycle(crate::lower::ty_recover)]
fn ty(&self, def: TyDefId) -> Binders<Ty>; 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 /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is
/// a `StructId` or `EnumVariantId` with a record constructor. /// a `StructId` or `EnumVariantId` with a record constructor.
#[ra_salsa::invoke(crate::lower::value_ty_query)] #[ra_salsa::invoke(crate::lower::value_ty_query)]
fn value_ty(&self, def: ValueTyDefId) -> Option<Binders<Ty>>; 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::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>; 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)] #[ra_salsa::invoke(crate::lower::const_param_ty_query)]
fn const_param_ty(&self, def: ConstParamId) -> Ty; 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)] #[ra_salsa::invoke(crate::lower::impl_trait_query)]
fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>; 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)] #[ra_salsa::invoke(crate::lower::field_types_query)]
fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>; 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)] #[ra_salsa::invoke(crate::lower::generic_predicates_query)]
fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; 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)] #[ra_salsa::invoke(crate::lower::generic_predicates_without_parent_query)]
fn generic_predicates_without_parent(&self, def: GenericDefId) -> GenericPredicates; 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)] #[ra_salsa::invoke(crate::lower::trait_environment_query)]
fn trait_environment(&self, def: GenericDefId) -> Arc<TraitEnvironment>; 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::invoke(crate::lower::generic_defaults_query)]
#[ra_salsa::cycle(crate::lower::generic_defaults_recover)]
fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults; fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults;
#[ra_salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] #[ra_salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]

View file

@ -55,6 +55,10 @@ impl Generics {
self.def self.def
} }
pub(crate) fn self_types_map(&self) -> &TypesMap {
&self.params.types_map
}
pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ { pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
self.iter_self_id().chain(self.iter_parent_id()) self.iter_self_id().chain(self.iter_parent_id())
} }
@ -86,15 +90,13 @@ impl Generics {
self.iter_self().chain(self.iter_parent()) self.iter_self().chain(self.iter_parent())
} }
pub(crate) fn iter_with_types_map( pub(crate) fn iter_parents_with_types_map(
&self, &self,
) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &TypesMap)> + '_ { ) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &TypesMap)> + '_ {
self.iter_self().zip(std::iter::repeat(&self.params.types_map)).chain( self.iter_parent().zip(
self.iter_parent().zip( self.parent_generics()
self.parent_generics() .into_iter()
.into_iter() .flat_map(|it| std::iter::repeat(&it.params.types_map)),
.flat_map(|it| std::iter::repeat(&it.params.types_map)),
),
) )
} }

View file

@ -90,7 +90,8 @@ pub use infer::{
pub use interner::Interner; pub use interner::Interner;
pub use lower::{ pub use lower::{
associated_type_shorthand_candidates, GenericArgsProhibitedReason, ImplTraitLoweringMode, associated_type_shorthand_candidates, GenericArgsProhibitedReason, ImplTraitLoweringMode,
ParamLoweringMode, TyDefId, TyLoweringContext, TyLoweringDiagnosticKind, ValueTyDefId, ParamLoweringMode, TyDefId, TyLoweringContext, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
ValueTyDefId,
}; };
pub use mapping::{ pub use mapping::{
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,

View file

@ -48,7 +48,7 @@ use rustc_pattern_analysis::Captures;
use smallvec::SmallVec; use smallvec::SmallVec;
use stdx::{impl_from, never}; use stdx::{impl_from, never};
use syntax::ast; use syntax::ast;
use triomphe::Arc; use triomphe::{Arc, ThinArc};
use crate::{ use crate::{
all_super_traits, 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( pub(crate) fn field_types_query(
db: &dyn HirDatabase, db: &dyn HirDatabase,
variant_id: VariantId, variant_id: VariantId,
) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> { ) -> 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 var_data = variant_id.variant_data(db.upcast());
let (resolver, def): (_, GenericDefId) = match variant_id { let (resolver, def): (_, GenericDefId) = match variant_id {
VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()), 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() { 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))); 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 /// 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, db: &dyn HirDatabase,
def: GenericDefId, def: GenericDefId,
) -> GenericPredicates { ) -> 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( pub(crate) fn generic_predicates_without_parent_query(
db: &dyn HirDatabase, db: &dyn HirDatabase,
def: GenericDefId, def: GenericDefId,
) -> GenericPredicates { ) -> 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) generic_predicates_filtered_by(db, def, |_, d| *d == def)
} }
@ -1891,7 +1911,7 @@ fn generic_predicates_filtered_by<F>(
db: &dyn HirDatabase, db: &dyn HirDatabase,
def: GenericDefId, def: GenericDefId,
filter: F, filter: F,
) -> GenericPredicates ) -> (GenericPredicates, Diagnostics)
where where
F: Fn(&WherePredicate, &GenericDefId) -> bool, 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. /// 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 { 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); let generic_params = generics(db.upcast(), def);
if generic_params.len() == 0 { if generic_params.len() == 0 {
return GenericDefaults(None); return (GenericDefaults(None), None);
} }
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let parent_start_idx = generic_params.len_self(); let parent_start_idx = generic_params.len_self();
let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into()) let mut ctx =
.with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) TyLoweringContext::new(db, &resolver, generic_params.self_types_map(), def.into())
.with_type_param_mode(ParamLoweringMode::Variable); .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
GenericDefaults(Some(Arc::from_iter(generic_params.iter_with_types_map().enumerate().map( .with_type_param_mode(ParamLoweringMode::Variable);
|(idx, ((id, p), types_map))| { let mut idx = 0;
ctx.types_map = types_map; let mut defaults = generic_params
match p { .iter_self()
GenericParamDataRef::TypeParamData(p) => { .map(|(id, p)| {
let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| { let result =
// Each default can only refer to previous parameters. handle_generic_param(&mut ctx, idx, id, p, parent_start_idx, &generic_params);
// Type variable default referring to parameter coming idx += 1;
// after it is forbidden (FIXME: report diagnostic) result
fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx) })
}); .collect::<Vec<_>>();
crate::make_binders(db, &generic_params, ty.cast(Interner)) let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics));
} defaults.extend(generic_params.iter_parents_with_types_map().map(|((id, p), types_map)| {
GenericParamDataRef::ConstParamData(p) => { ctx.types_map = types_map;
let GenericParamId::ConstParamId(id) = id else { let result = handle_generic_param(&mut ctx, idx, id, p, parent_start_idx, &generic_params);
unreachable!("Unexpected lifetime or type argument") idx += 1;
}; result
}));
let defaults = GenericDefaults(Some(Arc::from_iter(defaults)));
return (defaults, diagnostics);
let mut val = p.default.as_ref().map_or_else( fn handle_generic_param(
|| unknown_const_as_generic(db.const_param_ty(id)), ctx: &mut TyLoweringContext<'_>,
|c| { idx: usize,
let param_ty = ctx.lower_ty(p.ty); id: GenericParamId,
let c = ctx.lower_const(c, param_ty); p: GenericParamDataRef<'_>,
c.cast(Interner) parent_start_idx: usize,
}, generic_params: &Generics,
); ) -> Binders<crate::GenericArg> {
// Each default can only refer to previous parameters, see above. match p {
val = fallback_bound_vars(val, idx, parent_start_idx); GenericParamDataRef::TypeParamData(p) => {
make_binders(db, &generic_params, val) let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| {
} // Each default can only refer to previous parameters.
GenericParamDataRef::LifetimeParamData(_) => { // Type variable default referring to parameter coming
make_binders(db, &generic_params, error_lifetime().cast(Interner)) // 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(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, db: &dyn HirDatabase,
_cycle: &Cycle, _cycle: &Cycle,
def: &GenericDefId, def: &GenericDefId,
) -> GenericDefaults { ) -> (GenericDefaults, Diagnostics) {
let generic_params = generics(db.upcast(), *def); let generic_params = generics(db.upcast(), *def);
if generic_params.len() == 0 { if generic_params.len() == 0 {
return GenericDefaults(None); return (GenericDefaults(None), None);
} }
// FIXME: this code is not covered in tests. // FIXME: this code is not covered in tests.
// we still need one default per parameter // 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 { let val = match id {
GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner), GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)), GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)),
GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner), GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
}; };
crate::make_binders(db, &generic_params, val) crate::make_binders(db, &generic_params, val)
})))) }))));
(defaults, None)
} }
fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { 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) 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 generics = generics(db.upcast(), t.into());
let resolver = t.resolver(db.upcast()); let resolver = t.resolver(db.upcast());
let type_alias_data = db.type_alias_data(t); 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)) .map(|type_ref| ctx.lower_ty(type_ref))
.unwrap_or_else(|| TyKind::Error.intern(Interner)) .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)] #[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 { match def {
TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)), TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)),
TyDefId::AdtId(it) => type_for_adt(db, 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> { 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 impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast()); let resolver = impl_id.resolver(db.upcast());
let generics = generics(db.upcast(), impl_id.into()); let generics = generics(db.upcast(), impl_id.into());
let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into()) let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
.with_type_param_mode(ParamLoweringMode::Variable); .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),
)
}
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 // returns None if def is a type arg
pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { 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 parent_data = db.generic_params(def.parent());
let data = &parent_data[def.local_id()]; let data = &parent_data[def.local_id()];
let resolver = def.parent().resolver(db.upcast()); let resolver = def.parent().resolver(db.upcast());
let mut ctx = let mut ctx =
TyLoweringContext::new(db, &resolver, &parent_data.types_map, def.parent().into()); TyLoweringContext::new(db, &resolver, &parent_data.types_map, def.parent().into());
match data { let ty = match data {
TypeOrConstParamData::TypeParamData(_) => { TypeOrConstParamData::TypeParamData(_) => {
never!(); never!();
Ty::new(Interner, TyKind::Error) Ty::new(Interner, TyKind::Error)
} }
TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty), 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, db: &dyn HirDatabase,
_cycle: &Cycle, _cycle: &Cycle,
impl_id: &ImplId, impl_id: &ImplId,
) -> Binders<Ty> { ) -> (Binders<Ty>, Diagnostics) {
let generics = generics(db.upcast(), (*impl_id).into()); 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>> { 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 impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast()); let resolver = impl_id.resolver(db.upcast());
let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into()) let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); 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 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( pub(crate) fn return_type_impl_traits(

View file

@ -15,7 +15,8 @@ use hir_expand::{name::Name, HirFileId, InFile};
use hir_ty::{ use hir_ty::{
db::HirDatabase, db::HirDatabase,
diagnostics::{BodyValidationDiagnostic, UnsafetyReason}, diagnostics::{BodyValidationDiagnostic, UnsafetyReason},
CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnosticKind, CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic,
TyLoweringDiagnosticKind,
}; };
use syntax::{ use syntax::{
ast::{self, HasGenericArgs}, ast::{self, HasGenericArgs},
@ -402,7 +403,7 @@ pub struct InvalidCast {
#[derive(Debug)] #[derive(Debug)]
pub struct GenericArgsProhibited { pub struct GenericArgsProhibited {
pub args: InFile<AstPtr<Either<ast::GenericArgList, ast::ParamList>>>, pub args: InFile<AstPtr<Either<ast::GenericArgList, ast::ParenthesizedArgList>>>,
pub reason: GenericArgsProhibitedReason, pub reason: GenericArgsProhibitedReason,
} }
@ -664,30 +665,38 @@ impl AnyDiagnostic {
InferenceTyDiagnosticSource::Body => &source_map.types, InferenceTyDiagnosticSource::Body => &source_map.types,
InferenceTyDiagnosticSource::Signature => outer_types_source_map, InferenceTyDiagnosticSource::Signature => outer_types_source_map,
}; };
let source = match diag.source { Self::ty_diagnostic(diag, source_map, db)?
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;
}; pub(crate) fn ty_diagnostic(
source diag: &TyLoweringDiagnostic,
} source_map: &TypesSourceMap,
Either::Right(source) => source, 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)); source
match diag.kind { }
TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => { Either::Right(source) => source,
let ast::Type::PathType(syntax) = syntax() else { return None }; };
let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?; let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id));
let args = if let Some(generics) = segment.generic_arg_list() { Some(match diag.kind {
AstPtr::new(&generics).wrap_left() TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => {
} else { let ast::Type::PathType(syntax) = syntax() else { return None };
AstPtr::new(&segment.param_list()?).wrap_right() let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?;
}; let args = if let Some(generics) = segment.generic_arg_list() {
let args = source.with_value(args); AstPtr::new(&generics).wrap_left()
GenericArgsProhibited { args, reason }.into() } else {
} AstPtr::new(&segment.parenthesized_arg_list()?).wrap_right()
} };
let args = source.with_value(args);
GenericArgsProhibited { args, reason }.into()
} }
}) })
} }

View file

@ -76,8 +76,8 @@ use hir_ty::{
traits::FnTrait, traits::FnTrait,
AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg, AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution, GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyLoweringDiagnostic,
WhereClause, ValueTyDefId, WhereClause,
}; };
use itertools::Itertools; use itertools::Itertools;
use nameres::diagnostics::DefDiagnosticKind; use nameres::diagnostics::DefDiagnosticKind;
@ -89,7 +89,7 @@ use syntax::{
ast::{self, HasAttrs as _, HasGenericParams, HasName}, ast::{self, HasAttrs as _, HasGenericParams, HasName},
format_smolstr, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ToSmolStr, T, format_smolstr, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ToSmolStr, T,
}; };
use triomphe::Arc; use triomphe::{Arc, ThinArc};
use crate::db::{DefDatabase, HirDatabase}; 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 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> { pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
Some(match self { Some(match self {
ModuleDef::Module(it) => it.attrs(db), ModuleDef::Module(it) => it.attrs(db),
@ -605,17 +626,42 @@ impl Module {
ModuleDef::Adt(adt) => { ModuleDef::Adt(adt) => {
match adt { match adt {
Adt::Struct(s) => { 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() { for diag in db.struct_data_with_diagnostics(s.id).1.iter() {
emit_def_diagnostic(db, acc, diag, edition); emit_def_diagnostic(db, acc, diag, edition);
} }
} }
Adt::Union(u) => { 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() { for diag in db.union_data_with_diagnostics(u.id).1.iter() {
emit_def_diagnostic(db, acc, diag, edition); emit_def_diagnostic(db, acc, diag, edition);
} }
} }
Adt::Enum(e) => { Adt::Enum(e) => {
for v in e.variants(db) { 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)); acc.extend(ModuleDef::Variant(v).diagnostics(db, style_lints));
for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() { for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() {
emit_def_diagnostic(db, acc, diag, edition); emit_def_diagnostic(db, acc, diag, edition);
@ -626,6 +672,17 @@ impl Module {
acc.extend(def.diagnostics(db, style_lints)) acc.extend(def.diagnostics(db, style_lints))
} }
ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m), 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)), _ => acc.extend(def.diagnostics(db, style_lints)),
} }
} }
@ -635,8 +692,11 @@ impl Module {
let mut impl_assoc_items_scratch = vec![]; let mut impl_assoc_items_scratch = vec![];
for impl_def in self.impl_defs(db) { for impl_def in self.impl_defs(db) {
GenericDef::Impl(impl_def).diagnostics(db, acc);
let loc = impl_def.id.lookup(db.upcast()); 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 node = &tree[loc.id.value];
let file_id = loc.id.file_id(); let file_id = loc.id.file_id();
if file_id.macro_file().map_or(false, |it| it.is_builtin_derive(db.upcast())) { 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(); 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() { for &item in db.impl_data(impl_def.id).items.iter() {
AssocItem::from(item).diagnostics(db, acc, style_lints); AssocItem::from(item).diagnostics(db, acc, style_lints);
} }
@ -3350,12 +3423,22 @@ impl AssocItem {
) { ) {
match self { match self {
AssocItem::Function(func) => { AssocItem::Function(func) => {
GenericDef::Function(func).diagnostics(db, acc);
DefWithBody::from(func).diagnostics(db, acc, style_lints); DefWithBody::from(func).diagnostics(db, acc, style_lints);
} }
AssocItem::Const(const_) => { AssocItem::Const(const_) => {
DefWithBody::from(const_).diagnostics(db, acc, style_lints); DefWithBody::from(const_).diagnostics(db, acc, style_lints);
} }
AssocItem::TypeAlias(type_alias) => { 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()) { for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) {
acc.push(diag.into()); acc.push(diag.into());
} }
@ -3442,6 +3525,97 @@ impl GenericDef {
}) })
.collect() .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. /// A single local definition.
@ -5825,3 +5999,19 @@ pub enum DocLinkDef {
Field(Field), Field(Field),
SelfType(Trait), 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)),
);
}
}

View file

@ -68,6 +68,9 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::GenericArgsProhibited) -> Option
#[cfg(test)] #[cfg(test)]
mod tests { 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}; use crate::tests::{check_diagnostics, check_fix};
#[test] #[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
}
"#,
);
}
} }