Class ObjectUsedBeforeConstructedOrError
Construction runs the super constructor, then this type's property initialisers in declaration order, then the constructor body. Until every property has a value, calling a method on the object - or handing out 'this' - can reach a property that is still unset, and it failed with a NullPointerException at run time (front-end audit FE32). This is the two-phase rule: the object may not be used until it is complete.
- A property initialiser runs before the constructor body, so the object is never complete there: no method
call on it (even an inherited one - an inherited method can call back into one this type overrides) and no
'this' at all - not as a value, not in a capture list, and not to reach a property (
this.first + 1is writtenfirst + 1; Steve, 2026-10-08, F4 rule 1). - A constructor may use the object once every property is set on the current path (the flow tracking E08060
already does) - counting what a 'this(...)' call set, which is only what the constructor it delegates to sets
(
DelegatedConstructorInitialisation): a private one may set nothing. Never inside the arguments of 'this(...)' or 'super(...)': nothing has been constructed yet. - In an open or abstract type, a constructor can never call a method a subtype may override, nor hand out 'this': the subtype's own properties are only set after this constructor returns.
The last rule holds at the other end of the object's life too (E81068): in an open or abstract type, the 'operator close' body can never call a method a subtype may override, nor hand out 'this' - a subtype's own properties are closed before its super's close runs (C++'s destructor order without its devirtualisation; Core Guidelines C.82). Same predicate, same walk; only the enclosing operation differs.
Inside the arguments of 'this(...)' or 'super(...)' even reading one of the object's own properties is a use
(acceptPropertyRead(EK9Parser.IdentifierContext), decision 3 of the absence work, family F): nothing has been constructed yet - the
super constructor has not run, nor this type's property initialisers, which run after it
(ConstructionSteps). So a property with an initialiser has no value there
either; the JVM verifier rejected the read as a 'getfield' on 'uninitializedThis' at class load, and on a
back end with no verifier it is a null read. Java's rule (JLS 8.8.7.1) is the same.
Anywhere else, reading and writing a property (this.count) is not a use of the object: E08060 checks
each property.
Nor is storing the object in one of its own properties (me: this, SelfReferenceStore): that
completes the property like any other assignment. The property is then the object under another name, so any
other appearance of it in that constructor (me.twice(), other <- me) is a use of the object.
THE PARENT LINK (Steve, 2026-10-08, F4 - strict, lenient only for capture-construction). A statement giving one of
the type's OWN properties a dynamic function or class that captures 'this' (child :=? (owner: this) with
trait of Child as class ..., also := or :) is the same kind of store
(SelfReferenceStore.capturedInto(EK9Parser.AssignmentStatementContext, SymbolsAndScopes)), so it is not a use of the object - provided every OTHER property is set
on that path or is itself the target of a later capture-assignment (checkCaptureAssignment(EK9Parser.PrimaryReferenceContext, EK9Parser.AssignmentStatementContext)). This is
how a parent hands each child a reference back to itself: the object becomes complete when its last such property
is set. Until then:
- the property holding the capture is the object under another name, so calling it, passing it or capturing
it again is E08061 (the alias rule above, through
SelfReferenceStore.propertiesStoredIn(EK9Parser.MethodDeclarationContext, SymbolsAndScopes)); - a dynamic class created that way runs its own property initialisers during the capturing statement, while
the object is incomplete, so using the captured 'this' there is E08061 (
checkIncompleteOwnerUse(ParserRuleContext, ISymbol)); its methods, and a dynamic function's body, run only when called, so they fall under the alias rule.
Unchanged: never in the arguments of this(...) or super(...), and never in an open or abstract type, whose
subtype's properties are only set after this constructor returns. No new analysis: the path state is E08060's, the
delegated-constructor state is D9's (DelegatedConstructorInitialisation), and the stores are
SelfReferenceStore's.
-
Field Summary
Fields inherited from class RuleSupport
errorListener, symbolsAndScopes -
Constructor Summary
ConstructorsConstructorDescriptionObjectUsedBeforeConstructedOrError(SymbolsAndScopes symbolsAndScopes, ErrorListener errorListener) -
Method Summary
Modifier and TypeMethodDescription(package private) voidA method called with no receiver - on the object itself - such astwice().(package private) voidA property that refers back to the object, used as a value (other <- me).(package private) voidA property that refers back to the object, used to reach it (me.twice()).(package private) voidA use of 'this' or 'super': a call through it, or 'this' as a value.(package private) booleanA read of one of the object's own properties -count,this.count,count.length()- inside the arguments of 'this(...)' or 'super(...)', however deeply nested in an expression or another call.Methods inherited from class TypedSymbolAccess
emitTypeNotResolvedError, getRecordedAndTypedSymbol, isAlreadyInError, isProcessingScopePure, recordATypedSymbol
-
Constructor Details
-
ObjectUsedBeforeConstructedOrError
ObjectUsedBeforeConstructedOrError(SymbolsAndScopes symbolsAndScopes, ErrorListener errorListener)
-
-
Method Details
-
acceptCall
A method called with no receiver - on the object itself - such astwice(). -
acceptPrimaryReference
A use of 'this' or 'super': a call through it, or 'this' as a value. Reaching a property is not a use. -
acceptPropertyRead
A read of one of the object's own properties -count,this.count,count.length()- inside the arguments of 'this(...)' or 'super(...)', however deeply nested in an expression or another call. A property of another object (other.count), a nested dynamic function's or class's capture label, and an argument label are not reads of this object's properties.- Returns:
- true if the read was reported, so the per-property check (E08060) need not also report it
-
acceptIdentifierReference
A property that refers back to the object, used as a value (other <- me). -
acceptObjectAccessStart
A property that refers back to the object, used to reach it (me.twice()).
-