Class CallDetailsFactory

java.lang.Object
org.ek9lang.compiler.phase7.support.CallDetailsFactory

public final class CallDetailsFactory extends Object
THE factories for the recurring CallDetails shapes in IR generation - hold one (private final CallDetailsFactory callDetailsFactory = new CallDetailsFactory();) and call it.

CallDetails is a ten-argument record; the overwhelming majority of call sites build a non-virtual, non-trait, non-explicit-trait-default call (the trailing false, false, false). Constructor calls additionally repeat the type name three times (target object, target type and return type are all the constructed type) with the IRConstants.INIT_METHOD method. These factories single-source those shapes so the boolean tail and the type-name repetition are written once.

Sites that genuinely need a virtual / trait / explicit-trait-default call keep the explicit new CallDetails(...) so the non-default flags stay visible at the call site.

Every string-named factory here takes externallyLinked right after the type name it describes (IR lane F, Steve 2026-10-28): the value of CallDetails.isExternTarget, true exactly when that type is externally linked. There is no default - a type name does not say whether it is a user type. Pass DispatchFacts.externallyLinked(symbol) when the symbol is in hand, a TypeLinkage when only the name is, and true only for a runtime helper class or a core built-in constant (Boolean, Panic).

  • Constructor Details

    • CallDetailsFactory

      public CallDetailsFactory()
  • Method Details

    • call

      public CallDetails call(String targetObject, String targetTypeName, boolean externallyLinked, String methodName, List<String> parameterTypes, String returnTypeName, List<String> arguments, CallMetaDataDetails metaData)
      A non-virtual, non-trait call to methodName on targetObject.
      Parameters:
      targetObject - the receiver variable (or null for a static/free call)
      targetTypeName - the type that defines the method
      externallyLinked - that type is externally linked (IR lane F): from its symbol (DispatchFacts.externallyLinked) or its name (TypeLinkage)
      methodName - the (mangled) method name
      parameterTypes - the declared parameter types
      returnTypeName - the declared return type
      arguments - the argument variables
      metaData - purity / complexity / side-effect metadata, or null for a plumbing callee. Metadata supplied for a callee that CompilerPlumbingCalls identifies as plumbing is DROPPED - see below.
    • functionCall

      public CallDetails functionCall(String functionInstanceVar, String functionTypeName, boolean externallyLinked, List<String> parameterTypes, String returnTypeName, List<String> arguments, CallMetaDataDetails metaData, boolean isDelegateCall)
      THE shared shape for invoking a function through its _call method - use this rather than deciding the dispatch flag at each of the three sites that emit one.

      Dispatch here is NOT a question about the function type's openness. A concrete function type is closed, yet a DELEGATE invocation is polymorphic: the variable can hold any function of that signature, including a dynamic function, so the body is only known at run time. A NAMED function call is the opposite - it reaches a singleton whose body is statically known, and must be direct. The dispatch criterion is therefore a DISJUNCTION, and this is its second disjunct: (shape AND not-private AND targetOpen) OR isDelegateCall.

      isDelegateCall is not re-derived here - it is the DELEGATE_CALL marker phase 3 squirrelled onto the CallSymbol, which every caller has already read to decide whether to LOAD a variable or materialise a function singleton. Passing that same boolean keeps the receiver and the flag answering from one source.

      Parameters:
      isDelegateCall - the phase-3 DELEGATE_CALL marker: true for a delegate/chained invocation, false for a named singleton call
    • functionCall

      public CallDetails functionCall(String functionInstanceVar, String functionTypeName, boolean externallyLinked, List<String> parameterTypes, String returnTypeName, List<String> arguments, CallMetaDataDetails metaData, boolean isDelegateCall, boolean statementOwned)
      A function call made at a source call site, carrying phase 5's decision on whether the statement making it owns (and closes) the closeable it returns (support/MarkStatementOwned).
    • resolvedCall

      public CallDetails resolvedCall(String targetObject, DispatchFacts dispatch, String methodName, List<String> parameterTypes, String returnTypeName, List<String> arguments, CallMetaDataDetails metaData, boolean statementOwned)
      THE call to a callee whose dispatch was decided by DispatchFacts - the type it names, interface or not, virtual or not, extern or not all come from the facts, so a route never writes the four flags by hand.

      The metadata is passed through as given: the facts come from a resolved symbol (or a synthesised callee's type), and a callee with a symbol is never compiler plumbing.

      Parameters:
      targetObject - the receiver variable (super for a super call, null for a free call)
      dispatch - the dispatch facts of this call
      methodName - the (mangled) method name
      parameterTypes - the declared parameter types
      returnTypeName - the declared return type
      arguments - the argument variables
      metaData - the callee's purity / complexity / side-effect metadata
      statementOwned - phase 5's decision that the statement owns (and closes) the closeable returned
    • call

      public CallDetails call(String targetObject, ISymbol targetType, String methodName, List<String> parameterTypes, String returnTypeName, List<String> arguments, CallMetaDataDetails metaData)
      The same call, but taking the target type as a SYMBOL so BOTH the emitted type name and the virtual-dispatch flag derive from it - they then cannot disagree.

      The String overload hard-codes isVirtualCall = false, on the reasoning that a site "genuinely needing" a virtual call would build its own CallDetails. That framing is the root of a real defect: virtual dispatch is not a choice a call site makes, it is a PROPERTY of the target type (IsOpenAggregate). Treating it as a choice let the same type render both ways - Integer._eq appeared as virtual=true 83 times and without it 23 times. Prefer this overload wherever the caller holds the symbol; the flag is then derived once, from the same place the type name comes from.

      DO NOT migrate constructor or super-call sites onto this overload. It sees the target type but NOT the call-site shape, and dispatch is a function of both. An explicit super.m() or a <init> must be a DIRECT call; deriving from openness alone would make them virtual (a type must be as open to be extended at all), which on the LLVM back-end vtable-dispatches super.m() back to the override - infinite recursion. The two shapes it can see are vetoed below; callee privateness it cannot see at all, because CallDetails carries no access modifier. See docs/ir-and-codegen/EK9_IR_DERIVED_FACTS_REVIEW.md before using this more widely - the criterion is under review and this overload is deliberately NOT yet the answer.

      Parameters:
      targetType - the type that defines the method, as a resolved symbol
    • constructorCall

      public CallDetails constructorCall(String typeName, boolean externallyLinked, List<String> parameterTypes, List<String> arguments, CallMetaDataDetails metaData)
      A constructor call on typeName: target object, target type and return type are all typeName and the method is IRConstants.INIT_METHOD.
    • generatedConstructorCall

      public CallDetails generatedConstructorCall(String typeName, boolean externallyLinked, List<String> parameterTypes, List<String> arguments, CallMetaDataDetails metaData)
      A constructor call the compiler GENERATES inside a synthesised body (a constrained type's base value, copy and wrapping constructor): no target object, the type named and returned, the method IRConstants.INIT_METHOD, no dispatch, and the metadata as given.

      It differs from constructorCall(String, boolean, List, List, CallMetaDataDetails) in one rendered field: that one names the type as the target object too. The two are kept apart because unifying them moves every golden of the sites that use this one (a wave-4 decision); use this, never a literal new CallDetails(null, type, INIT_METHOD, ...).

    • constructorCall

      public CallDetails constructorCall(String typeName, boolean externallyLinked, List<String> parameterTypes, List<String> arguments, CallMetaDataDetails metaData, boolean statementOwned)
      A constructor call on typeName made at a source call site, carrying phase 5's decision on whether the statement making it owns (and closes) the closeable it makes (support/MarkStatementOwned).
    • defaultConstructorCall

      public CallDetails defaultConstructorCall(String typeName, boolean externallyLinked, CallMetaDataDetails metaData)
      The no-argument default constructor call on typeName.