diff --git a/lib/parser/context.rb b/lib/parser/context.rb index ff5f24dcf..cb5411ef8 100644 --- a/lib/parser/context.rb +++ b/lib/parser/context.rb @@ -24,6 +24,7 @@ class Context in_class in_block in_lambda + cant_return ] def initialize @@ -38,6 +39,7 @@ def reset @in_class = false @in_block = false @in_lambda = false + @cant_return = false end attr_accessor(*FLAGS) diff --git a/lib/parser/ruby34.y b/lib/parser/ruby34.y index 8e5760195..89602826b 100644 --- a/lib/parser/ruby34.y +++ b/lib/parser/ruby34.y @@ -366,6 +366,7 @@ rule result = [ val[0], @context.dup ] @context.in_def = true + @context.cant_return = false } defn_head: k_def def_name @@ -1319,6 +1320,7 @@ rule | k_class cpath superclass { @context.in_class = true + @context.cant_return = true local_push } bodystmt kEND @@ -1334,11 +1336,13 @@ rule local_pop @context.in_class = ctx.in_class + @context.cant_return = ctx.cant_return } | k_class tLSHFT expr_value term { @context.in_def = false @context.in_class = false + @context.cant_return = true local_push } bodystmt kEND @@ -1350,10 +1354,12 @@ rule local_pop @context.in_def = ctx.in_def @context.in_class = ctx.in_class + @context.cant_return = ctx.cant_return } | k_module cpath { @context.in_class = true + @context.cant_return = true local_push } bodystmt kEND @@ -1367,6 +1373,7 @@ rule local_pop @context.in_class = ctx.in_class + @context.cant_return = ctx.cant_return } | defn_head f_arglist bodystmt kEND { @@ -1425,7 +1432,7 @@ rule k_return: kRETURN { - if @context.in_class && !@context.in_def && !(context.in_block || context.in_lambda) + if @context.cant_return && !(context.in_block || context.in_lambda) diagnostic :error, :invalid_return, nil, val[0] end } diff --git a/test/test_parser.rb b/test/test_parser.rb index f146a5522..17efcf870 100644 --- a/test/test_parser.rb +++ b/test/test_parser.rb @@ -6805,7 +6805,8 @@ def test_context_class %q{class A; get_context; end}, %q{class A < B; get_context; end} ].each do |code| - assert_context([:in_class], code, ALL_VERSIONS) + assert_context([:in_class], code, ALL_VERSIONS - SINCE_3_4) + assert_context([:in_class, :cant_return], code, SINCE_3_4) end end @@ -6813,7 +6814,20 @@ def test_context_module assert_context( [:in_class], %q{module M; get_context; end}, - ALL_VERSIONS) + ALL_VERSIONS - SINCE_3_4) + assert_context( + [:in_class, :cant_return], + %q{module M; get_context; end}, + SINCE_3_4) + end + + def test_context_sclass + [ + %q{class << foo; get_context; end}, + %q{class A; class << self; get_context; end; end} + ].each do |code| + assert_context([:cant_return], code, SINCE_3_4) + end end def test_context_def @@ -6900,15 +6914,21 @@ def test_return_in_class SINCE_2_5) [ - %q{class << foo; return; end}, %q{def m; return; end}, %q{tap { return }}, - %q{class A; class << self; return; end; end}, + %q{class A; class << self; def m; return; end; end; end}, %q{class A; def m; return; end; end}, ].each do |code| refute_diagnoses(code, ALL_VERSIONS) end + [ + %q{class << foo; return; end}, + %q{class A; class << self; return; end; end}, + ].each do |code| + refute_diagnoses(code, ALL_VERSIONS - SINCE_3_4) + end + [ %q{-> do return end}, %q{class A; -> do return end; end}, @@ -6917,6 +6937,20 @@ def test_return_in_class end end + def test_return_in_sclass_since_34 + assert_diagnoses( + [:error, :invalid_return, {}], + %q{class << foo; return; end}, + %q{ ^^^^^^ location}, + SINCE_3_4) + + assert_diagnoses( + [:error, :invalid_return, {}], + %q{class A; class << self; return; end; end}, + %q{ ^^^^^^ location}, + SINCE_3_4) + end + def test_method_definition_in_while_cond assert_parses( s(:while,