Overview
Shed Skin uses a sophisticated constraint-based type inference algorithm to automatically determine types for Python code. The type inference system combines two powerful algorithms to handle both function polymorphism and data polymorphism.Core Algorithms
Cartesian Product Algorithm (CPA)
Shed Skin implements Agesen’s Cartesian Product Algorithm to handle parametric polymorphism, where the return type of a method depends on the actual types of the method arguments. For example:shedskin/infer.py:1236 - The cpa() function handles cartesian product analysis
Iterative Flow Analysis (IFA)
Plevyak’s Iterative Flow Analysis handles data polymorphism, where variable types depend on control flow paths. For example:shedskin/infer.py:1460 - The ifa() function performs iterative flow analysis
Constraint Graph
Type inference works by propagating types through a constraint graph:- Nodes represent program elements (variables, expressions, function calls)
- Edges represent type constraints between nodes
- Types flow from sources to sinks following constraint edges
shedskin/graph.py by the ModuleVisitor class.
Graph Structure
Nodes are identified by a tuple(AST_node, dcpa, cpa) where:
AST_node: The Python AST nodedcpa: Data duplication index (for class/container polymorphism)cpa: Function duplication index (for parametric polymorphism)
Iterative Dataflow Analysis
The main inference algorithm initerative_dataflow_analysis() proceeds in phases:
Forward Phase
-
Propagate types through the constraint graph via
propagate()(infer.py:862)- Types flow from nodes to their successors
- Continues until reaching a fixed point
-
Create function duplicates using CPA via
cpa()(infer.py:1236)- Generates specialized function versions for different type combinations
- Connects actual arguments to formal parameters
-
Seed allocation points with correct types via
ifa_seed_template()(infer.py:1713)- Ensures container allocations get appropriate element types
Backward Phase
-
Find imprecision points via
ifa()(infer.py:1460)- Identifies where types are mixing inappropriately
- Traces backwards to find related allocation points
-
Duplicate classes and distribute across allocation points
- Creates specialized container types for different use cases
- Example:
list[int]vslist[str]become separate types
Cleanup
- Exit if no imprecision points found (analysis converged)
- Otherwise reset graph state and restart with more duplicates
- Allocation point types maintained in
gx.alloc_info
Type Seeds
Inference starts from known “type seeds”:- Integer literals →
int_type - String literals →
str_type - List constructors →
listtype - Class instantiations → class type
Tuning Parameters
The inference algorithm has several tunable constants ininfer.py:137-175:
Scalability Limitations
Cartesian Product Explosion
The main scalability challenge is combinatorial explosion in the cartesian product algorithm. For a function called with N different type combinations, CPA generates up to N specialized versions. Mitigation: TheCPA_LIMIT parameter (default: 10) limits combinations per call site. When exceeded, the limit doubles and analysis restarts with reduced precision.
Memory Usage
Large programs with many polymorphic functions can consume significant memory:- Each function specialization requires duplicated constraint graph nodes
- Type information is maintained for all nodes and their combinations
INCREMENTAL = True) adds functions gradually to show progress and manage memory.
Iteration Count
Complex type dependencies may require many iterations to converge:- Each IFA split restarts the entire analysis
- After 3 consecutive max-iteration hits, analysis terminates
MAXITERS for faster compilation at the cost of potentially less precise types.
Example: Type Inference in Action
Consider this Python code:- Initial call with
[1, 2, 3]createsprocess_list<int>specialization resultinferred aslist[int]- Second call with
["a", "b"]createsprocess_list<str>specialization - Second
resultinferred aslist[str] - Two separate function versions generated in C++
Debugging Type Inference
Use the debug level flags for insight into inference:- Template creation for function specializations
- IFA splits when types are duplicated
- Iteration counts and convergence status
Further Reading
- Ole Agesen’s PhD thesis: “The Cartesian Product Algorithm”
- Mark Dufour’s MSc thesis: “Shed Skin: An Optimizing Python-to-C++ Compiler”
- Module docstrings in
shedskin/infer.pyandshedskin/graph.py