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:
- Variable Assignment: Infer the type of a variable based on the type of the value assigned to it.
- Arithmetic Operations: Infer the type of the result of arithmetic operations (e.g.,
+,-,*,/). - 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.
- Reassignment: Handle cases where a variable is reassigned. The inferred type should be updated accordingly.
- Basic Types: Support inference for
int,float,str, andbool.
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 + floatresults infloat), 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:
xis assigned an integer10, so its type isint.yis assigned a float3.14, so its type isfloat.zis assigned the result ofx * 2.xisint,2isint. Integer multiplication results in anint.
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:
nameis assigned a string, inferred asstr.ageis assigned an integer, inferred asint.is_studentis assigned a boolean, inferred asbool.greetingis assigned"Hello, " + name."Hello, "isstr,nameisstr. String concatenation results instr.new_ageis assignedage + 5.ageisint,5isint. Integer addition results inint.
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_idis assigned the result ofget_id(), which returnsint.radiusis assigned an integer,int.circumferenceis assigned2 * 3.14 * radius.2isint,3.14isfloat,radiusisint. The operation involves afloat, so the result is promoted tofloat.pi_valis assigned the result ofget_pi(), which returnsfloat.
Constraints
- The input
code_stringwill 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 + floatshould inferfloat). - The provided
function_return_typesdictionary will be passed to yourinfer_typesfunction.