ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
python_types.h
Go to the documentation of this file.
1#pragma once
2
3#include <util/irep/irep.h>
4
5class typet;
6
8
10
11// True when a function yields nothing a postcondition could name: `-> None`,
12// no annotation, or no enclosing function at all. Shared so the clause check
13// and the __ESBMC_return_value lowering cannot disagree about what None means.
14bool returns_no_value(const typet &t);
15
16// Classification of Python "internal model aggregate" struct types.
17//
18// The Python frontend lowers a handful of built-in container/union types to
19// plain structs whose representation and lifetime are managed by the
20// operational model rather than by user code: tuples, dicts and typing
21// Optional unions. These must be distinguished from user-defined Python class
22// instances, which behave like ordinary garbage-collected objects.
23//
24// Historically the distinction was recovered by substring-matching the struct
25// tag (e.g. tag.find("dict_") != npos, tag.rfind("tag-tuple", 0) == 0). That
26// is brittle -- a user class named "dict_node" matches "dict_" -- and the
27// literal tag spellings were duplicated across the frontend and goto-symex
28// behind a "keep in sync" comment. Instead, each aggregate type is stamped
29// with an explicit kind attribute at creation time and every consumer reads it
30// back. The attribute lives on the (old-irep) struct type, survives
31// symbol-table storage and namespacet::follow, and is read both by the Python
32// frontend (dunder dispatch, list object-ref) and by goto-symex (object GC
33// lifetime).
34//
35// The "#"-prefixed name routes to the irep comment slot, so the stamp does not
36// perturb type identity (irept::operator== ignores comments) -- existing
37// type-equality and symbol-matching logic is unaffected. The flip side is that
38// the kind is preserved only across copies / follow: rebuilding a type from its
39// tag and components drops it. All tuple/dict/Optional types are produced by
40// the factory functions in this frontend (which both tag and stamp), and the
41// consumers read the factory-produced type by copy, so this holds today; a new
42// code path that reconstructs one of these structs by hand must re-stamp it.
43#define PYTHON_AGGREGATE_ATTR "#python_aggregate"
44
45// Marks the null void* the frontend returns for a method call it could not
46// resolve to a class. The value is only a placeholder: reading it as a
47// truthiness test would prove `not call()` from an inference gap, so the `not`
48// arm replaces a tagged operand with a nondet bool. Every other use keeps the
49// constant, whose folding is what stops method-heavy programs from blowing up.
50#define PYTHON_UNRESOLVED_CALL_ATTR "#python_unresolved_call"
51
52// Marks a dict keys view, which is set-like and so compares with a set by
53// content. It must be stamped where `d.keys()` is lowered: by the time the
54// comparison sees it, it is a bare `keys` member indistinguishable from the
55// items placeholder or from a user attribute of that name.
56#define PYTHON_KEYS_VIEW_ATTR "#python_keys_view"
57
62#define PYTHON_ITEMS_VIEW_ATTR "#python_items_view"
63
64// Stamp a Python internal-aggregate kind ("tuple", "dict", "optional") onto a
65// freshly created struct type.
67
68// Return the stamped kind, or an empty id for user class instances / non-Python
69// structs.
71
72// True for tuple / dict / Optional model aggregates; false for user-defined
73// Python class instances.
Definition irep_idt.h:12
typet & type()
Definition irep.h:153
Definition type.h:9
bool is_python_internal_aggregate(const typet &type)
Definition python_types.cpp:31
typet any_type()
Definition python_types.cpp:10
bool returns_no_value(const typet &t)
Definition python_types.cpp:16
irep_idt python_aggregate_kind(const typet &type)
Definition python_types.cpp:26
void set_python_aggregate_kind(typet &type, const irep_idt &kind)
Definition python_types.cpp:21
typet none_type()
Definition python_types.cpp:4