@@ -400,6 +400,8 @@ def foo(): 1", vec![" test".to_owned(), " test".to_owned(), "".to_owned()], vec!
400400 #[ case:: block( "do \" hello\" end" , "hello" , SymbolKind :: String ) ]
401401 #[ case:: try_( "try: 1 catch: 2" , "try" , SymbolKind :: Try ) ]
402402 #[ case:: catch_( "try: 1 catch: 2" , "catch" , SymbolKind :: Catch ) ]
403+ #[ case:: catch_with_binder( "try: 1 catch(e): e" , "catch" , SymbolKind :: Catch ) ]
404+ #[ case:: catch_error_binder_param( "try: 1 catch(e): e" , "e" , SymbolKind :: Parameter ) ]
403405 #[ case:: symbol_ident( ":foo" , "foo" , SymbolKind :: Symbol ) ]
404406 #[ case:: symbol_string( ":\" hello\" " , "hello" , SymbolKind :: Symbol ) ]
405407 #[ case:: pattern_match( "match (v): | [1,2,3]: 1 end" , "match" , SymbolKind :: Match ) ]
@@ -597,6 +599,68 @@ end"#;
597599 assert ! ( hir. errors( ) . is_empty( ) , "Should have no unresolved symbols" ) ;
598600 }
599601
602+ #[ test]
603+ fn test_catch_error_binder_resolution ( ) {
604+ let mut hir = Hir :: default ( ) ;
605+ hir. builtin . disabled = true ;
606+
607+ let code = "try: 1 catch(e): e" ;
608+ hir. add_code ( None , code) ;
609+
610+ let binder_symbol = hir
611+ . symbols ( )
612+ . find ( |( _, s) | s. kind == SymbolKind :: Parameter && s. value . as_deref ( ) == Some ( "e" ) ) ;
613+ assert ! ( binder_symbol. is_some( ) , "catch(e) should declare e as a Parameter" ) ;
614+
615+ let ref_symbol = hir
616+ . symbols ( )
617+ . find ( |( _, s) | s. kind == SymbolKind :: Ref && s. value . as_deref ( ) == Some ( "e" ) ) ;
618+ assert ! ( ref_symbol. is_some( ) , "Should have a Ref symbol for e in the catch body" ) ;
619+
620+ let ( ref_id, _) = ref_symbol. unwrap ( ) ;
621+ let resolved = hir. resolve_reference_symbol ( ref_id) ;
622+
623+ assert_eq ! (
624+ resolved,
625+ Some ( binder_symbol. unwrap( ) . 0 ) ,
626+ "e in the catch body should resolve to the catch(e) binder"
627+ ) ;
628+ assert ! ( hir. errors( ) . is_empty( ) , "Should have no unresolved symbols" ) ;
629+ }
630+
631+ #[ test]
632+ fn test_catch_error_binder_shadows_outer_variable ( ) {
633+ let mut hir = Hir :: default ( ) ;
634+ hir. builtin . disabled = true ;
635+
636+ let code = "let e = \" hello\" | try: 1 catch(e): e" ;
637+ hir. add_code ( None , code) ;
638+
639+ let outer_e = hir
640+ . symbols ( )
641+ . find ( |( _, s) | s. kind == SymbolKind :: Variable && s. value . as_deref ( ) == Some ( "e" ) )
642+ . unwrap ( )
643+ . 0 ;
644+ let binder_e = hir
645+ . symbols ( )
646+ . find ( |( _, s) | s. kind == SymbolKind :: Parameter && s. value . as_deref ( ) == Some ( "e" ) )
647+ . unwrap ( )
648+ . 0 ;
649+
650+ let ref_symbol = hir
651+ . symbols ( )
652+ . find ( |( _, s) | s. kind == SymbolKind :: Ref && s. value . as_deref ( ) == Some ( "e" ) ) ;
653+ let ( ref_id, _) = ref_symbol. unwrap ( ) ;
654+ let resolved = hir. resolve_reference_symbol ( ref_id) ;
655+
656+ assert_eq ! (
657+ resolved,
658+ Some ( binder_e) ,
659+ "e inside the catch body should resolve to the catch(e) binder, not the outer `let e`"
660+ ) ;
661+ assert_ne ! ( resolved, Some ( outer_e) ) ;
662+ }
663+
600664 #[ test]
601665 fn test_match_expression_basic ( ) {
602666 let mut hir = Hir :: default ( ) ;
0 commit comments