Skip to content

Analyzers: add an ErrorContextKey name/value-type conflict rule #239

Description

@Reefact

Problem

ErrorContextKey.Register throws InvalidOperationException at runtime when a literal name is re-registered with a different value type (ErrorContextKey.cs:139-147) — typically surfacing as an opaque TypeInitializationException in whichever assembly's static field initializes last, in code its author never touched. Two literal declarations with conflicting T in one compilation are statically detectable exactly the way FCE001 detects code collisions, but no rule exists.

Impact

A documented runtime crash that could be a build-time Error; the cheapest high-alignment rule available (the facts helper ErrorContextKeyFacts.TryGetCreatedKey, the CompilationEnd pattern, and the doc template all exist).

Direction

  • Compilation-end analyzer collecting (literal name → T) pairs via ErrorContextKeyFacts, reporting on same-name/different-type — the FCE001 pattern with a ConcurrentDictionary keyed by name. Error severity, on by default (it guards a runtime throw), CompilationEnd tag.
  • Use the next free FCE id (FCE019–FCE021 are taken by the in-flight Outcome.Try branch).
  • While in the area: document a key-namespacing convention and unify the three competing naming examples (PascalCase XML docs vs SCREAMING_SNAKE guide vs #-prefixed framework keys), reserving # for framework keys — see §9.3(c).

Acceptance criteria

  • Two same-name/different-T literal registrations in one compilation produce a build-time Error naming both sites; same-name/same-T stays silent.
  • Bilingual doc page, tests, README row — consistent with the suite.

Context

Surfaced by the 2026-07-20 architecture, design & ecosystem audit (doc/handwritten/for-maintainers/audit/2026-07-20-firstclasserrors-architecture-and-design-audit.md, §9.3(c)/§14-HV6; branch claude/firstclasserrors-audit-83gap7).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions