Project

General

Profile

Bug #19392

Updated by zverok (Victor Shepelev) 5 months ago

**Initial description** 

 [Discovered](https://twitter.com/lucianghinda/status/1617783952353406977) by Lucian Ghinda:  

 ```ruby 
 def test = puts("foo") and puts("bar") 
 # prints "bar" immediately 
 test 
 # prints "foo" 
 ``` 

 It seems that it is a parser error, right?.. 
 ```ruby 
 RubyVM::AbstractSyntaxTree.parse('def test = puts("foo") and puts("bar")') 
 #    =>  
 # (SCOPE@1:0-1:38                                                          
 #    tbl: []                                                                 
 #    args: nil                                                               
 #    body:                                                                   
 #      (AND@1:0-1:38                                                         
 #         (DEFN@1:0-1:22                                                     
 #          mid: :test                                                        
 #          body:                                                             
 #            (SCOPE@1:0-1:22                                                 
 #             tbl: []                                                        
 #             args:                                                          
 #               (ARGS@1:0-1:8 pre_num: 0 pre_init: nil opt: nil first_post: nil post_num: 0 post_init: nil rest: nil kw: nil kwrest: nil block: nil) 
 #             body: (FCALL@1:11-1:22 :puts (LIST@1:16-1:21 (STR@1:16-1:21 "foo") nil)))) 
 #         (FCALL@1:27-1:38 :puts (LIST@1:32-1:37 (STR@1:32-1:37 "bar") nil))))  
 ``` 

 E.g. it is parsed as  
 ```ruby 
 (def test = puts("foo")) and (puts("bar")) 
 ``` 
 ...which is hardly intentional or have any practical use. The rightly parsed code in this case _can_ have practical use, like 
 ```ruby 
 def write(data) = File.write(@filename, data) == data.size or raise "Something went wrong" 
 ``` 

 **Additional cases of what seems to be the same problem** 

 ```ruby 
 def save = File.write(name, self.to_yaml) unless invalid? 
 # Parsed as: 
 (def save = File.write(name, self.to_yaml)) unless invalid? 
 ``` 
 ...which makes it very hard for the users to diagnose the real reason, see #19731 

 ```ruby 
 def initialize(a, b) = @a, b = a, b 
 # syntax error, unexpected ',', expecting end-of-input (SyntaxError)                                                  
 # def initialize(a, b) = @a, b = a, b                             
 #                            ^          

 # Again, parsed as 
 (def initialize(a, b) = @a), b = a, b 
 ``` 
 While this one is at least diagnosed early, in pathological cases, it might lead to very subtle bugs: 
 ```ruby 
 private def start = @operation, @conversion = :print, :to_s 
 ``` 
 This code doesn't throw a syntax error, but its effect is very far from expected. Again, it is parsed as 
 ```ruby 
 private( (def start = @operation), @conversion = :print, :to_s ) 
 ``` 
 ...and ends up in: 
 * defining a private method `start` 
 * making private methods `:print` and `:to_s` 

Back