Class Scenario2WrapperHelper
java.lang.Object
org.ek9lang.compiler.phase7.Scenario2WrapperHelper
Shared utilities for Scenario 2 wrapper IR generation.
Provides common operations needed by all Scenario 2 specialist generators:
- Temporary variable and scope ID generation
- Type name resolution from Ek9Types
- Operator name mapping (symbol to method name)
- Type erasure for delegation (finding base method parameter/return types)
- Basic block creation
- Delegate field load pattern
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescription(package private) static final recordTHE choice of the two calls a wrapper makes on its delegate to reach the contained value: the presence check and the accessor, which differ between Optional (_isSet/get) and Result (isOk/ok, orisError/errorforwhenError). -
Field Summary
FieldsModifier and TypeFieldDescription(package private) final ISymbol(package private) final String(package private) final Ek9Types(package private) final PossibleGenericSymbol(package private) final SynthesisedCallMetaData(package private) final String -
Constructor Summary
ConstructorsConstructorDescriptionScenario2WrapperHelper(Ek9Types ek9Types, IRContext baseContext, PossibleGenericSymbol parameterizedAggregate) One helper per wrapper. -
Method Summary
Modifier and TypeMethodDescription(package private) booleanTrue iff the wrapped base generic is DictEntry, whose no-argument constructor must supply an unset V (decision 11, docs/language-design/EK9_ABSENCE_UNOBSERVABLE.md).(package private) booleanTrue iff the wrapped base generic is Iterator, whose?is "can it give a next item": the wrapper's ownhasNext(), dispatched, never the delegate's - a type extending the wrapper has no meaningful delegate, and its ownhasNext()is the answer.(package private) booleanTrue iff the wrapped base generic is Result — its_eqcompares the contained value via Javaequals(), so the wrapper must value-extract rather than delegate.(package private) voidBegin generating one wrapper operation: its temps, scope ids and labels are numbered afresh, exactly asIRGenerationContext.enterMethodScopenumbers every other operation's.(package private) voidA value this scope does not own - a LOAD of a field or parameter, or a CAST alias of a value owned elsewhere - borrowed for the scope:OwnershipStatements.borrowInScope(String, String, DebugInfo).(package private) StringcastBorrowed(List<IRInstr> instructions, String value, String typeName, String scopeId, DebugInfo debugInfo) A value this scope does not own, CAST totypeNameand the cast borrowed for the scope (a parameter given asAny).(package private) StringcastWhenThisWrapper(List<IRInstr> instructions, String operandName, String notThisWrapperLabel, String scopeId, DebugInfo debugInfo) THE test of an operand declaredAnyfor being exactly THIS wrapper, and its cast when it is - shared by wrapper equality (Scenario2EqualityGenerator) and every other operator the generic declares as takingAny(Scenario2AggregateWrapperGenerator, D60:DictEntry <=> Any).(package private) booleancontainedTypeHasOperator(ISymbol type, String operatorGlyph) Whether the contained (element) type has a REAL binaryoperatorGlyph(==,<>) - its own, a super's or a trait's, never only the degenerateAnyone.(package private) Scenario2WrapperHelper.ContainerAccesscontainerAccess(String forMethod) The presence check and accessor to use for the wrapper methodforMethod.(package private) BasicBlockInstrcreateBasicBlock(List<IRInstr> instructions) (package private) DebugInfo(package private) booleanWhether a parameterised wrapper's equality should DELEGATE to the base type's own_eqrather than extract-and-compare the contained value.(package private) StringemitVirtualCall(List<IRInstr> instructions, String targetVar, String targetType, ISymbol targetTypeSymbol, String methodName, List<String> paramTypes, String returnType, List<String> argNames, DebugInfo debugInfo) A virtual method call whose result (+1) the caller states the owner of itself - it casts it (ownedCast(List, String, String, String, DebugInfo)) or moves it.(package private) StringextractPrimitiveBoolean(List<IRInstr> instructions, String booleanVar, DebugInfo debugInfo) Extract primitive boolean from Boolean object via _true() method.(package private) MethodSymbolThe generic template's method a wrapper method was cloned from - READ what phase 6 encoded, never re-derived.(package private) StringgenerateConstructorCall(List<IRInstr> instructions, ISymbol type, boolean externallyLinked, String typeName, List<String> paramTypes, List<String> argNames, DebugInfo debugInfo) A constructor call whose new value (+1) the caller states the owner of itself (it moves it).(package private) StringgenerateConstructorCallInstructions(List<IRInstr> instructions, ISymbol type, String typeName, List<String> paramTypes, List<String> argNames, String scopeId, DebugInfo debugInfo) Generate a constructor call on a type: the new value (+1) is owned by the scope, dropped at its exit.(package private) StringgenerateLabelName(String prefix) A label of the operation:_<prefix>_<n>.(package private) StringgenerateProducerVirtualCall(List<IRInstr> instructions, String targetVar, String targetType, ISymbol targetTypeSymbol, String methodName, List<String> paramTypes, String returnType, List<String> argNames, String scopeId, DebugInfo debugInfo) Generate a virtual method call whose result is a +1 PRODUCER — a value-method or operator that hands back a freshly-owned object (e.g.(package private) StringgenerateScopeId(String prefix) A scope id of the operation:_scope_<name>_<n>(ShouldRegisterVariableInScopekeys on the_scope_form), the operator's method name for an operator.(package private) String(package private) StringgenerateUnsetBoolean(List<IRInstr> instructions, String scopeId, DebugInfo debugInfo) Generate an unset Boolean constructor call.(package private) StringGet the parameter types from the BASE generic type's method, not the substituted version.(package private) StringgetBaseMethodReturnType(MethodSymbol method) Get the return type from the BASE generic type's method, not the substituted version.(package private) String(package private) String(package private) String(package private) String(package private) booleanWhethertype()can be called here to make an unset value of it: a concrete aggregate with a public no-argument constructor.(package private) booleanIs this the built-in Any (by symbol identity, never by name)?(package private) booleanisBareConceptualOnTemplate(ISymbol templateDeclaredType) True when the generic template declared this position as a bare conceptual type parameter (T), as opposed to a parameterisation such as Iterator of T or Comparator of T.(package private) booleanTHE shared check for "is this a parameterised BUILT-IN generic that carries a rawdelegate" — one whose value must be UNWRAPPED via.delegateon store and RE-WRAPPED on return / at a callback edge.(package private) booleanTHE shared check for "is this type a parameterisation of a generic FUNCTION" (e.g.(package private) booleanisThisWrapper(ISymbol type) Is this exactly THIS wrapper's type (parameterised wrappers are closed: a different parameterisation of the same generic is a different type)?(package private) booleanIs this the built-in Void (by symbol identity)? An absent type is a void return.(package private) StringThe delegate ofwrapperVar, a value of THIS wrapper's type, borrowed for the scope.(package private) StringloadDelegate(List<IRInstr> instructions, String scopeId, DebugInfo debugInfo) This wrapper's own delegate (this.delegate), borrowed for the scope.(package private) StringloadDelegateOf(List<IRInstr> instructions, String wrapperVar, String wrapperType, String delegateFieldType, String scopeId, DebugInfo debugInfo) THE delegate load of the Scenario-2 wrappers: a wrapper value'sdelegatefield, borrowed for the scope (DelegateLoad, shared with the constrained types).(package private) voidA value just made (+1) that this scope owns and drops at its exit:OwnershipStatements.droppedAtExit(String, String, DebugInfo).(package private) StringownedCast(List<IRInstr> instructions, String value, String typeName, String scopeId, DebugInfo debugInfo) A value just made (+1), cast totypeName: the CAST takes the value's count (V-D) and the scope owns the cast, dropping it at exit - one count, one drop, whichever name holds the object.(package private) StringrawDelegateTypeName(PossibleGenericSymbol parameterizedType) The RAW type a built-in parameterised value is held as - its generic (List of Integer->List).(package private) voidreturnFresh(List<IRInstr> instructions, String value, DebugInfo debugInfo) A value just made (+1), moved into the return variable (empty here):OwnershipStatements.returnFresh(String, String, DebugInfo)- the caller receives the producer's count.(package private) voidreturnVirtualCall(List<IRInstr> instructions, String targetVar, String targetType, ISymbol targetTypeSymbol, String methodName, List<String> paramTypes, String returnType, List<String> argNames, String scopeId, DebugInfo debugInfo) A virtual method call whose result (+1) is moved straight into the return variable: the method hands its caller exactly the count the callee handed it.(package private) StringrewrapRawDelegate(List<IRInstr> instructions, String rawVar, PossibleGenericSymbol wrapper, String scopeId, DebugInfo debugInfo) THE wrap of a RAW delegate value back into its built-in parameterised wrapper (the inverse ofunwrapDelegate(List, String, PossibleGenericSymbol, String, DebugInfo)):wrapper(rawVar), the new wrapper owned by the scope.(package private) voidstoreDelegateField(List<IRInstr> instructions, String value, DebugInfo debugInfo) The wrapper's delegate field, its first store in a constructor: the field takes its own reference to a value the constructor's scope still owns (FIELD_ASSIGN [copy, init]).(package private) voidstoreUnsetBooleanReturn(List<IRInstr> instructions, String scopeId, DebugInfo debugInfo) An unset Boolean as the return value: made, and moved into the return variable (empty here).(package private) StringtoMethodName(String operatorOrMethodName) Convert operator symbols to their mapped method names for use in IR.(package private) StringTHE IR name of a type in a Scenario-2 wrapper: its fully qualified name.(package private) StringunwrapDelegate(List<IRInstr> instructions, String wrapperVar, PossibleGenericSymbol parameterizedType, String scopeId, DebugInfo debugInfo) Load the raw delegate out of a built-in parameterised wrapper value (List of Integer-> itsList), for a base-type call that takes the raw type, borrowed for the scope.
-
Field Details
-
ek9Types
-
parameterizedAggregate
-
wrapperTypeName
-
delegateType
-
delegateTypeName
-
synthesisedCallMetaData
-
-
Constructor Details
-
Scenario2WrapperHelper
Scenario2WrapperHelper(Ek9Types ek9Types, IRContext baseContext, PossibleGenericSymbol parameterizedAggregate) One helper per wrapper.- Parameters:
ek9Types- the built-in typesbaseContext- the generation's IR context, copied for each operation's namesparameterizedAggregate- the parameterised type the wrapper is generated for
-
-
Method Details
-
beginOperation
void beginOperation()Begin generating one wrapper operation: its temps, scope ids and labels are numbered afresh, exactly asIRGenerationContext.enterMethodScopenumbers every other operation's. -
generateTempName
String generateTempName() -
generateScopeId
-
generateLabelName
-
toMethodName
-
createDebugInfo
DebugInfo createDebugInfo() -
createBasicBlock
-
typeName
-
getBooleanTypeName
String getBooleanTypeName() -
getVoidTypeName
String getVoidTypeName() -
getStringTypeName
String getStringTypeName() -
getIntegerTypeName
String getIntegerTypeName() -
isAny
Is this the built-in Any (by symbol identity, never by name)? -
getAnyTypeName
String getAnyTypeName() -
isVoid
Is this the built-in Void (by symbol identity)? An absent type is a void return. -
isThisWrapper
Is this exactly THIS wrapper's type (parameterised wrappers are closed: a different parameterisation of the same generic is a different type)? -
rawDelegateTypeName
The RAW type a built-in parameterised value is held as - its generic (List of Integer->List). -
loadDelegateOf
String loadDelegateOf(List<IRInstr> instructions, String wrapperVar, String wrapperType, String delegateFieldType, String scopeId, DebugInfo debugInfo) THE delegate load of the Scenario-2 wrappers: a wrapper value'sdelegatefield, borrowed for the scope (DelegateLoad, shared with the constrained types).delegateVar = LOAD_FIELD wrapperVar.delegate (wrapperType -> delegateType) borrowed in scopeId
-
loadDelegate
-
loadDelegate
-
unwrapDelegate
String unwrapDelegate(List<IRInstr> instructions, String wrapperVar, PossibleGenericSymbol parameterizedType, String scopeId, DebugInfo debugInfo) Load the raw delegate out of a built-in parameterised wrapper value (List of Integer-> itsList), for a base-type call that takes the raw type, borrowed for the scope. -
rewrapRawDelegate
String rewrapRawDelegate(List<IRInstr> instructions, String rawVar, PossibleGenericSymbol wrapper, String scopeId, DebugInfo debugInfo) THE wrap of a RAW delegate value back into its built-in parameterised wrapper (the inverse ofunwrapDelegate(List, String, PossibleGenericSymbol, String, DebugInfo)):wrapper(rawVar), the new wrapper owned by the scope. A built-in container holds a parameterised element as its raw delegate, so it is wrapped again wherever it is handed out as the element type - the callback edge and the_call(Any...)bridge. -
castBorrowed
-
borrow
-
owned
-
ownedCast
-
returnFresh
A value just made (+1), moved into the return variable (empty here):OwnershipStatements.returnFresh(String, String, DebugInfo)- the caller receives the producer's count. -
storeDelegateField
-
castWhenThisWrapper
String castWhenThisWrapper(List<IRInstr> instructions, String operandName, String notThisWrapperLabel, String scopeId, DebugInfo debugInfo) THE test of an operand declaredAnyfor being exactly THIS wrapper, and its cast when it is - shared by wrapper equality (Scenario2EqualityGenerator) and every other operator the generic declares as takingAny(Scenario2AggregateWrapperGenerator, D60:DictEntry <=> Any). EXACT: parameterised wrappers are closed, so a different parameterisation of the same generic is a different type and is NOT this wrapper. The callers differ only in where a value that is not this wrapper goes (notThisWrapperLabel). This wrapper's form of THE sharedWrapperGivenAsAny.castWhenExactly(List, Supplier, String, String, String, String, DebugInfo).isWrapper = INSTANCE_OF_EXACT operand, wrapperType BRANCH_FALSE isWrapper, notThisWrapperLabel casted = CAST operand -> wrapperType RETAIN casted SCOPE_REGISTER casted, scopeId
- Returns:
- the variable holding the operand cast to this wrapper (valid only on the fall-through path)
-
generateConstructorCallInstructions
String generateConstructorCallInstructions(List<IRInstr> instructions, ISymbol type, String typeName, List<String> paramTypes, List<String> argNames, String scopeId, DebugInfo debugInfo) Generate a constructor call on a type: the new value (+1) is owned by the scope, dropped at its exit. A caller that keeps it states that itself - a field store copies it, a return moves it. A GENERATED wrapping constructor takes its own reference to its argument, as a PRE_BUILT one does, so the argument needs no extra count. -
generateConstructorCall
-
returnVirtualCall
void returnVirtualCall(List<IRInstr> instructions, String targetVar, String targetType, ISymbol targetTypeSymbol, String methodName, List<String> paramTypes, String returnType, List<String> argNames, String scopeId, DebugInfo debugInfo) A virtual method call whose result (+1) is moved straight into the return variable: the method hands its caller exactly the count the callee handed it. (A RETAIN as a "borrow" of the result and the return's own RETAIN handed it back at +2 - a leak on every call of a function wrapper's_call,_eqand_isSet.) -
generateProducerVirtualCall
String generateProducerVirtualCall(List<IRInstr> instructions, String targetVar, String targetType, ISymbol targetTypeSymbol, String methodName, List<String> paramTypes, String returnType, List<String> argNames, String scopeId, DebugInfo debugInfo) Generate a virtual method call whose result is a +1 PRODUCER — a value-method or operator that hands back a freshly-owned object (e.g.Result.isOk()returns a NEW Boolean;Result.ok()ek9_retains the stored value before returning, so the caller receives it at +1). Per the uniform +1 ARC ownership-transfer convention (THE authority:VariableMemoryManagement— a CALL result is owned), the scope owns it and its exit consumes the +1. An additional RETAIN (the borrow form) hands the value back at +2, so the single scope-exit release leaves +1 and leaks it once per invocation. Use this for internal producer call results consumed within the method body; a result that IS the method's return goes throughreturnVirtualCall(List, String, String, ISymbol, String, List, String, List, String, DebugInfo). -
emitVirtualCall
String emitVirtualCall(List<IRInstr> instructions, String targetVar, String targetType, ISymbol targetTypeSymbol, String methodName, List<String> paramTypes, String returnType, List<String> argNames, DebugInfo debugInfo) A virtual method call whose result (+1) the caller states the owner of itself - it casts it (ownedCast(List, String, String, String, DebugInfo)) or moves it. -
extractPrimitiveBoolean
-
storeUnsetBooleanReturn
-
generateUnsetBoolean
-
containedTypeHasOperator
Whether the contained (element) type has a REAL binaryoperatorGlyph(==,<>) - its own, a super's or a trait's, never only the degenerateAnyone. THE test isHasRealOperator; this once scanned the element's own scope only, so an INHERITED==made the wrapper's==a constant UNSET (B18 prerequisite P1). -
delegatesBaseEquality
boolean delegatesBaseEquality()Whether a parameterised wrapper's equality should DELEGATE to the base type's own_eqrather than extract-and-compare the contained value.Collections (List/Dict/PriorityQueue) compare element-wise and MutexLock compares by IDENTITY — in both cases the base type's own
_eqalready yields the correct wrapper semantics, so we delegate. Only the single-value containers (Optional, Result) need value-extraction, because their_eqcompares the contained value via Javaequals()(which bypasses the EK9 contained type's_eq). MutexLock additionally exposes NO value accessor (noget()), so the extraction path would emit a call to a non-existentMutexLock.get()— fine on the JVM (the method is never invoked) but an undefined-symbol LINK failure on the eagerly-linked native backend. -
baseIsResult
boolean baseIsResult()True iff the wrapped base generic is Result — its_eqcompares the contained value via Javaequals(), so the wrapper must value-extract rather than delegate. Symbol identity. -
baseIsIterator
boolean baseIsIterator()True iff the wrapped base generic is Iterator, whose?is "can it give a next item": the wrapper's ownhasNext(), dispatched, never the delegate's - a type extending the wrapper has no meaningful delegate, and its ownhasNext()is the answer. Symbol identity. -
containerAccess
The presence check and accessor to use for the wrapper methodforMethod. -
baseIsDictEntry
boolean baseIsDictEntry()True iff the wrapped base generic is DictEntry, whose no-argument constructor must supply an unset V (decision 11, docs/language-design/EK9_ABSENCE_UNOBSERVABLE.md). Symbol identity. -
hasPublicNoArgConstructor
Whethertype()can be called here to make an unset value of it: a concrete aggregate with a public no-argument constructor. False for a trait, an abstract type, a function, or a type whose no-argument constructor is private or absent (FE39) - none of those has an unset value a wrapper can make. -
getBaseMethodParameterTypes
Get the parameter types from the BASE generic type's method, not the substituted version. -
getBaseMethodReturnType
Get the return type from the BASE generic type's method, not the substituted version. -
isFunctionParameterisation
THE shared check for "is this type a parameterisation of a generic FUNCTION" (e.g. Supplier of String, Comparator of T) — use this in the Scenario-2 generators rather than re-deriving the instanceof chain. -
isDelegatingParameterisedType
THE shared check for "is this a parameterised BUILT-IN generic that carries a rawdelegate" — one whose value must be UNWRAPPED via.delegateon store and RE-WRAPPED on return / at a callback edge. True for Scenario-1 (pre-built) and Scenario-2 (extern delegation) wrappers; FALSE for a user-defined (Scenario-3) generic, whose monomorphised class IS the value and has NOdelegatefield. Unwrapping a Scenario-3 value via.delegatethrowsNoSuchFieldError, and re-wrapping it needs a wrapping constructor it does not have. Every unwrap/re-wrap gate in the Scenario-2 generators must use THIS rather than bareisParameterisedType()(which is true for all three scenarios), so a built-in container over a user generic element stores/retrieves it directly. -
isBareConceptualOnTemplate
True when the generic template declared this position as a bare conceptual type parameter (T), as opposed to a parameterisation such as Iterator of T or Comparator of T. Mirrors the discrimination used by getBaseMethodParameterTypes/getBaseMethodReturnType. -
findOriginalMethodOnGenericTemplate
The generic template's method a wrapper method was cloned from - READ what phase 6 encoded, never re-derived.TypeSubstitutionclones the template's methods one-for-one and records the correspondence on each clone (setGenericTemplateMethod), and every Scenario-2 wrapper method is such a clone (the hidden_sinkBuffer()records a stand-in). A method without one is a compiler defect, reported as one: the shape comparison that used to stand behind this could not separate+=(T)from+=(List of T)once T is substituted, and it never ran (MONO-12: proved by this throw over compiler-main and -Pfuzz before it went).
-