Class CallTargetResolution
CallDetailsBuilder) and the chained
object-access path (ObjectAccessInstrGenerator) so the two never re-derive - and drift on - the CALL
descriptor owner. See docs/ir-and-codegen/EK9_UNIFIED_CALL_TARGET_RESOLUTION_DESIGN.md.
Invariant (enforced by the JVM back-end): the descriptor owner type and isTraitCall move
TOGETHER - INVOKEINTERFACE iff the owner is an interface (trait / Any) - so a caller derives
BOTH from the SAME definingType(ISymbol, ISymbol): targetType = definingType and
isTraitCall = TraitCall.requiredFor(definingType) (never one from the defining type and the
other from the static receiver).
-
Method Summary
Modifier and TypeMethodDescriptionstatic ISymboldefiningType(ISymbol resolvedMethod, ISymbol staticType) The type that DECLARES the resolved method (its enclosing scope) - i.e.static booleanisNonDispatchableLifecycleMethod(String methodName) The compiler-synthesised LIFECYCLE methods, which are never dynamically dispatched: the constructor itself plusi_init(instance field initialisation) andc_init(class/static initialisation).static booleanisOpenAggregate(ISymbol type) Whether an aggregate type is open for extension (can have subclasses).static booleanisVirtualCall(ISymbol resolvedMethod, ISymbol targetType) Whether the call needs virtual (vtable) dispatch:falsefor constructors, private methods (cannot be overridden), and targets not open for extension (effectively final).static booleanisVirtualForSynthesisedCallee(ISymbol targetType) The dispatch flag for a call the compiler SYNTHESISED, where the callee type may not have been threaded through.
-
Method Details
-
definingType
The type that DECLARES the resolved method (its enclosing scope) - i.e. where its body is emitted. For an inherited method this is the PARENT, not the static receiver: the descriptor owner must name the declaring type because the native back-end resolves by the mangled(type, member)name and the body exists only on the declaring type (the JVM tolerates either spelling). Falls back tostaticTypewhen a defining scope cannot be determined. -
isVirtualCall
Whether the call needs virtual (vtable) dispatch:falsefor constructors, private methods (cannot be overridden), and targets not open for extension (effectively final). LLVM-only - the JVM back-end ignores the flag and always emits INVOKEVIRTUAL / INVOKEINTERFACE. -
isNonDispatchableLifecycleMethod
The compiler-synthesised LIFECYCLE methods, which are never dynamically dispatched: the constructor itself plusi_init(instance field initialisation) andc_init(class/static initialisation).Each
<init>must run ITS OWNi_init. Dispatching one dynamically would send a base constructor's field-initialisation call to the DERIVED body, running it against a half-built object whose own fields do not exist yet - and a base type must beas opento be extended at all, so openness alone says "virtual" for exactly the hierarchies where this breaks.These are NOT
CompilerPlumbingCallsplumbing: they have real symbols and measured complexity, so they DO carry a metadata clause. They are simply not dispatchable. Keeping the two ideas apart is the point - a site that needs "no metadata" and a site that needs "no dispatch" are different questions with different answers. -
isVirtualForSynthesisedCallee
The dispatch flag for a call the compiler SYNTHESISED, where the callee type may not have been threaded through. Openness is a property of the target type, so it is read from the symbol whenever one is in hand.When no symbol reached the site there is no honest source, and a boolean still has to be emitted.
falseis the answer that preserves the pre-existing rendering at those sites, so migrating a site to pass its symbol is visible as churn rather than being masked by a changed default. It is NOT a claim that the type is closed - prefer threading the symbol, exactly as the metadata pass did. -
isOpenAggregate
Whether an aggregate type is open for extension (can have subclasses). Traits are always "open" - implementations override them.
-