@@ -316,33 +316,39 @@ fn cpython_parse_diagnostic_override(
316316 }
317317
318318 source_error ! ( invalid_dict_error( source_text) ) ;
319- source_error ! ( invalid_collection_assignment_error( source_text) ) ;
319+ if !matches ! ( mode, Mode :: Eval ) {
320+ source_error ! ( invalid_collection_assignment_error( source_text) ) ;
321+ }
320322 source_error ! ( invalid_group_error( source_text) ) ;
321323 source_error ! ( invalid_def_type_params_error( source_text) ) ;
322324 source_error ! ( invalid_expression_error( source_text) ) ;
323325 source_error ! ( invalid_named_expression_error( source_text) ) ;
324- source_error ! ( invalid_plain_assignment_error( source_text) ) ;
325- source_error ! ( expression_assignment_error( source_text) ) ;
326- source_error ! ( invalid_annotation_target_error( source_text) ) ;
327- source_error ! ( invalid_assignment_target_error( source_text) ) ;
328- source_error ! ( invalid_condition_assignment_error(
329- source_text,
330- error. location. start( ) . to_usize( )
331- ) ) ;
332- source_error ! ( invalid_augassign_target_error( source_text) ) ;
333- source_error ! ( invalid_for_target_error( source_text) ) ;
334- source_error ! ( invalid_with_target_error( source_text) ) ;
335- source_error ! ( invalid_delete_target_error( source_text) ) ;
336- source_error ! ( invalid_standalone_except_error( source_text) ) ;
337- source_error ! ( invalid_import_statement_error( source_text) ) ;
338- source_error ! ( invalid_import_target_error( source_text) ) ;
339- source_error ! ( invalid_except_as_target_error( source_text) ) ;
340- source_error ! ( invalid_match_mapping_rest_wildcard_error( source_text) ) ;
341- source_error ! ( invalid_match_as_target_error( source_text) ) ;
342- source_error ! ( invalid_for_if_clause_error( source_text) ) ;
343- source_error ! ( invalid_if_expression_statement_error( source_text) ) ;
344- source_error ! ( invalid_else_elif_error( source_text) ) ;
345- source_error ! ( mixed_except_handlers_error( source_text) ) ;
326+ // Assignment and other statements are not expressions. Eval keeps the
327+ // generic parse error rather than a statement-target rewrite.
328+ if !matches ! ( mode, Mode :: Eval ) {
329+ source_error ! ( invalid_plain_assignment_error( source_text) ) ;
330+ source_error ! ( expression_assignment_error( source_text) ) ;
331+ source_error ! ( invalid_annotation_target_error( source_text) ) ;
332+ source_error ! ( invalid_assignment_target_error( source_text) ) ;
333+ source_error ! ( invalid_condition_assignment_error(
334+ source_text,
335+ error. location. start( ) . to_usize( )
336+ ) ) ;
337+ source_error ! ( invalid_augassign_target_error( source_text) ) ;
338+ source_error ! ( invalid_for_target_error( source_text) ) ;
339+ source_error ! ( invalid_with_target_error( source_text) ) ;
340+ source_error ! ( invalid_delete_target_error( source_text) ) ;
341+ source_error ! ( invalid_standalone_except_error( source_text) ) ;
342+ source_error ! ( invalid_import_statement_error( source_text) ) ;
343+ source_error ! ( invalid_import_target_error( source_text) ) ;
344+ source_error ! ( invalid_except_as_target_error( source_text) ) ;
345+ source_error ! ( invalid_match_mapping_rest_wildcard_error( source_text) ) ;
346+ source_error ! ( invalid_match_as_target_error( source_text) ) ;
347+ source_error ! ( invalid_for_if_clause_error( source_text) ) ;
348+ source_error ! ( invalid_if_expression_statement_error( source_text) ) ;
349+ source_error ! ( invalid_else_elif_error( source_text) ) ;
350+ source_error ! ( mixed_except_handlers_error( source_text) ) ;
351+ }
346352
347353 if matches ! (
348354 & error. error,
@@ -381,7 +387,11 @@ fn cpython_parse_diagnostic_override(
381387 // into the generic "invalid syntax" message. rustpython-vm's `vm_new.rs`
382388 // does this same collapse for its own callers; rustpython-compiler has no
383389 // vm dependency, so mirror it here.
384- if matches ! ( & error. error, parser:: ParseErrorType :: ExpectedExpression ) {
390+ if matches ! (
391+ & error. error,
392+ parser:: ParseErrorType :: ExpectedExpression
393+ | parser:: ParseErrorType :: UnexpectedExpressionToken
394+ ) {
385395 let ( loc, end_loc) = adjusted_error_locations ( source_file, error. location ) ;
386396 return Some ( NormalizedParseDiagnostic :: new (
387397 parser:: ParseErrorType :: OtherError ( "invalid syntax" . into ( ) ) ,
@@ -7630,6 +7640,21 @@ mod tests {
76307640 ) ;
76317641 }
76327642
7643+ #[ test]
7644+ fn eval_fstring_assignment_keeps_invalid_syntax ( ) {
7645+ for source in [ "f'' = 3" , "f'{0}' = x" , "f'{x}' = x" ] {
7646+ let err = compile ( source, Mode :: Eval , "<eval>" , CompileOpts :: default ( ) )
7647+ . expect_err ( "assignment is invalid in eval" ) ;
7648+ assert_eq ! ( err. to_string( ) , "invalid syntax" , "{source}" ) ;
7649+ }
7650+ let err = compile ( "f'' = 3" , Mode :: Exec , "<exec>" , CompileOpts :: default ( ) )
7651+ . expect_err ( "f-string is not an assignment target" ) ;
7652+ assert_eq ! (
7653+ err. to_string( ) ,
7654+ "cannot assign to f-string expression here. Maybe you meant '==' instead of '='?"
7655+ ) ;
7656+ }
7657+
76337658 #[ test]
76347659 fn if_assignment_uses_eq_or_walrus_message ( ) {
76357660 let err = compile (
0 commit comments