Skip to content

[index] TastyIndexer.mkSymbolId NonFatal fallback hard-codes isType=false #71

Description

@rochala

Severity: medium — crash paths silently violate the type-vs-term invariant established by Phase 1.

Symptom

TastyIndexer.mkSymbolId:

def mkSymbolId(sym: Symbol): SymbolId =
  try {
    val isType = isTypeLike(sym)
    val name = stripDollar(sym.name)
    val (pkg, owners) = collectOwners(sym.maybeOwner)
    SymbolId.fromTasty(pkg, owners, name, isType)
  } catch {
    case NonFatal(_) =>
      try SymbolId.fromTasty(Nil, Nil, stripDollar(sym.name), isType = false)
      catch { case NonFatal(_) => SymbolId(Nil, Nil, "<unknown>", None) }
  }

The fallback hard-codes isType = false. If isTypeLike succeeds (correctly classifying a class as a type) but collectOwners throws (e.g. broken owner chain in best-effort TASTy), the catch promotes the class to a term id.

Concrete failure

A transient TASTy error inside collectOwners while indexing class Foo produces term(Nil, Nil, "Foo") instead of tpe(...). Downstream queries against the correct tpe(...) miss; the orphan term id pollutes getSubtypes / getReferences.

The <unknown> second-fallback is also a collision risk — every fully-broken symbol coalesces under one id.

Fix

Compute isType outside the try so it survives collectOwners failures:

def mkSymbolId(sym: Symbol): SymbolId = {
  val isType = try isTypeLike(sym) catch { case NonFatal(_) => false }
  try {
    val name = stripDollar(sym.name)
    val (pkg, owners) = collectOwners(sym.maybeOwner)
    SymbolId.fromTasty(pkg, owners, name, isType)
  } catch {
    case NonFatal(_) =>
      try SymbolId.fromTasty(Nil, Nil, stripDollar(sym.name), isType)
      catch { case NonFatal(_) => SymbolId(Nil, Nil, "<unknown>", None) }
  }
}

Separately, consider whether <unknown> should be replaced with something less collision-prone — e.g. include the source-file URI in the synthetic name, or skip the symbol entirely.

Acceptance criteria

  • Unit test: inject a Symbol whose collectOwners throws but isTypeLike succeeds; verify the produced SymbolId has the right type/term shape

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    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