Project

General

Profile

Actions

Bug #21540

closed

prism allows `foo && return bar` when parse.y doesn't

Added by Earlopain (Earlopain _) about 1 month ago. Updated 2 days ago.

Status:
Closed
Assignee:
Target version:
-
ruby -v:
ruby 3.5.0dev (2025-08-08T02:57:23Z master 3ad26d0501) [x86_64-linux]
[ruby-core:122953]

Description

Code such as foo && return bar has been disallowed in ruby since at least Ruby 2.0. Prism allows it though:

$ ruby -cve "a && return foo"
ruby 3.5.0dev (2025-08-08T02:57:23Z master 3ad26d0501) +PRISM [x86_64-linux]
Syntax OK

$ ruby --parser=parse.y -cve "a && return foo"
ruby 3.5.0dev (2025-08-08T02:57:23Z master 3ad26d0501) [x86_64-linux]
-e:1: syntax error, unexpected local variable or method, expecting end-of-input
a && return foo
ruby: compile error (SyntaxError)

The code seems to behave like I'd expect it to and I wouldn't mind it being accepted but it is inconsistent. Also happens on Ruby 3.4

Actions #1

Updated by Earlopain (Earlopain _) about 1 month ago

  • Description updated (diff)

Updated by nobu (Nobuyoshi Nakada) about 1 month ago

It is because of the precedence, and has been since 1.x at least.

Actions #3

Updated by nobu (Nobuyoshi Nakada) about 1 month ago

  • Backport changed from 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN to 3.2: DONTNEED, 3.3: DONTNEED, 3.4: REQUIRED

Updated by Earlopain (Earlopain _) about 1 month ago

Right, I understand. foo && (return bar) would be allowed, thanks for clarifying (works as expected in prism and parse.y)

Updated by naruse (Yui NARUSE) 25 days ago

  • Status changed from Open to Assigned
  • Assignee set to prism

Updated by Eregon (Benoit Daloze) 24 days ago ยท Edited

Given it's ruby: compile error (SyntaxError) from parse.y I guess it's a check done in compile.c and missing in prism_compile.c, if so it's not an issue in the parser itself but in the validation done by the bytecode compiler.

Updated by Earlopain (Earlopain _) 23 days ago

That's just how parse.y shows its syntax errors in general, you can check with any other syntax error. -c doesn't involve the compiler.

Anyways, if it was done in the compiler then other implementations would need to handle it as well and consumers of prism can successfully parse code that ruby would otherwise reject at runtime with a syntax error.

Updated by Eregon (Benoit Daloze) 23 days ago

Indeed, you're right:

