From a6471109a41af9e2b085270bba483c410760a372 Mon Sep 17 00:00:00 2001 From: Radek Szymczyszyn Date: Tue, 30 Aug 2022 19:43:19 +0200 Subject: [PATCH 1/3] Add test/should_pass/record_union_with_any_should_pass.erl --- .../record_union_with_any_should_pass.erl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 test/should_pass/record_union_with_any_should_pass.erl diff --git a/test/should_pass/record_union_with_any_should_pass.erl b/test/should_pass/record_union_with_any_should_pass.erl new file mode 100644 index 00000000..e9fe2dc3 --- /dev/null +++ b/test/should_pass/record_union_with_any_should_pass.erl @@ -0,0 +1,14 @@ +-module(record_union_with_any_should_pass). + +-export([f/1, + g/0]). + +-record(r, {field}). + +-spec f(_) -> #r{} | any(). +f(R) -> + R#r{field = val}. + +-spec g() -> #r{} | any(). +g() -> + #r{field = val}. From b598be2f75ca92911195b2ff75ad692c69edc5e5 Mon Sep 17 00:00:00 2001 From: Radek Szymczyszyn Date: Tue, 30 Aug 2022 19:53:40 +0200 Subject: [PATCH 2/3] Fix crash when any() is found in a record union --- src/typechecker.erl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/typechecker.erl b/src/typechecker.erl index 9efbb8f9..e192ed88 100644 --- a/src/typechecker.erl +++ b/src/typechecker.erl @@ -2462,7 +2462,10 @@ do_type_check_expr_in(Env, ResTy, {record, Anno, Name, Fields} = Record) -> {VarBinds, Cs2} = type_check_fields(Env, Rec, Fields), {VarBinds, constraints:combine(Cs1, Cs2)}; {fields_tys, Tyss, Cs1} -> - case type_check_record_union_in(Env, Tyss, Fields) of + Tyss2 = lists:map(fun (?type(any)) -> get_record_fields(Name, Anno, Env); + (Other) -> Other + end, Tyss), + case type_check_record_union_in(Env, Tyss2, Fields) of none -> {Ty, _VB, _Cs} = type_check_expr(Env#env{infer = true}, Record), throw(type_error(Record, Ty, ResTy)); @@ -2493,7 +2496,10 @@ do_type_check_expr_in(Env, ResTy, {record, Anno, Exp, Name, Fields} = Record) -> {union_var_binds([VarBinds|VarBindsList], Env) ,constraints:combine([Cs1, Cs2|Css])}; {fields_tys, Tyss, Cs1} -> - case type_check_record_union_in(Env, Tyss, Fields) of + Tyss2 = lists:map(fun (?type(any)) -> get_record_fields(Name, Anno, Env); + (Other) -> Other + end, Tyss), + case type_check_record_union_in(Env, Tyss2, Fields) of none -> {Ty, _VB, _Cs} = type_check_expr(Env#env{infer = true}, Record), throw(type_error(Record, Ty, ResTy)); From 8a1e4f478ed1a0fc7775d5d3d5dc6a2057eedc6e Mon Sep 17 00:00:00 2001 From: Radek Szymczyszyn Date: Wed, 31 Aug 2022 16:18:11 +0200 Subject: [PATCH 3/3] Pull in getting the record def into type_check_record_union_in --- src/typechecker.erl | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/typechecker.erl b/src/typechecker.erl index e192ed88..00dd2006 100644 --- a/src/typechecker.erl +++ b/src/typechecker.erl @@ -2462,10 +2462,7 @@ do_type_check_expr_in(Env, ResTy, {record, Anno, Name, Fields} = Record) -> {VarBinds, Cs2} = type_check_fields(Env, Rec, Fields), {VarBinds, constraints:combine(Cs1, Cs2)}; {fields_tys, Tyss, Cs1} -> - Tyss2 = lists:map(fun (?type(any)) -> get_record_fields(Name, Anno, Env); - (Other) -> Other - end, Tyss), - case type_check_record_union_in(Env, Tyss2, Fields) of + case type_check_record_union_in(Name, Anno, Tyss, Fields, Env) of none -> {Ty, _VB, _Cs} = type_check_expr(Env#env{infer = true}, Record), throw(type_error(Record, Ty, ResTy)); @@ -2496,10 +2493,7 @@ do_type_check_expr_in(Env, ResTy, {record, Anno, Exp, Name, Fields} = Record) -> {union_var_binds([VarBinds|VarBindsList], Env) ,constraints:combine([Cs1, Cs2|Css])}; {fields_tys, Tyss, Cs1} -> - Tyss2 = lists:map(fun (?type(any)) -> get_record_fields(Name, Anno, Env); - (Other) -> Other - end, Tyss), - case type_check_record_union_in(Env, Tyss2, Fields) of + case type_check_record_union_in(Name, Anno, Tyss, Fields, Env) of none -> {Ty, _VB, _Cs} = type_check_expr(Env#env{infer = true}, Record), throw(type_error(Record, Ty, ResTy)); @@ -3347,16 +3341,24 @@ type_check_tuple_union_in(Env, [Tys|Tyss], Elems) -> type_check_tuple_union_in(_Env, [], _Elems) -> none. --spec type_check_record_union_in(env(), [[typed_record_field()]], [expr()]) -> R when +-spec type_check_record_union_in(Name, Anno, Tyss, Fields, Env) -> R when + Name :: atom(), + Anno :: anno(), + Tyss :: [[typed_record_field()]], + Fields :: [expr()], + Env :: env(), R :: {env(), constraints:constraints()} | none. -type_check_record_union_in(Env, [Tys|Tyss], Fields) -> +type_check_record_union_in(Name, Anno, [?type(any) | Tyss], Fields, Env) -> + Rec = get_record_fields(Name, Anno, Env), + type_check_record_union_in(Name, Anno, [Rec | Tyss], Fields, Env); +type_check_record_union_in(Name, Anno, [Tys|Tyss], Fields, Env) -> try type_check_fields(Env, Tys, Fields) catch - E when element(1,E) == type_error -> - type_check_record_union_in(Env, Tyss, Fields) + E when element(1, E) == type_error -> + type_check_record_union_in(Name, Anno, Tyss, Fields, Env) end; -type_check_record_union_in(_Env, [], _Fields) -> +type_check_record_union_in(_Name, _Anno, [], _Fields, _Env) -> none. get_bounded_fun_type_list(Name, Arity, Env, P) ->