diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 428cedbb49..8053300ad2 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -219,6 +219,9 @@ pub enum InferenceDiagnostic { field_with_same_name: Option, assoc_func_with_same_name: Option, }, + UnresolvedAssocItem { + id: ExprOrPatId, + }, // FIXME: This should be emitted in body lowering BreakOutsideOfLoop { expr: ExprId, diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 49fb78f67a..e61a070265 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -340,6 +340,9 @@ impl InferenceContext<'_> { }, ); let res = res.or(not_visible); + if res.is_none() { + self.push_diagnostic(InferenceDiagnostic::UnresolvedAssocItem { id }); + } let (item, visible) = res?; let (def, container) = match item { diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index ba591e1892..bf29a53913 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -62,6 +62,7 @@ diagnostics![ UndeclaredLabel, UnimplementedBuiltinMacro, UnreachableLabel, + UnresolvedAssocItem, UnresolvedExternCrate, UnresolvedField, UnresolvedImport, @@ -218,6 +219,11 @@ pub struct UnresolvedMethodCall { pub assoc_func_with_same_name: Option, } +#[derive(Debug)] +pub struct UnresolvedAssocItem { + pub expr_or_pat: InFile>>>, +} + #[derive(Debug)] pub struct PrivateField { pub expr: InFile>, diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 087404ccb0..09b56e1382 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1697,6 +1697,13 @@ impl DefWithBody { .into(), ) } + &hir_ty::InferenceDiagnostic::UnresolvedAssocItem { id } => { + let expr_or_pat = match id { + ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left), + ExprOrPatId::PatId(pat) => pat_syntax(pat).map(AstPtr::wrap_right), + }; + acc.push(UnresolvedAssocItem { expr_or_pat }.into()) + } &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, diff --git a/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs b/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs new file mode 100644 index 0000000000..f1c95993c8 --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs @@ -0,0 +1,52 @@ +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: unresolved-assoc-item +// +// This diagnostic is triggered if the referenced associated item does not exist. +pub(crate) fn unresolved_assoc_item( + ctx: &DiagnosticsContext<'_>, + d: &hir::UnresolvedAssocItem, +) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0599"), + "no such associated item", + d.expr_or_pat.clone().map(Into::into), + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn bare() { + check_diagnostics( + r#" +struct S; + +fn main() { + let _ = S::Assoc; + //^^^^^^^^ error: no such associated item +} +"#, + ); + } + + #[test] + fn unimplemented_trait() { + check_diagnostics( + r#" +struct S; +trait Foo { + const X: u32; +} + +fn main() { + let _ = S::X; + //^^^^ error: no such associated item +} +"#, + ); + } +} diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 579386c72e..c7ad09e7eb 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -51,6 +51,7 @@ mod handlers { pub(crate) mod typed_hole; pub(crate) mod type_mismatch; pub(crate) mod unimplemented_builtin_macro; + pub(crate) mod unresolved_assoc_item; pub(crate) mod unresolved_extern_crate; pub(crate) mod unresolved_field; pub(crate) mod unresolved_method; @@ -371,7 +372,8 @@ pub fn diagnostics( AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d), AnyDiagnostic::UndeclaredLabel(d) => handlers::undeclared_label::undeclared_label(&ctx, &d), AnyDiagnostic::UnimplementedBuiltinMacro(d) => handlers::unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), - AnyDiagnostic::UnreachableLabel(d) => handlers::unreachable_label:: unreachable_label(&ctx, &d), + AnyDiagnostic::UnreachableLabel(d) => handlers::unreachable_label::unreachable_label(&ctx, &d), + AnyDiagnostic::UnresolvedAssocItem(d) => handlers::unresolved_assoc_item::unresolved_assoc_item(&ctx, &d), AnyDiagnostic::UnresolvedExternCrate(d) => handlers::unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), AnyDiagnostic::UnresolvedField(d) => handlers::unresolved_field::unresolved_field(&ctx, &d), AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d),