Thread 1 "ruby" hit Breakpoint 1, syntax_error_initialize (argc=0, argv=0x0, self=140736655388480) at error.c:2943
warning: 2943	error.c: No such file or directory
(gdb) bt
#0  syntax_error_initialize (argc=0, argv=0x0, self=140736655388480) at error.c:2943
#1  0x00007ffff7af993b in vm_call0_cfunc_with_frame (ec=0x40dd00, calling=0x7fffffffbee0, argv=0x0) at /tmp/ruby-build.20250215124933.32308.uR2rR3/ruby-3.4.2/vm_eval.c:164
#2  vm_call0_cfunc (ec=0x40dd00, calling=0x7fffffffbee0, argv=0x0) at /tmp/ruby-build.20250215124933.32308.uR2rR3/ruby-3.4.2/vm_eval.c:178
#3  vm_call0_body (ec=ec@entry=0x40dd00, calling=calling@entry=0x7fffffffc030, argv=argv@entry=0x0) at /tmp/ruby-build.20250215124933.32308.uR2rR3/ruby-3.4.2/vm_eval.c:229
#4  0x00007ffff7afe534 in vm_call0_cc (ec=0x40dd00, recv=140736655388480, id=3169, argc=0, argv=0x0, cc=0x7fffce59ef18, kw_splat=<optimized out>) at /tmp/ruby-build.20250215124933.32308.uR2rR3/ruby-3.4.2/vm_eval.c:101
#5  rb_call0 (ec=0x40dd00, recv=recv@entry=140736655388480, mid=mid@entry=3169, argc=argc@entry=0, argv=argv@entry=0x0, call_scope=call_scope@entry=CALL_FCALL, self=140737353010600) at /tmp/ruby-build.20250215124933.32308.uR2rR3/ruby-3.4.2/vm_eval.c:554
#6  0x00007ffff7afefb2 in rb_call (recv=140736655388480, mid=3169, argc=0, argv=0x0, scope=CALL_FCALL) at /tmp/ruby-build.20250215124933.32308.uR2rR3/ruby-3.4.2/vm_eval.c:873
#7  rb_funcallv_kw (recv=recv@entry=140736655388480, mid=mid@entry=3169, argc=argc@entry=0, argv=argv@entry=0x0, kw_splat=kw_splat@entry=0) at /tmp/ruby-build.20250215124933.32308.uR2rR3/ruby-3.4.2/vm_eval.c:1070
#8  0x00007ffff78f2a1f in rb_obj_call_init_kw (obj=obj@entry=140736655388480, argc=argc@entry=0, argv=argv@entry=0x0, kw_splat=kw_splat@entry=0) at eval.c:1752
#9  0x00007ffff799378d in rb_class_new_instance_kw (argc=0, argv=0x0, klass=140737353079040, kw_splat=kw_splat@entry=0) at object.c:2191
#10 0x00007ffff79937b7 in rb_class_new_instance (argc=<optimized out>, argv=<optimized out>, klass=<optimized out>) at object.c:2199
#11 0x00007ffff79d1361 in syntax_error_new () at /tmp/ruby-build.20250215124933.32308.uR2rR3/ruby-3.4.2/parse.y:75
#12 yycompile0 (arg=arg@entry=4958656) at /tmp/ruby-build.20250215124933.32308.uR2rR3/ruby-3.4.2/parse.y:7558
#13 0x00007ffff7b0ffbd in rb_suppress_tracing (func=func@entry=0x7ffff79d1060 <yycompile0>, arg=arg@entry=4958656) at vm_trace.c:487
#14 0x00007ffff79ac10f in yycompile (p=0x4ba9c0, fname=<optimized out>, line=1) at /tmp/ruby-build.20250215124933.32308.uR2rR3/ruby-3.4.2/parse.y:7604
#15 rb_parser_compile (p=0x4ba9c0, gets=gets@entry=0x7ffff7a42860 <lex_get_str>, fname=fname@entry=140736655388760, input=input@entry=0x4bac10, line=line@entry=1) at /tmp/ruby-build.20250215124933.32308.uR2rR3/ruby-3.4.2/parse.y:7644
#16 0x00007ffff7a42b5c in parser_compile (p=<optimized out>, gets=0x7ffff7a42860 <lex_get_str>, fname=140736655388760, input=0x4bac10, line=1) at ruby_parser.c:649
#17 parser_compile_string0 (parser=0x4bac00, fname=140736655388760, s=140736685089480, line=1) at ruby_parser.c:663
#18 parser_compile_string_path (parser=0x4bac00, f=140736655388760, s=140736685089480, line=1) at ruby_parser.c:680
#19 parser_compile_string (parser=0x4bac00, f=<optimized out>, s=140736685089480, line=1) at ruby_parser.c:686
#20 rb_parser_compile_string (vparser=<optimized out>, vparser@entry=140736655388880, f=<optimized out>, s=140736685089480, line=line@entry=1) at ruby_parser.c:812
#21 0x00007ffff7a41186 in process_script (opt=0x7fffffffd850) at ruby.c:2094
#22 process_options (argc=0, argc@entry=4, argv=0x7fffffffdb68, argv@entry=0x7fffffffdb48, opt=opt@entry=0x7fffffffd850) at ruby.c:2534
#23 0x00007ffff7a41e7e in ruby_process_options (argc=argc@entry=4, argv=argv@entry=0x7fffffffdb48) at ruby.c:228
#24 0x00007ffff78f1e48 in ruby_options (argc=argc@entry=4, argv=argv@entry=0x7fffffffdb48) at eval.c:117
#25 0x00000000004010f8 in rb_main (argc=4, argv=0x7fffffffdb48) at ./main.c:43
#26 main (argc=<optimized out>, argv=<optimized out>) at ./main.c:68

And syntax_error_initialize defaults to "compile error" if there is no message, that's quite confusing, I assumed "compile error" to mean "error while compiling to bytecode".

Updated by naruse (Yui NARUSE) 2 days ago

@prism This issue breaks Ruby's compatibility. This should be fixed before Ruby 3.5 (or 4.0) is released. But this issue looks not worked even if there is a PR. I worried that prism is now well maintained or not. As release manager, I also worried this situation is not enough healthy for Ruby 3.5. Could you handle prism issues?

Updated by kddnewton (Kevin Newton) 2 days ago

I will make a PR for this as soon as possible to get it ready for the 3.5 release.

Updated by kddnewton (Kevin Newton) 2 days ago

  • Status changed from Assigned to Closed

Thanks to @Earlopain this is now done. https://github.com/ruby/prism/pull/3630

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0