ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
preprocessor.function_value_dispatch Namespace Reference

Classes

class  _Refused
class  _Plan
class  _Codes
class  _Returns
class  _Dispatch

Functions

 _mixed_groups (analysis)
 _parents (module)
 _rebinds (module, name)
 _binds_by_string (node, names)
 _bound_names (nodes)
 _sole_def (fn, defs, module, analysis)
 _takes_positional (fn, count)
 _is_callee (parent, node)
 _is_builtin_call (parent, name, arg)
 _call_directly (stmt, group, callee, fn)
 _chain (arms, callee, origin)
 dispatch_mixed_function_values (module, path)
 _propagated (module, path)

Variables

int _CAP = 8
str _PREFIX = "_esbmc_fv"
str _SITE = "esbmc_fv_site"
str _CODE = "esbmc_fv_code"
str _IDENTITY = "esbmc_fv_identity"
str _CALLABLE = "esbmc_fv_callable"
str _CHOSEN = "esbmc_fv_chosen"
str _RETURN = "esbmc_fv_return"
dict _REFLECTIVE = {"globals", "locals", "vars", "eval", "exec", "__import__"}
dict _REFLECTIVE_ATTRS = {"modules", "__dict__", "__globals__"}
tuple _NESTED
tuple _UNCOPYABLE
 _COMPOUND

Detailed Description

Dispatch a call through a function value whose functions return different types (#8970).

The converter gives a call through a function value one return type, so
function_value_types refuses such a call when its functions disagree. For a
group of module-level functions whose values only flow through module-level
names, lists and tuples, this pass rewrites the program so that no function
value is left:

- each reference to a function of the group becomes its index in the group,
  so `h = f if c else g` becomes `h = 0 if c else 1`
- `h is f` becomes `h == 0` and `callable(h)` becomes `True`
- a statement calling `h()` becomes `if h == 0: ... elif ...: ... else: ...`,
  and each arm holds that statement and the rest of the module, with `h()`
  replaced by a direct call to that arm's function. A call in the body of an
  `if` first copies the rest of the module into both branches of that `if`.
- a module-level function that only returns the call `h()` of its parameter,
  as in `def call(h): return h()`, returns a direct call in each arm of such a
  chain instead, so nothing is copied.

Each arm then sees the precise type of its call's result. A name bound in an
arm is renamed per arm, so that it does not join values of different types.
When any condition does not hold, the module is left as it was and
function_value_types refuses the call as before.

Function Documentation

◆ _binds_by_string()

preprocessor.function_value_dispatch._binds_by_string ( node,
names )
protected
Whether `node` itself binds one of `names` other than through an `ast.Name`.

◆ _bound_names()

preprocessor.function_value_dispatch._bound_names ( nodes)
protected
Every name that `nodes` read or bind, in any scope.

◆ _call_directly()

preprocessor.function_value_dispatch._call_directly ( stmt,
group,
callee,
fn )
protected
Call `fn` at the chosen site in `stmt`, and at every site through the same name.

◆ _chain()

preprocessor.function_value_dispatch._chain ( arms,
callee,
origin )
protected
`if callee == 0: arms[0] elif ...: ... else: arms[-1]`, located at `origin`.

◆ _is_builtin_call()

preprocessor.function_value_dispatch._is_builtin_call ( parent,
name,
arg )
protected
Whether `parent` is `name(arg)` with no other argument.

◆ _is_callee()

preprocessor.function_value_dispatch._is_callee ( parent,
node )
protected

◆ _mixed_groups()

preprocessor.function_value_dispatch._mixed_groups ( analysis)
protected
The groups that a call goes through and whose functions disagree on return type.

◆ _parents()

preprocessor.function_value_dispatch._parents ( module)
protected

◆ _propagated()

preprocessor.function_value_dispatch._propagated ( module,
path )
protected

◆ _rebinds()

preprocessor.function_value_dispatch._rebinds ( module,
name )
protected
Whether `module` binds `name` anywhere.

◆ _sole_def()

preprocessor.function_value_dispatch._sole_def ( fn,
defs,
module,
analysis )
protected
Whether `fn` is the module's only, undecorated def of its name, never rebound.

◆ _takes_positional()

preprocessor.function_value_dispatch._takes_positional ( fn,
count )
protected
Whether `fn` takes exactly `count` positional arguments and nothing else.

◆ dispatch_mixed_function_values()

preprocessor.function_value_dispatch.dispatch_mixed_function_values ( module,
path )
Rewrite calls through mixed function values into dispatches, when every use allows it.

Variable Documentation

◆ _CALLABLE

str preprocessor.function_value_dispatch._CALLABLE = "esbmc_fv_callable"
protected

◆ _CAP

int preprocessor.function_value_dispatch._CAP = 8
protected

◆ _CHOSEN

str preprocessor.function_value_dispatch._CHOSEN = "esbmc_fv_chosen"
protected

◆ _CODE

str preprocessor.function_value_dispatch._CODE = "esbmc_fv_code"
protected

◆ _COMPOUND

preprocessor.function_value_dispatch._COMPOUND
protected
Initial value:
1= tuple(
2 getattr(ast, n)
3 for n in ("For", "AsyncFor", "While", "With", "AsyncWith", "Try", "TryStar", "Match")
4 if hasattr(ast, n))

◆ _IDENTITY

str preprocessor.function_value_dispatch._IDENTITY = "esbmc_fv_identity"
protected

◆ _NESTED

tuple preprocessor.function_value_dispatch._NESTED
protected
Initial value:
1= (ast.FunctionDef, ast.AsyncFunctionDef, ast.Lambda, ast.ClassDef, ast.ListComp,
2 ast.SetComp, ast.DictComp, ast.GeneratorExp)

◆ _PREFIX

str preprocessor.function_value_dispatch._PREFIX = "_esbmc_fv"
protected

◆ _REFLECTIVE

dict preprocessor.function_value_dispatch._REFLECTIVE = {"globals", "locals", "vars", "eval", "exec", "__import__"}
protected

◆ _REFLECTIVE_ATTRS

dict preprocessor.function_value_dispatch._REFLECTIVE_ATTRS = {"modules", "__dict__", "__globals__"}
protected

◆ _RETURN

str preprocessor.function_value_dispatch._RETURN = "esbmc_fv_return"
protected

◆ _SITE

str preprocessor.function_value_dispatch._SITE = "esbmc_fv_site"
protected

◆ _UNCOPYABLE

tuple preprocessor.function_value_dispatch._UNCOPYABLE
protected
Initial value:
1= (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Lambda, ast.Import,
2 ast.ImportFrom, ast.Global, ast.Nonlocal)