Hone logo
Hone
Problems

Python Type Inference Engine

This challenge asks you to build a rudimentary type inference system for a subset of Python. Type inference is crucial for static analysis tools, code completion, and improving code maintainability by automatically deducing variable and expression types without explicit annotations.

Problem Description

Your task is to implement a Python function, infer_types(code_string), that takes a string containing Python code as input and returns a dictionary mapping variable names to their inferred types. The system should be able to handle basic assignments, arithmetic operations, and function calls with predefined return types.

Key Requirements:

  1. Variable Assignment: Infer the type of a variable based on the type of the value assigned to it.
  2. Arithmetic Operations: Infer the type of the result of arithmetic operations (e.g., +, -, *, /).
  3. Function Calls: Infer the type of a variable if it's assigned the result of a function call. You will be provided with a predefined mapping of function names to their return types.
  4. Reassignment: Handle cases where a variable is reassigned. The inferred type should be updated accordingly.
  5. Basic Types: Support inference for int, float, str, and bool.

Expected Behavior:

The infer_types function should process the provided Python code line by line. It will maintain an internal symbol table to keep track of variable types. When an assignment occurs, it will determine the type of the right-hand side and update the symbol table. For operations, it will deduce the resulting type based on the operand types.

Edge Cases:

  • Type Mismatches in Operations: For simplicity, assume valid operations (e.g., don't infer types for int + str). If an operation involves types that would result in a standard Python type promotion (e.g., int + float results in float), infer the promoted type.
  • Undefined Variables: If an operation uses a variable that hasn't been assigned a type yet, assume a placeholder "unknown" type for that variable during the operation's type inference.
  • Multiple Assignments: A variable can be assigned multiple times; its type should reflect the latest assignment.

Examples

Example 1:

Input: """
x = 10
y = 3.14
z = x * 2
Output: {
    "x": "int",
    "y": "float",
    "z": "int"
}

Explanation:

  • x is assigned an integer 10, so its type is int.
  • y is assigned a float 3.14, so its type is float.
  • z is assigned the result of x * 2. x is int, 2 is int. Integer multiplication results in an int.

Example 2:

Input: """
name = "Alice"
age = 30
is_student = True
greeting = "Hello, " + name
new_age = age + 5
Output: {
    "name": "str",
    "age": "int",
    "is_student": "bool",
    "greeting": "str",
    "new_age": "int"
}

Explanation:

  • name is assigned a string, inferred as str.
  • age is assigned an integer, inferred as int.
  • is_student is assigned a boolean, inferred as bool.
  • greeting is assigned "Hello, " + name. "Hello, " is str, name is str. String concatenation results in str.
  • new_age is assigned age + 5. age is int, 5 is int. Integer addition results in int.

Example 3: (Function Call and Type Promotion)

Input: """
def get_id():
    return 123

def get_pi():
    return 3.14159

user_id = get_id()
radius = 5
circumference = 2 * 3.14 * radius
pi_val = get_pi()
Output: {
    "user_id": "int",
    "radius": "int",
    "circumference": "float",
    "pi_val": "float"
}

Predefined function return types: get_id: int get_pi: float

Explanation:

  • user_id is assigned the result of get_id(), which returns int.
  • radius is assigned an integer, int.
  • circumference is assigned 2 * 3.14 * radius. 2 is int, 3.14 is float, radius is int. The operation involves a float, so the result is promoted to float.
  • pi_val is assigned the result of get_pi(), which returns float.

Constraints

  • The input code_string will be a valid Python snippet syntactically, but may not be semantically correct in terms of types for all operations.
  • The code will not contain complex control flow structures like if, for, while, try-except.
  • The code will not contain class definitions or method calls.
  • Only basic arithmetic operators (+, -, *, /) and string concatenation (+) will be used.
  • Variable names will be alphanumeric and follow Python identifier rules.
  • Integers, floats, strings, and booleans will be the primary literal types.
  • You will be provided with a dictionary mapping function names to their return types.

Notes

  • Focus on accurately inferring types for assignments and basic operations.
  • You might need to parse the code line by line. Abstract Syntax Trees (ASTs) are a powerful tool for this, but for this challenge, simpler string manipulation or regular expressions might suffice if you constrain the input significantly.
  • Consider how you will represent types internally (e.g., strings like "int", "float").
  • Remember to handle type promotion correctly (e.g., int + float should infer float).
  • The provided function_return_types dictionary will be passed to your infer_types function.
Loading editor...
python