about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir-ty/src/infer.rs3
-rw-r--r--crates/hir-ty/src/infer/path.rs3
-rw-r--r--crates/hir/src/diagnostics.rs6
-rw-r--r--crates/hir/src/lib.rs7
-rw-r--r--crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs52
-rw-r--r--crates/ide-diagnostics/src/lib.rs4
6 files changed, 74 insertions, 1 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 428cedbb49b..8053300ad22 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<Ty>,
         assoc_func_with_same_name: Option<AssocItemId>,
     },
+    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 49fb78f67a6..e61a070265a 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 ba591e18921..bf29a53913d 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,
@@ -219,6 +220,11 @@ pub struct UnresolvedMethodCall {
 }
 
 #[derive(Debug)]
+pub struct UnresolvedAssocItem {
+    pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, Either<ast::Pat, ast::SelfParam>>>>,
+}
+
+#[derive(Debug)]
 pub struct PrivateField {
     pub expr: InFile<AstPtr<ast::Expr>>,
     pub field: Field,
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 087404ccb09..09b56e13824 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 00000000000..f1c95993c84
--- /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 579386c72ef..c7ad09e7ebd 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),