From 83eda421d5da52328f5c5f552967591e22a0695e Mon Sep 17 00:00:00 2001 From: Svilen Ivanov Date: Sat, 17 Jun 2017 15:16:50 +0300 Subject: Fix infinite loop in shell caused by record with recursive typespec If record with recursive typespec such as -record(r,{f :: #r{} | undefined}). is used in interactive shell it stucks in inifinite loop when trying to find definitions for all records used in expression. --- lib/stdlib/src/shell.erl | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl index 6eafc7b209..26b3960f4f 100644 --- a/lib/stdlib/src/shell.erl +++ b/lib/stdlib/src/shell.erl @@ -727,7 +727,7 @@ result_will_be_saved() -> used_record_defs(E, RT) -> %% Be careful to return a list where used records come before %% records that use them. The linter wants them ordered that way. - UR = case used_records(E, [], RT) of + UR = case used_records(E, [], RT, []) of [] -> []; L0 -> @@ -737,13 +737,19 @@ used_record_defs(E, RT) -> end, record_defs(RT, UR). -used_records(E, U0, RT) -> +used_records(E, U0, RT, Skip) -> case used_records(E) of {name,Name,E1} -> - U = used_records(ets:lookup(RT, Name), [Name | U0], RT), - used_records(E1, U, RT); + U = case lists:member(Name, Skip) of + true -> + U0; + false -> + R = ets:lookup(RT, Name), + used_records(R, [Name | U0], RT, [Name | Skip]) + end, + used_records(E1, U, RT, Skip); {expr,[E1 | Es]} -> - used_records(Es, used_records(E1, U0, RT), RT); + used_records(Es, used_records(E1, U0, RT, Skip), RT, Skip); _ -> U0 end. -- cgit v1.2.3 From 55fe5402cedce9d664fea9aaa5928feccaf641be Mon Sep 17 00:00:00 2001 From: Svilen Ivanov Date: Mon, 19 Jun 2017 22:22:02 +0300 Subject: Add test for using typed records in shell --- lib/stdlib/test/shell_SUITE.erl | 50 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl index 4f0fdc4c6a..217e8cc252 100644 --- a/lib/stdlib/test/shell_SUITE.erl +++ b/lib/stdlib/test/shell_SUITE.erl @@ -31,7 +31,7 @@ progex_lc/1, progex_funs/1, otp_5990/1, otp_6166/1, otp_6554/1, otp_7184/1, otp_7232/1, otp_8393/1, otp_10302/1, otp_13719/1, - otp_14285/1, otp_14296/1]). + otp_14285/1, otp_14296/1, typed_records/1]). -export([ start_restricted_from_shell/1, start_restricted_on_command_line/1,restricted_local/1]). @@ -74,10 +74,10 @@ suite() -> {timetrap,{minutes,10}}]. all() -> - [forget, records, known_bugs, otp_5226, otp_5327, + [forget, known_bugs, otp_5226, otp_5327, otp_5435, otp_5195, otp_5915, otp_5916, {group, bits}, {group, refman}, {group, progex}, {group, tickets}, - {group, restricted}]. + {group, restricted}, {group, records}]. groups() -> [{restricted, [], @@ -86,6 +86,8 @@ groups() -> {bits, [], [bs_match_misc_SUITE, bs_match_tail_SUITE, bs_match_bin_SUITE, bs_construct_SUITE]}, + {records, [], + [records, typed_records]}, {refman, [], [refman_bit_syntax]}, {progex, [], [progex_bit_syntax, progex_records, progex_lc, @@ -486,6 +488,48 @@ records(Config) when is_list(Config) -> ok. +%% Test of typed record support. +typed_records(Config) when is_list(Config) -> + Test = filename:join(proplists:get_value(priv_dir, Config), "test.hrl"), + Contents = <<"-module(test). + -record(r0,{f :: any()}). + -record(r1,{f1 :: #r1{} | undefined, f2 :: #r0{} | atom()}). + -record(r2,{f :: #r2{} | undefined}). + ">>, + ok = file:write_file(Test, Contents), + + RR1 = "rr(\"" ++ Test ++ "\"), + #r1{} = (#r1{f1=#r1{f1=undefined, f2=x}, f2 = #r0{}})#r1.f1, + ok.", + RR2 = "rr(\"" ++ Test ++ "\"), + #r0{} = (#r1{f1=#r1{f1=undefined, f2=x}, f2 = #r0{}})#r1.f2, + ok. ", + RR3 = "rr(\"" ++ Test ++ "\"), + #r1{f2=#r0{}} = (#r1{f1=#r1{f1=undefined, f2=#r0{}}, f2 = x})#r1.f1, + ok.", + RR4 = "rr(\"" ++ Test ++ "\"), + (#r1{f2 = #r0{}})#r1{f2 = x}, + ok. ", + RR5 = "rr(\"" ++ Test ++ "\"), + (#r1{f2 = #r0{}})#r1{f1 = #r1{}}, + ok. ", + RR6 = "rr(\"" ++ Test ++ "\"), + (#r2{f=#r2{f=undefined}})#r2.f, + ok.", + RR7 = "rr(\"" ++ Test ++ "\"), + #r2{} = (#r2{f=#r2{f=undefined}})#r2.f, + ok.", + [ok] = scan(RR1), + [ok] = scan(RR2), + [ok] = scan(RR3), + [ok] = scan(RR4), + [ok] = scan(RR5), + [ok] = scan(RR6), + [ok] = scan(RR7), + + file:delete(Test), + ok. + %% Known bugs. known_bugs(Config) when is_list(Config) -> %% erl_eval:merge_bindings/2 cannot handle _removal_ of bindings. -- cgit v1.2.3