Class ConstructorThisEscapeOrError
- All Implemented Interfaces:
BiConsumer<EK9Parser.ParamExpressionContext, ISymbol>
Eliminates publication-during-construction races: if 'this' escapes to a thread-spawning receiver (or any receiver that retains the reference) before the constructor has finished initialising fields, another thread can observe partially-initialised state.
Passing 'this' to a PURE receiver is permitted — pure functions have no observable side
effects (no global writes, no thread spawning, no retained references), so they cannot
leak the reference. This allows the Consumer-based delegated-initialisation pattern
(e.g., a pure constructor accepting a Consumer of T as pure and calling
initializer(this)).
A local that refers to 'this' (other <- this, or other := this) is 'this' under
another name, so passing it is the same escape: recordReference(ReferenceAssignment) marks such a local
(REFERS_TO_THIS, followed through further locals) and the argument check treats it as
'this'.
A property the constructor stores 'this' into (me: this, SelfReferenceStore) is 'this' too, in
that constructor: passing me is the same escape as passing 'this'.
A dynamic function or dynamic class that captures 'this' (or such a local) holds the half-built
object, so it is 'this' too: passed directly (reg.watch((me: this) is Lazy ...)), through a
local it is declared into (recordReference(ReferenceAssignment) for a dynamic function,
recordDynamicClass(ISymbol, EK9Parser.AssignmentExpressionContext) for a dynamic class), or captured again by another dynamic function.
Any of these STORED into another object (checkStore(EK9Parser.AssignmentStatementContext)) is the same escape without a call: the other object
holds the half-built one and can call back into it. Storing into this object's own property is not.
Part of EK9's compile-time data-race detection (slice 1, model rule §3.5). Error E08250 THIS_ESCAPES_CONSTRUCTOR.
-
Field Summary
Fields inherited from class RuleSupport
errorListener, symbolsAndScopes -
Constructor Summary
ConstructorsConstructorDescriptionConstructorThisEscapeOrError(SymbolsAndScopes symbolsAndScopes, ErrorListener errorListener) -
Method Summary
Modifier and TypeMethodDescriptionvoidaccept(EK9Parser.ParamExpressionContext paramExpression, ISymbol resolvedTarget) (package private) voidInside a constructor, 'this' (or an alias, or a dynamic function/class capturing either) must not be STORED into another object: a property of another instance (p.parent: this), a collection another object holds or returns (p.kids += this,reg.members() += this), or another object's mutating operator (reg += this,others += this).(package private) voidrecordDynamicClass(ISymbol target, EK9Parser.AssignmentExpressionContext assignment) Inside a constructor, mark a local that is given a dynamic class capturing 'this'.(package private) voidrecordReference(ReferenceAssignment reference) Inside a constructor, mark a local that a declaration or assignment makes refer to 'this'.Methods inherited from class TypedSymbolAccess
emitTypeNotResolvedError, getRecordedAndTypedSymbol, isProcessingScopePure, recordATypedSymbolMethods inherited from class Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface BiConsumer
andThen
-
Constructor Details
-
ConstructorThisEscapeOrError
ConstructorThisEscapeOrError(SymbolsAndScopes symbolsAndScopes, ErrorListener errorListener)
-
-
Method Details
-
accept
- Specified by:
acceptin interfaceBiConsumer<EK9Parser.ParamExpressionContext, ISymbol>
-
recordReference
Inside a constructor, mark a local that a declaration or assignment makes refer to 'this'. -
recordDynamicClass
Inside a constructor, mark a local that is given a dynamic class capturing 'this'. -
checkStore
Inside a constructor, 'this' (or an alias, or a dynamic function/class capturing either) must not be STORED into another object: a property of another instance (p.parent: this), a collection another object holds or returns (p.kids += this,reg.members() += this), or another object's mutating operator (reg += this,others += this). The other object can then call back into the half-built one - the hazard of passing 'this' as an argument, reached without a call.Storing into this object's OWN property is not an escape: re-pointing a property or local (
me: this), an in-place operator on its own property (kids += this), orthis.propdirectly. A property of this object that refers to ANOTHER object is reached by a chain (this.me.parent: this) and is an escape.
-