Skip to content

Soundness bug: PNot returns exception for None and DictStrAny inputs instead of computing not #934

@keyboardDrummer-bot

Description

@keyboardDrummer-bot

Bug

PNot in PythonRuntimeLaurelPart.lean is unsound for None and DictStrAny inputs. It falls through to exception(UndefinedError(...)) for these types, but Python's not operator works on all types (it's equivalent to not bool(x)) and never raises an exception for non-exception inputs.

Affected cases

Expression Python behavior Strata (PNot) result
not None True exception(UndefinedError(...))
not {} True exception(UndefinedError(...))

PNot currently handles bool, int, float, str, and ListAny, but is missing branches for None and DictStrAny.

Related issue in Any_to_bool

Any_to_bool (around line 309) has a similar gap — it handles None and DictStrAny but is missing float. These two functions should be kept in sync since not x is semantically not bool(x).

Proposed fix

  1. Add None and DictStrAny branches to PNot
  2. Change the else branch from exception to hole (to be safe for types not yet modeled, e.g. datetime, bytes, ClassInstance)
  3. Add the missing float branch to Any_to_bool
  4. Align PNot and Any_to_bool so they cover the same set of types

Sketch for PNot:

function PNot (v: Any) : Any
{
  if Any..isexception(v) then v
  else if Any..isfrom_bool(v) then from_bool(!(Any..as_bool!(v)))
  else if Any..isfrom_int(v) then from_bool(!(Any..as_int!(v) == 0))
  else if Any..isfrom_float(v) then from_bool(!(Any..as_float!(v) == 0.0))
  else if Any..isfrom_str(v) then from_bool(!(Any..as_string!(v) == ""))
  else if Any..isfrom_ListAny(v) then from_bool(!(List_len(Any..as_ListAny!(v)) == 0))
  else if Any..isfrom_None(v) then from_bool(true)
  else if Any..isfrom_DictStrAny(v) then from_bool(!(Any..as_Dict!(v) == DictStrAny_empty()))
  else hole
};

Context

Discovered during review of #926 (bitwise operators PR). See this review thread for the full discussion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions