mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 13:48:50 +00:00
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:
parent
5f25ae3d1b
commit
21ad3b5b87
8 changed files with 621 additions and 103 deletions
|
@ -224,6 +224,11 @@ impl GenericParams {
|
|||
self.len() == 0
|
||||
}
|
||||
|
||||
#[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()
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
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))
|
||||
}
|
||||
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(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),
|
||||
)
|
||||
}
|
||||
|
||||
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_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 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(
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue