Class LockIdentityInference

java.lang.Object
org.ek9lang.compiler.phase5.flow.LockIdentityInference

public final class LockIdentityInference extends Object
Primitives layer for slice-2 lock-identity tracking — mints opaque Object tokens for MutexLock allocation sites, returns the ISymbol reference as token for field/parameter/capture-rooted identities, and produces stable string IDs for cross-record / wire-format use.

Used by the LockAnalysisListener (Phase B.1) to assign and propagate LockIdentityValue entries through the ValueTrackingAnalyzer state during the AST walk.

Identity discipline: tokens are compared by Java == reference equality. Two distinct calls to mintAllocationToken(IToken) for different source locations always produce different tokens, even if the resulting LockIdentityValues look superficially similar. The tokenForSymbol(ISymbol) path returns the symbol itself as the token, so all call sites resolving to the same ISymbol share one conceptual identity.

Caching: mintAllocationToken(IToken) caches per source location, so revisiting the same MutexLock(...) constructor expression returns the same Object reference and thus the same conceptual identity. The cache is per-LockIdentityInference instance, which lives per function/source pass (or longer if reused across passes).

Stable IDs: stableIdFor(Object, IdentityOrigin) encodes the token into a deterministic string suitable for foreign-key references in the LockAnalysis schema and for JSON output to MCP consumers. The encoding is canonical for a given token+origin pair within a compilation; it is not stable across compiles or across workspaces (intentional — the analysis is transient).

  • Constructor Details

    • LockIdentityInference

      public LockIdentityInference()
  • Method Details

    • mintAllocationToken

      public Object mintAllocationToken(IToken siteLocation)
      Mint (or return cached) opaque identity token for a MutexLock(...) constructor call at the given source location.

      Subsequent calls with the same location key return the same Object reference, so multiple analyses of the same call site agree on identity.

      Parameters:
      siteLocation - source token of the constructor call expression. Must be non-null.
      Returns:
      opaque identity token (always non-null).
    • tokenForSymbol

      public Object tokenForSymbol(ISymbol symbol)
      Return an identity token for a field, parameter, or capture receiver.

      Parameters mint a PlaceholderToken keyed by the parameter's fully-qualified name. The placeholder is resolved at each call site during inter-procedural propagation (Phase C.2) — the static analogue of "fill the slot when you push the next stack frame." Two placeholders for the same parameter FQN compare equal (structural equality on PlaceholderToken.paramFqn), so propagation and fixpoint iteration see consistent identities across passes.

      Fields and captures return the ISymbol reference itself. Per EK9's A.4 freshness constraint a field's symbol is 1:1 with the allocation that initialised it, so the symbol's identity (==) is a safe stand-in for the underlying object identity. Captures similarly preserve the outer symbol's identity (callers should unwrap via unwrapCapture(ISymbol, IScopedSymbol) before requesting a token).

      Parameters:
      symbol - the field / parameter / capture symbol. Must be non-null.
      Returns:
      a PlaceholderToken for incoming parameters, or the symbol itself for fields and captures.
    • resolveParamSymbol

      public ISymbol resolveParamSymbol(String paramFqn)
      Resolve the original parameter ISymbol for a placeholder FQN, if one has been registered via tokenForSymbol(ISymbol).

      Used by consumers that need the parameter's declaration site (name + source token) rather than the alias variable that happened to be in scope when an identity was first resolved at an enter call site.

      Parameters:
      paramFqn - fully-qualified parameter name as carried on the PlaceholderToken.
      Returns:
      the original parameter symbol, or null if no token has been minted for this FQN through this inference instance.
    • unwrapCapture

      public ISymbol unwrapCapture(ISymbol symbol, IScopedSymbol enclosingFunction)
      Like tokenForSymbol(ISymbol) but unwraps one level of dynamic-function capture: if the symbol is one of enclosingFunction's captured variables, resolve the same-named variable in the CaptureScope's enclosing scope and use that outer symbol's identity instead.

      Why: EK9's DynamicCaptureOrError creates a fresh VariableSymbol in the CaptureScope when a variable is captured into a lambda. That fresh symbol has a different ISymbol identity than the outer variable being captured, so naive tokenForSymbol would treat the same conceptual lock as two distinct identities. The C.3 verdict would then over-flag legitimate reentrant patterns (positive case) and fail to recognise same-lock-cross-thread patterns (E08253 case).

      Scope: first-cut handles one level of capture. Deep-nested lambdas (lambda-in-lambda-in-method) where the outer is itself a capture would need iterative unwrapping; tracked as a known limitation.

      Parameters:
      symbol - the receiver symbol resolved inside the lambda body.
      enclosingFunction - the immediate enclosing function/method when symbol was resolved (i.e. the dynamic function containing the receiver reference).
      Returns:
      the outer ISymbol if the receiver is a single-level capture; symbol itself otherwise.
    • lockIdentityValueFor

      public LockIdentityValue lockIdentityValueFor(Object token)
      Wrap a token in a LockIdentityValue for assignment to the analyzer state via ValueTrackingAnalyzer.recordAssignment.
      Parameters:
      token - the opaque identity token (typically obtained via mintAllocationToken(IToken) or tokenForSymbol(ISymbol)).
      Returns:
      a new LockIdentityValue carrying the token.
    • stableIdFor

      public String stableIdFor(Object token, IdentityOrigin origin)
      Produce a deterministic string identifier for the given token, suitable for foreign-key references in the LockAnalysis schema and for JSON output to MCP consumers.

      Encoding by origin:

      Parameters:
      token - the opaque identity token.
      origin - how the token was sourced; controls the encoding prefix.
      Returns:
      stable string identifier; never null.