E08089: isSet check is always false based on data flow analysis
What went wrong
This isSet check (?) is always false based on data flow analysis. The variable is provably UNSET at this point — typically because it was declared with ? (unset) and never assigned a value before this check.
The same applies to set-checks you do not write as '?' (D7). A guard whose stored value is provably unset never enters: 'if v <- Integer()' (a literal type's no-argument constructor is present but unset), or 'if late :=? String()' on an unset 'late'. 'then not v?' after a guard on v is always false, because the condition only runs once the gate has found v set. An 'x?' that is one operand of an 'and' condition is judged like a whole condition.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 2256 (Why does the compiler say my 'if x?' can never be true...)
- ek9 -q 559 (Why does EK9 reject my isSet check as redundant?)
- ek9 -q 2255 (How does the EK9 compiler decide a variable is definitely...)
- ek9 -q 736 (How does EK9 detect redundant empty and isSet checks?)
- ek9 -q 640 (When is an isSet check on a collection genuinely needed...)
- ek9 -q 311 (What code quality checks does the EK9 compiler perform?)
How to fix it
- Assign a value to the variable before checking it with ?
- Remove the unreachable code block
- Check if a required assignment is missing
- Consider whether the variable should have been declared with an initial value
Common causes
- Variable declared with ? (unset) but no assignment before the isSet check
- Intended assignment was accidentally deleted or commented out
- Refactoring moved the check above the assignment
- Misunderstanding of EK9's unset declaration semantics
- Optional created empty (no value) and then checked with ? — always UNSET
- A guard over 'Integer()', 'String()', 'Date()' ... — the no-argument constructor makes an unset value, so the guard never enters; use the value you meant to store
- 'then not v?' after 'if v <- f()' — the guard only enters when v is set
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E08089: isSet check is always false based on data flow analysis
#!ek9 defines module error.e08089.bad defines function computeName() <- rtn as String: "Alice" computeCount() <- rtn as Integer: 42 //Else of isSet narrows to UNSET, re-checking is always false checkNeverSetInElse() <- result as String: "no-name-found" name <- computeName() if name? result: name else if name? result: "unreachable-name-branch" //Same pattern with Integer variable checkNeverSetIntegerElse() <- result as String: "no-count-found" count <- computeCount() if count? result: $count else if count? result: "unreachable-count-branch"
Fixed: Do not re-test what the else already decided
#!ek9 defines module error.e08089.good defines function computeName() <- rtn as String: "Alice" checkName() <- result as String: "no-name-found" name <- computeName() if name? result: name
Questions and answers
These Q&A entries show E08089 and its fix: