Class OperatorTargetMethodResolver
aggregate.resolveMember(new MethodSymbolSearch(name)) silently gets wrong (see the
dual-glyph note below), and every phase-7 site that needs a resolved callee - whether to read its
defining type or to read its CallMetaDataDetails - must go through here.
Uses resolveMember with the argument types so SymbolMatcher finds the correct overload -
including coercible (promotable) matches, e.g. Float._addAss(Float) for f += celsius
where Celsius promotes to Float. The symbol table keys operator methods by EK9 name
(":=:"), so the JVM method name ("_copy") is reverse-mapped for the search. A
non-operator method name (e.g. iterator, hasNext) is searched as given.
Negate is dual-glyph. The JVM method _negate is aliased by TWO EK9 operators: ~
(declared by Boolean/Bits/List/Colour as operator ~) and the zero-arg unary - (declared
by the numeric types as operator -, split from binary _sub by arity in phase 2's
ValidOperatorOrError.minusOperatorOrError). OperatorMap.getBackward("_negate") only
yields ~ (the - key is taken by binary _sub), so a ~ search misses on a
numeric type whose negate is stored under -. This mirrors, in reverse, the one-way
-/not -> ~ normalisation that UnaryOperationGenerator does on the way
in: on a ~ miss for a zero-arg call, retry the unary -. A zero-parameter search matches
ONLY the unary - (SymbolMatcher rejects arity mismatch), never binary _sub.
Without this the dispatch/defining type silently falls back to the static receiver - correct for the
on-receiver common case, but a wrong, never-emitted symbol for an INHERITED numeric negate on the
eagerly-linked native back-end (the cea4d156c defining-type remedy otherwise no-ops here).
Not-equals is dual-glyph as well. <> and != both map to _neq;
OperatorMap.getBackward("_neq") yields != (registered last), but types DECLARE
operator <>, so a != miss retries <>. Without it every synthesised _neq
fell back to the static receiver - a never-emitted symbol for an INHERITED <> natively.
A call resolved on a generic's bare T is resolved again on the type argument. Phase 3
resolves an operator in a generic body against the conceptual T, whose operators are synthesised
as T._cmp(T). Inside a monomorphisation T stands for a real type, and the member that
serves the call is that type's - possibly INHERITED from a super (Base._cmp(Base) for a
Kid that declares none, D53) or declared on a TRAIT, which needs an interface call (D54). See
onTypeArgument(ScopedSymbol, UnaryOperator).
- See Also:
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionResolve a method/operator on the target type, returning the resolved symbol itself (not just type names), so callers can read its defining type, return type and metadata rather than re-deriving them.declaredParameterTypes(ISymbol targetType, String methodName, List<ISymbol> argumentTypes) THE declared parameter types of the operator/method that actually serves a call - read off the RESOLVED member, never copied from the arguments.declaredParameterTypes(ISymbol targetType, String methodName, List<ISymbol> argumentTypes, UnaryOperator<ISymbol> typeArgumentOf) declaredParameterTypes(ISymbol, String, List)inside a monomorphisation: the parameter types the member that SERVES the call declares (servingMember(ISymbol, String, List, UnaryOperator)), so a call a generic body makes on its bareTnames the type argument's operator, never the template'sT._cmp(T)(D53).onTypeArgument(ScopedSymbol templateMember, UnaryOperator<ISymbol> typeArgumentOf) THE member that serves, inside a monomorphisation, a call phase 3 resolved on a generic's bareT.servingMember(ISymbol targetType, String methodName, List<ISymbol> argumentTypes, UnaryOperator<ISymbol> typeArgumentOf) apply(ISymbol, String, List)followed byonTypeArgument(ScopedSymbol, UnaryOperator): the member that serves the call, read off the type argument when the call is resolved on a generic's bareTinside a monomorphisation.
-
Constructor Details
-
OperatorTargetMethodResolver
public OperatorTargetMethodResolver()
-
-
Method Details
-
apply
public Optional<ScopedSymbol> apply(ISymbol targetType, String methodName, List<ISymbol> argumentTypes) Resolve a method/operator on the target type, returning the resolved symbol itself (not just type names), so callers can read its defining type, return type and metadata rather than re-deriving them.- Parameters:
targetType- the type the call is made ON (a non-aggregate never resolves)methodName- the JVM method name (_copy) or the EK9 name (:=:) or a plain method name (iterator)argumentTypes- the resolved argument types, driving overload selection- Returns:
- the resolved method, or empty when the target is not an aggregate or declares no such member
-
declaredParameterTypes
public Optional<List<ISymbol>> declaredParameterTypes(ISymbol targetType, String methodName, List<ISymbol> argumentTypes) THE declared parameter types of the operator/method that actually serves a call - read off the RESOLVED member, never copied from the arguments. Use this - do not re-derive it. An operator may take a WIDER type than the argument (its trait, a super,Any), and the call must name the declared descriptor: naming the argument's type asks for a method that does not exist - aNoSuchMethodError C2._cmp(C3)on the JVM forc2 >? c3over a trait's<=>(B18 prerequisite P2), an undefined symbol natively. Shared by the synthesised comparisons, the Scenario-2 wrapper equality and comparison coalescing.- Parameters:
targetType- the type the call is made ONmethodName- the JVM or EK9 name, as forapply(ISymbol, String, List)argumentTypes- the resolved argument types- Returns:
- the declared parameter types, or empty when nothing resolves
-
declaredParameterTypes
public Optional<List<ISymbol>> declaredParameterTypes(ISymbol targetType, String methodName, List<ISymbol> argumentTypes, UnaryOperator<ISymbol> typeArgumentOf) declaredParameterTypes(ISymbol, String, List)inside a monomorphisation: the parameter types the member that SERVES the call declares (servingMember(ISymbol, String, List, UnaryOperator)), so a call a generic body makes on its bareTnames the type argument's operator, never the template'sT._cmp(T)(D53).- Parameters:
typeArgumentOf- the substitution of the monomorphisation in progress (IRGenerationContext::resolveType); the identity outside one
-
servingMember
public Optional<ScopedSymbol> servingMember(ISymbol targetType, String methodName, List<ISymbol> argumentTypes, UnaryOperator<ISymbol> typeArgumentOf) apply(ISymbol, String, List)followed byonTypeArgument(ScopedSymbol, UnaryOperator): the member that serves the call, read off the type argument when the call is resolved on a generic's bareTinside a monomorphisation. A site that names a call's owner or parameter types itself (rather than throughCallDetailsBuilder) uses this.- Parameters:
typeArgumentOf- the substitution of the monomorphisation in progress (IRGenerationContext::resolveType); the identity outside one
-
onTypeArgument
public Optional<ScopedSymbol> onTypeArgument(ScopedSymbol templateMember, UnaryOperator<ISymbol> typeArgumentOf) THE member that serves, inside a monomorphisation, a call phase 3 resolved on a generic's bareT. Use this - do not re-derive it. The generic body is generated once per parameterisation from ONE template-typed AST, so the recorded callee is the conceptualT's synthesised operator, declared ONTand TAKINGT. Substituting the type argument into that template signature names a method that need not exist:compared() of KidcalledKid._cmp(Kid)where the operatorKidhas isBase._cmp(Base)(aNoSuchMethodError, D53), andcompared() of Sizedcalled a trait's operator as a class method (anIncompatibleClassChangeError, D54). The descriptor - owner, declared parameter types, return type, and whether the owner is an interface - must be read off the member that ACTUALLY serves it, found here by resolving the same operator on the type argument.- Parameters:
templateMember- the callee phase 3 recorded (possibly a member of a bareT)typeArgumentOf- the substitution of the monomorphisation in progress (IRGenerationContext::resolveType); the identity outside one- Returns:
- the member of the type argument, or empty when the callee is not a member of a bare
T, the substitution leavesTas it is, or nothing resolves (a function type argument, say)
-