Skip to content

Feature Request: Add relationship type to relatedInformation for cascade error detection #21431

@aady-nuvai

Description

@aady-nuvai

Summary

When rustc emits multiple diagnostics for related errors (e.g., missing semicolon causing "unexpected token" on the next line), IDEs and developer tools cannot programmatically determine which diagnostic is the root cause and which are cascade effects. This information exists in rustc's internal diagnostic structure but is lost when converted to LSP format.

Problem Description

The Cascade Error Problem

Consider this Rust code with a missing semicolon:

fn main() {
    let x = 10      // Missing semicolon
    let y = x + 1;  // Cascade error: "unexpected token"
}

rustc produces multiple diagnostics:

  1. expected ';', found keyword 'let' (line 2) - ROOT CAUSE
  2. unexpected token (line 3) - CASCADE EFFECT

If the developer fixes error #1, error #2 disappears automatically.

Current LSP Behavior

rust-analyzer correctly provides relatedInformation in diagnostics:

{
  "message": "borrow of moved value: `x`",
  "severity": 1,
  "relatedInformation": [
    {
      "location": { "uri": "file:///...", "range": {...} },
      "message": "value moved here"
    },
    {
      "location": { "uri": "file:///...", "range": {...} },
      "message": "move occurs because `x` has type `String`, which does not implement `Copy`"
    }
  ]
}

The problem: There's no way to programmatically know which related information is:

  • The cause of the error
  • Additional context (e.g., "defined here")
  • A suggestion for fixing
  • A cascade effect that will disappear when the root is fixed

Current Workaround (Fragile)

Tools must infer relationship types by parsing message text:

fn infer_relationship(message: &str) -> RelationshipType {
    let msg = message.to_lowercase();
    if msg.contains("defined here") { RelationshipType::Context }
    else if msg.contains("unexpected token") { RelationshipType::Effect }
    else if msg.contains("consider") { RelationshipType::Suggestion }
    else { RelationshipType::Unknown }
}

This breaks when rust-analyzer/rustc changes message wording.

Proposed Solution

Option 1: Add relationship field to relatedInformation (LSP Extension)

{
  "relatedInformation": [
    {
      "location": {...},
      "message": "value moved here",
      "relationship": "cause"
    },
    {
      "location": {...},
      "message": "consider borrowing here: `&`",
      "relationship": "suggestion"
    }
  ]
}

Possible values:

  • "cause" - This location caused the diagnostic
  • "effect" - This is a cascade effect (will disappear when root is fixed)
  • "context" - Additional context (e.g., "defined here", "first borrow occurs here")
  • "suggestion" - A fix suggestion

Option 2: Preserve rustc's children structure

rustc's JSON output already has this information via the level field:

{
  "children": [
    { "message": "...", "level": "note" },   // context
    { "message": "...", "level": "help" }    // suggestion
  ]
}

This could be mapped to LSP more explicitly.

Use Cases

  1. Error Deduplication in IDEs - Show only root causes by default
  2. AI-Assisted Debugging - AI tools can focus on root causes rather than cascade noise
  3. Error Prioritization - Sort errors by "fixability"
  4. Learning Tools - Help beginners understand error relationships
  5. CI/CD Error Reporting - Reduce noise in build logs

Implementation Notes

Data Already Exists

rustc internally tracks:

  • is_primary on spans (primary vs secondary)
  • children array with level (note/help/error)
  • Suggestion applicability

Backward Compatibility

  • New field is optional
  • Existing clients ignore unknown fields
  • No breaking changes

Related Work

  • Clang: Uses -ferror-limit and internal error recovery
  • TypeScript: Uses ErrorType poisoning to prevent cascade diagnostics
  • rustc JSON diagnostic format - Shows the rich structure available

Questions

  1. Is there appetite for LSP extensions, or should this be proposed to LSP spec?
  2. Would simply exposing rustc's level field be sufficient?
  3. Are there concerns about increased diagnostic payload size?

This feature would significantly improve developer experience by helping tools distinguish between errors that need fixing and errors that will fix themselves.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions