diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index df83b2abb870..985a3ddc6a52 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -55,7 +55,7 @@ use thin_vec::ThinVec; use tracing::debug; use crate::{ - ImplTraitId, Span, TyLoweringDiagnostic, TyLoweringDiagnosticKind, + ImplTraitId, Span, TyLoweringDiagnostic, consteval::{create_anon_const, path_to_const}, db::{AnonConstId, GeneralConstId, HirDatabase, InternedOpaqueTyId}, generics::{Generics, SingleGenerics, generics}, @@ -302,8 +302,14 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { self } - pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) { - self.diagnostics.push(TyLoweringDiagnostic { source: type_ref, kind }); + pub(crate) fn push_diagnostic(&mut self, diagnostic: TyLoweringDiagnostic) { + self.diagnostics.push(diagnostic); + } + + fn push_infer_vars_not_allowed(&mut self, span: Span) { + if !span.is_dummy() { + self.push_diagnostic(TyLoweringDiagnostic::InferVarsNotAllowed { source: span }); + } } #[track_caller] @@ -315,7 +321,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { match &mut self.infer_vars { Some(infer_vars) => infer_vars.next_ty_var(span), None => { - // FIXME: Emit an error: no infer vars allowed here. + self.push_infer_vars_not_allowed(span); self.types.types.error } } @@ -325,7 +331,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { match &mut self.infer_vars { Some(infer_vars) => infer_vars.next_const_var(span), None => { - // FIXME: Emit an error: no infer vars allowed here. + self.push_infer_vars_not_allowed(span); self.types.consts.error } } @@ -335,7 +341,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { match &mut self.infer_vars { Some(infer_vars) => infer_vars.next_region_var(span), None => { - // FIXME: Emit an error: no infer vars allowed here. + self.push_infer_vars_not_allowed(span); self.types.regions.error } } @@ -634,7 +640,10 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { data: Either::Left(PathDiagnosticCallbackData(type_ref)), callback: |data, this, diag| { let type_ref = data.as_ref().left().unwrap().0; - this.push_diagnostic(type_ref, TyLoweringDiagnosticKind::PathDiagnostic(diag)) + this.push_diagnostic(TyLoweringDiagnostic::PathDiagnostic { + source: type_ref, + diag, + }) }, } } diff --git a/crates/hir-ty/src/lower/diagnostics.rs b/crates/hir-ty/src/lower/diagnostics.rs index 2565fb46ce8c..35ee99cb95a3 100644 --- a/crates/hir-ty/src/lower/diagnostics.rs +++ b/crates/hir-ty/src/lower/diagnostics.rs @@ -1,17 +1,13 @@ //! This files contains the declaration of diagnostics kinds for ty and path lowering. -use hir_def::type_ref::TypeRefId; -use hir_def::{GenericDefId, GenericParamId}; +use hir_def::{GenericDefId, GenericParamId, type_ref::TypeRefId}; -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct TyLoweringDiagnostic { - pub source: TypeRefId, - pub kind: TyLoweringDiagnosticKind, -} +use crate::Span; #[derive(Debug, PartialEq, Eq, Clone)] -pub enum TyLoweringDiagnosticKind { - PathDiagnostic(PathLoweringDiagnostic), +pub enum TyLoweringDiagnostic { + PathDiagnostic { source: TypeRefId, diag: PathLoweringDiagnostic }, + InferVarsNotAllowed { source: Span }, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index f3188c9aada5..ed073cb43789 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -11,12 +11,13 @@ use hir_def::{ ExprOrPatPtr, ExpressionStoreSourceMap, hir_assoc_type_binding_to_ast, hir_generic_arg_to_ast, hir_segment_to_ast_segment, }, - hir::ExprOrPatId, + hir::{ExprId, ExprOrPatId, PatId}, + type_ref::TypeRefId, }; use hir_expand::{HirFileId, InFile, mod_path::ModPath, name::Name}; use hir_ty::{ CastError, ExplicitDropMethodUseKind, InferenceDiagnostic, InferenceTyDiagnosticSource, - PathGenericsSource, PathLoweringDiagnostic, TyLoweringDiagnostic, TyLoweringDiagnosticKind, + PathGenericsSource, PathLoweringDiagnostic, TyLoweringDiagnostic, db::HirDatabase, diagnostics::{BodyValidationDiagnostic, UnsafetyReason}, display::{DisplayTarget, HirDisplay}, @@ -118,6 +119,7 @@ diagnostics![AnyDiagnostic<'db> -> IncorrectCase, IncorrectGenericsLen, IncorrectGenericsOrder, + InferVarsNotAllowed, InvalidCast<'db>, InvalidDeriveTarget, InvalidLhsOfAssignment, @@ -564,6 +566,11 @@ pub struct BadRtn { pub rtn: InFile>, } +#[derive(Debug)] +pub struct InferVarsNotAllowed { + pub node: InFile, +} + #[derive(Debug)] pub struct IncorrectGenericsLen { /// Points at the name if there are no generics. @@ -799,41 +806,14 @@ impl<'db> AnyDiagnostic<'db> { sig_map: &hir_def::expr_store::ExpressionStoreSourceMap, type_owner: TypeOwnerId, ) -> Option> { - let expr_syntax = |expr| { - source_map - .expr_syntax(expr) - .inspect_err(|_| stdx::never!("inference diagnostic in desugared expr")) - .ok() - }; - let pat_syntax = |pat| { - source_map - .pat_syntax(pat) - .inspect_err(|_| stdx::never!("inference diagnostic in desugared pattern")) - .ok() - }; - let type_syntax = |pat| { - source_map - .type_syntax(pat) - .inspect_err(|_| stdx::never!("inference diagnostic in desugared type")) - .ok() - }; + let expr_syntax = |expr| Self::expr_syntax(expr, source_map); + let pat_syntax = |pat| Self::pat_syntax(pat, source_map); let expr_or_pat_syntax = |id| match id { ExprOrPatId::ExprId(expr) => expr_syntax(expr), ExprOrPatId::PatId(pat) => pat_syntax(pat), }; let new_ty = |ty| Type { owner: type_owner, ty: EarlyBinder::bind(ty) }; - let span_syntax = |span| match span { - hir_ty::Span::ExprId(idx) => expr_syntax(idx).map(|it| it.upcast()), - hir_ty::Span::PatId(idx) => pat_syntax(idx).map(|it| it.upcast()), - hir_ty::Span::TypeRefId(idx) => type_syntax(idx).map(|it| it.upcast()), - hir_ty::Span::BindingId(idx) => { - pat_syntax(source_map.patterns_for_binding(idx)[0]).map(|it| it.upcast()) - } - hir_ty::Span::Dummy => { - never!("should never create a diagnostic for dummy spans"); - None - } - }; + let span_syntax = |span| Self::span_syntax(span, source_map); Some(match d { &InferenceDiagnostic::NoSuchField { field: expr, private, variant } => { let expr_or_pat = match expr { @@ -1238,21 +1218,73 @@ impl<'db> AnyDiagnostic<'db> { }) } + fn expr_syntax( + expr: ExprId, + source_map: &ExpressionStoreSourceMap, + ) -> Option> { + source_map + .expr_syntax(expr) + .inspect_err(|_| stdx::never!("inference diagnostic in desugared expr")) + .ok() + } + + fn pat_syntax( + pat: PatId, + source_map: &ExpressionStoreSourceMap, + ) -> Option> { + source_map + .pat_syntax(pat) + .inspect_err(|_| stdx::never!("inference diagnostic in desugared pattern")) + .ok() + } + + fn type_syntax( + type_ref: TypeRefId, + source_map: &ExpressionStoreSourceMap, + ) -> Option>> { + source_map + .type_syntax(type_ref) + .inspect_err(|_| stdx::never!("inference diagnostic in desugared type")) + .ok() + } + + fn span_syntax( + span: hir_ty::Span, + source_map: &ExpressionStoreSourceMap, + ) -> Option>> { + Some(match span { + hir_ty::Span::ExprId(idx) => Self::expr_syntax(idx, source_map)?.map(|it| it.upcast()), + hir_ty::Span::PatId(idx) => Self::pat_syntax(idx, source_map)?.map(|it| it.upcast()), + hir_ty::Span::TypeRefId(idx) => { + Self::type_syntax(idx, source_map)?.map(|it| it.upcast()) + } + hir_ty::Span::BindingId(idx) => { + let &pat = source_map.patterns_for_binding(idx).first()?; + Self::pat_syntax(pat, source_map)?.map(|it| it.upcast()) + } + hir_ty::Span::Dummy => { + never!("should never create a diagnostic for dummy spans"); + return None; + } + }) + } + pub(crate) fn ty_diagnostic( diag: &TyLoweringDiagnostic, source_map: &ExpressionStoreSourceMap, db: &'db dyn HirDatabase, ) -> Option> { - let Ok(source) = source_map.type_syntax(diag.source) else { - stdx::never!("error on synthetic type syntax"); - return None; - }; - let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id)); - Some(match &diag.kind { - TyLoweringDiagnosticKind::PathDiagnostic(diag) => { - let ast::Type::PathType(syntax) = syntax() else { return None }; + Some(match diag { + TyLoweringDiagnostic::PathDiagnostic { source, diag } => { + let source = Self::type_syntax(*source, source_map)?; + let syntax = source.value.to_node(&db.parse_or_expand(source.file_id)); + let ast::Type::PathType(syntax) = syntax else { return None }; Self::path_diagnostic(diag, source.with_value(syntax.path()?))? } + TyLoweringDiagnostic::InferVarsNotAllowed { source } => { + let source = Self::span_syntax(*source, source_map)?; + InferVarsNotAllowed { node: source.map(Into::into) }.into() + } }) } } diff --git a/crates/ide-diagnostics/src/handlers/infer_vars_not_allowed.rs b/crates/ide-diagnostics/src/handlers/infer_vars_not_allowed.rs new file mode 100644 index 000000000000..cf369a1aa0e3 --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/infer_vars_not_allowed.rs @@ -0,0 +1,49 @@ +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: infer-vars-not-allowed +// +// This diagnostic is triggered when `_` is used where type +// inference is not allowed. +pub(crate) fn infer_vars_not_allowed( + ctx: &DiagnosticsContext<'_, '_>, + d: &hir::InferVarsNotAllowed, +) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0121"), + "the type placeholder `_` is not allowed within types on item signatures", + d.node, + ) +} +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + #[test] + fn type_alias() { + check_diagnostics( + r#" +type Foo = _; + // ^ error: the type placeholder `_` is not allowed within types on item signatures + "#, + ); + } + #[test] + fn const_item() { + check_diagnostics( + r#" +const X: _ = 0; + // ^ error: the type placeholder `_` is not allowed within types on item signatures + "#, + ); + } + + #[test] + fn static_item() { + check_diagnostics( + r#" +static Y: _ = 0; + // ^ error: the type placeholder `_` is not allowed within types on item signatures + "#, + ); + } +} diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index aec68b55c78d..ea0d2d954eb0 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -50,6 +50,7 @@ mod handlers { pub(crate) mod incorrect_case; pub(crate) mod incorrect_generics_len; pub(crate) mod incorrect_generics_order; + pub(crate) mod infer_vars_not_allowed; pub(crate) mod invalid_cast; pub(crate) mod invalid_derive_target; pub(crate) mod invalid_lhs_of_assignment; @@ -440,6 +441,7 @@ pub fn semantic_diagnostics( AnyDiagnostic::CannotImplicitlyDerefTraitObject(d) => handlers::cannot_implicitly_deref_trait_object::cannot_implicitly_deref_trait_object(&ctx, &d), AnyDiagnostic::CannotIndexInto(d) => handlers::cannot_index_into::cannot_index_into(&ctx, &d), AnyDiagnostic::CastToUnsized(d) => handlers::invalid_cast::cast_to_unsized(&ctx, &d), + AnyDiagnostic::InferVarsNotAllowed(d) => handlers::infer_vars_not_allowed::infer_vars_not_allowed(&ctx, &d), AnyDiagnostic::ArrayPatternWithoutFixedLength(d) => { handlers::array_pattern_without_fixed_length::array_pattern_without_fixed_length( &ctx, &d,