Skip to content

Analysis

TypeInference dataclass

TypeInference(
    dialects: DialectGroup,
    *,
    fuel: int | None = None,
    debug: bool = False,
    max_depth: int = 128,
    max_python_recursion_depth: int = 8192
)

Bases: Forward[TypeAttribute]

Type inference analysis for kirin.

This analysis uses the forward dataflow analysis framework to infer the types of the IR. The analysis uses the type information within the IR to determine the method dispatch.

The analysis will fallback to a type resolution algorithm if the type information is not available in the IR but the type information is available in the abstract values.

keys class-attribute instance-attribute

keys = ['typeinfer']

The name of the interpreter to select from dialects by order.

lattice class-attribute instance-attribute

lattice = TypeAttribute

lattice type for the abstract interpreter.

build_signature

build_signature(
    frame: ForwardFrame[types.TypeAttribute],
    stmt: ir.Statement,
) -> Signature

build signature for querying the statement implementation.

Source code in src/kirin/analysis/typeinfer/analysis.py
42
43
44
45
46
47
48
49
50
51
52
def build_signature(
    self, frame: ForwardFrame[types.TypeAttribute], stmt: ir.Statement
) -> Signature:
    _args = ()
    for x in frame.get_values(stmt.args):
        # TODO: remove this after we have multiple dispatch...
        if isinstance(x, types.Generic):
            _args += (x.body,)
        else:
            _args += (x,)
    return Signature(stmt.__class__, _args)

eval_stmt_fallback

eval_stmt_fallback(
    frame: ForwardFrame[types.TypeAttribute],
    stmt: ir.Statement,
) -> (
    tuple[types.TypeAttribute, ...]
    | interp.SpecialValue[types.TypeAttribute]
)

The fallback implementation of statements.

This is called when no implementation is found for the statement.

Parameters:

Name Type Description Default
frame FrameType

the current frame

required
stmt Statement

the statement to run

required

Returns:

Name Type Description
StatementResult StatementResult[ValueType]

the result of running the statement

Note

Overload this method to provide a fallback implementation for statements.

Source code in src/kirin/analysis/typeinfer/analysis.py
54
55
56
57
58
59
60
61
62
63
def eval_stmt_fallback(
    self, frame: ForwardFrame[types.TypeAttribute], stmt: ir.Statement
) -> tuple[types.TypeAttribute, ...] | interp.SpecialValue[types.TypeAttribute]:
    resolve = TypeResolution()
    fs = fields(stmt)
    for f, value in zip(fs.args.values(), frame.get_values(stmt.args)):
        resolve.solve(f.type, value)
    for arg, f in zip(stmt.args, fs.args.values()):
        frame.set(arg, frame.get(arg).meet(resolve.substitute(f.type)))
    return tuple(resolve.substitute(result.type) for result in stmt.results)

expect_const classmethod

expect_const(value: ir.SSAValue, type_: type[T])

Expect a constant value of a given type.

If the value is not a constant or the constant is not of the given type, raise an InterpreterError.

Source code in src/kirin/analysis/typeinfer/analysis.py
83
84
85
86
87
88
89
90
91
92
93
@classmethod
def expect_const(cls, value: ir.SSAValue, type_: type[T]):
    """Expect a constant value of a given type.

    If the value is not a constant or the constant is not of the given type, raise
    an `InterpreterError`.
    """
    hint = cls.maybe_const(value, type_)
    if hint is None:
        raise interp.InterpreterError(f"expected {type_}, got {hint}")
    return hint

maybe_const classmethod

maybe_const(value: ir.SSAValue, type_: type[T]) -> T | None

Get a constant value of a given type.

If the value is not a constant or the constant is not of the given type, return None.

Source code in src/kirin/analysis/typeinfer/analysis.py
72
73
74
75
76
77
78
79
80
81
@classmethod
def maybe_const(cls, value: ir.SSAValue, type_: type[T]) -> T | None:
    """Get a constant value of a given type.

    If the value is not a constant or the constant is not of the given type, return
    `None`.
    """
    hint = value.hints.get("const")
    if isinstance(hint, const.Value) and isinstance(hint.data, type_):
        return hint.data

run_analysis

run_analysis(
    method: ir.Method,
    args: tuple[types.TypeAttribute, ...] | None = None,
    *,
    no_raise: bool = True
) -> tuple[
    ForwardFrame[types.TypeAttribute], types.TypeAttribute
]

Run the forward dataflow analysis.

Parameters:

Name Type Description Default
method(ir.Method)

The method to analyze.

required
args(tuple[LatticeElemType])

The arguments to the method. Defaults to tuple of top values.

required

Other Parameters:

Name Type Description
no_raise(bool)

If True, return bottom values if the analysis fails. Defaults to True.

Returns:

Name Type Description
ForwardFrameType ForwardFrameType

The results of the analysis contained in the frame.

LatticeElemType LatticeElemType

The result of the analysis for the method return value.

Source code in src/kirin/analysis/typeinfer/analysis.py
28
29
30
31
32
33
34
35
36
37
def run_analysis(
    self,
    method: ir.Method,
    args: tuple[types.TypeAttribute, ...] | None = None,
    *,
    no_raise: bool = True,
) -> tuple[ForwardFrame[types.TypeAttribute], types.TypeAttribute]:
    if args is None:
        args = method.arg_types
    return super().run_analysis(method, args, no_raise=no_raise)

run_method

run_method(
    method: ir.Method, args: tuple[types.TypeAttribute, ...]
) -> tuple[
    ForwardFrame[types.TypeAttribute], types.TypeAttribute
]

How to run a method.

This is defined by subclasses to describe what's the corresponding value of a method during the interpretation. Usually, this method just calls run_callable.

Parameters:

Name Type Description Default
method Method

the method to run.

required
args tuple[ValueType, ...]

the arguments to the method, does not include self.

required

Returns:

Name Type Description
ValueType tuple[FrameType, ValueType]

the result of the method.

Source code in src/kirin/analysis/typeinfer/analysis.py
65
66
67
68
def run_method(
    self, method: ir.Method, args: tuple[types.TypeAttribute, ...]
) -> tuple[ForwardFrame[types.TypeAttribute], types.TypeAttribute]:
    return self.run_callable(method.code, (method.self_type,) + args)