E08088: isSet check is always true based on data flow analysis

Category: E08xxx Pre-IR checks (flow analysis) · Reported in phase: PRE_IR_CHECKS · Classification: REDUNDANT_ISSET_CHECK · All error codes

What went wrong

This isSet check (?) is always true based on data flow analysis. The variable is provably SET at this point — either from a literal assignment, a guard that already proved the variable is set, or a prior assignment from a constructor call.

The same applies to set-checks you do not write as '?' (D7). A guard's own gate is a set-check: 'if seven <- 7' always enters, as does 'if late :=? 5' on a provably unset 'late'. Re-testing a guard's own target in its then/with condition - 'if v <- f() then v?' or 'if x :=? f() then x?' - is always true: that condition only runs once the gate has passed. And an 'x?' that is one operand of an 'and' condition is judged like a whole condition: 'if x := 7 then x? and ready'.

Worked examples

Compilable examples demonstrating this error and the correct fix:

  • 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 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

  1. Remove the redundant isSet check and unwrap the code
  2. If the variable was assigned from a literal, the check is unnecessary
  3. If inside a guard's true-branch, the guard already guarantees the variable is set
  4. Verify this isn't a copy-paste error from a different variable
  5. A guard over a known value: declare the variable plainly and drop the 'if' (or test what you meant to test); after a guard, drop 'then v?' - the guard has checked it
  6. 'if x := f() then x?' (a blind re-point and gate) is fine: nothing proves f() set

Common causes

  • Variable assigned from a literal (String, Integer, Boolean) and then checked with ?
  • Declaration guard (if x <- expr()) followed by a redundant x? check in the body
  • Defensive coding habit from other languages where null checks are needed after assignment
  • Refactoring moved an assignment before a check but didn't remove the check
  • Collection (List, Dict) constructed and then checked with ? — collections are always SET when created
  • Optional constructed with a value and then checked with ? — always SET
  • A class, component or service with no fields (counting inherited ones) constructed and then checked with ? (a Stateless() then tested with 's?') — its '?' is generated and answers true whenever it is present
  • A guard over a literal or a collection constructor: 'if seven <- 7', 'if names <- List() of String'
  • 'then v?' after 'if v <- f()' or 'if v :=? f()' — the guard's gate already checked v
  • 'if x := 7 then x? and ready' — the 'x?' operand is known true

See also

  • E08089: isSet check always false (variable provably UNSET)
  • E08086: condition always true (comparison-based tautology)
  • E08087: condition always false (comparison-based)

Examples

Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.

Fails with E08088: isSet check is always true based on data flow analysis

#!ek9
defines module error.e08088.bad

  defines function

    checkStringLiteralAlwaysSet()
      <- result as String: String()

      greeting <- "hello"

      if greeting?
        result: greeting

    checkIntegerLiteralAlwaysSet()
      <- result as String: String()

      count <- 42

      if count?
        result: $count

    checkBooleanLiteralAlwaysSet()
      <- result as String: String()

      isEnabled <- true

      if isEnabled?
        result: $isEnabled

Fixed: Use a value that is known to be set directly

#!ek9
defines module error.e08088.good

  defines function

    checkStringLiteralAlwaysSet()
      <- result as String: String()
      greeting <- "hello"
      result: greeting

    checkMaybeSet()
      -> greeting as String
      <- result as String: String()
      if greeting?
        result: greeting

Questions and answers

These Q&A entries show E08088 and its fix: