1717 StrExpr ,
1818 UnaryExpr ,
1919 Var ,
20+ CallExpr ,
21+ MemberExpr ,
22+ ListExpr ,
2023)
2124
2225# All possible result types of constant folding
@@ -73,6 +76,23 @@ def constant_fold_expr(expr: Expression, cur_mod_id: str) -> ConstantValue | Non
7376 value = constant_fold_expr (expr .expr , cur_mod_id )
7477 if value is not None :
7578 return constant_fold_unary_op (expr .op , value )
79+ # --- f-string constant folding ---
80+ elif (
81+ isinstance (expr , CallExpr )
82+ and isinstance (callee := expr .callee , MemberExpr )
83+ and isinstance (callee .expr , StrExpr )
84+ and callee .expr .value == ""
85+ and callee .name == "join"
86+ and len (args := expr .args ) == 1
87+ and isinstance (arg := args [0 ], ListExpr )
88+ ):
89+ folded_items = []
90+ for item in arg .items :
91+ val = constant_fold_expr (item , cur_mod_id )
92+ if not isinstance (val , str ):
93+ return None
94+ folded_items .append (val )
95+ return "" .join (folded_items )
7696 return None
7797
7898
@@ -185,3 +205,7 @@ def constant_fold_unary_op(op: str, value: ConstantValue) -> int | float | None:
185205 elif op == "+" and isinstance (value , (int , float )):
186206 return value
187207 return None
208+
209+
210+ def is_f_string_expr (expr : Expression ) -> TypeGuard [CallExpr ]:
211+
0 commit comments