Skip to content

Commit a1e812f

Browse files
noahgiftclaude
andcommitted
[GREEN] DEPYLER-0554: Type inference for string comparison and datetime params (Refs GH-105)
Added param type inference patterns: - param == "literal" or param != "literal" → String - param in ["a", "b"] or param not in [...] → String - datetime.datetime.fromtimestamp(param) → f64 stdlib_integration improvements: - algorithm: serde_json::Value → &str - timestamp: serde_json::Value → &f64 - time_format: serde_json::Value → &str Oracle-guided fix: 84% accuracy identified TypeMismatch as root cause. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 9dfc6fc commit a1e812f

File tree

1 file changed

+57
-1
lines changed

1 file changed

+57
-1
lines changed

crates/depyler-core/src/rust_gen/func_gen.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1750,6 +1750,34 @@ fn infer_type_from_expr_usage(param_name: &str, expr: &HirExpr) -> Option<Type>
17501750
}
17511751
}
17521752
}
1753+
1754+
// DEPYLER-0554: datetime.datetime.fromtimestamp(param) → param is f64
1755+
// datetime.datetime.now() doesn't have param, but fromtimestamp does
1756+
if module_name == "datetime" && method == "fromtimestamp" {
1757+
if let Some(first_arg) = args.first() {
1758+
if let HirExpr::Var(var_name) = first_arg {
1759+
if var_name == param_name {
1760+
return Some(Type::Float);
1761+
}
1762+
}
1763+
}
1764+
}
1765+
}
1766+
1767+
// DEPYLER-0554: Handle datetime.datetime attribute access → fromtimestamp method
1768+
// Pattern: datetime.datetime.fromtimestamp(timestamp) where datetime.datetime is the object
1769+
if let HirExpr::Attribute { value, attr } = object.as_ref() {
1770+
if let HirExpr::Var(module_name) = value.as_ref() {
1771+
if module_name == "datetime" && attr == "datetime" && method == "fromtimestamp" {
1772+
if let Some(first_arg) = args.first() {
1773+
if let HirExpr::Var(var_name) = first_arg {
1774+
if var_name == param_name {
1775+
return Some(Type::Float);
1776+
}
1777+
}
1778+
}
1779+
}
1780+
}
17531781
}
17541782

17551783
// Methods that expect string arguments (for method calls on objects)
@@ -1841,11 +1869,39 @@ fn infer_type_from_expr_usage(param_name: &str, expr: &HirExpr) -> Option<Type>
18411869
HirExpr::Binary { left, right, op, .. } => {
18421870
use crate::hir::BinOp;
18431871

1872+
// DEPYLER-0554: Pattern: param == "literal" or param != "literal" → param is String
1873+
// Example: if algorithm == "md5": → algorithm must be String/&str
1874+
if matches!(op, BinOp::Eq | BinOp::NotEq) {
1875+
// Check if param is compared to a string literal
1876+
if let HirExpr::Var(var_name) = left.as_ref() {
1877+
if var_name == param_name {
1878+
if matches!(right.as_ref(), HirExpr::Literal(crate::hir::Literal::String(_))) {
1879+
return Some(Type::String);
1880+
}
1881+
}
1882+
}
1883+
// Also check the reverse: "literal" == param
1884+
if let HirExpr::Var(var_name) = right.as_ref() {
1885+
if var_name == param_name {
1886+
if matches!(left.as_ref(), HirExpr::Literal(crate::hir::Literal::String(_))) {
1887+
return Some(Type::String);
1888+
}
1889+
}
1890+
}
1891+
}
1892+
18441893
// DEPYLER-0524: Pattern: param in string → param is String (substring check)
18451894
// Example: if pattern in line: → pattern must be String for .contains()
1846-
if matches!(op, BinOp::In) {
1895+
// DEPYLER-0554: Pattern: param in ["a", "b"] or param not in [...] → param is String
1896+
if matches!(op, BinOp::In | BinOp::NotIn) {
18471897
if let HirExpr::Var(var_name) = left.as_ref() {
18481898
if var_name == param_name {
1899+
// Check if right side is a list of strings
1900+
if let HirExpr::List(elements) = right.as_ref() {
1901+
if elements.iter().all(|e| matches!(e, HirExpr::Literal(crate::hir::Literal::String(_)))) {
1902+
return Some(Type::String);
1903+
}
1904+
}
18491905
// In Python, "x in y" where y is string → x is also string
18501906
return Some(Type::String);
18511907
}

0 commit comments

Comments
 (0)