Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:24
erlang
5711-erl_lint-fix-unbound-singleton-types-in-un...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 5711-erl_lint-fix-unbound-singleton-types-in-unions.patch of Package erlang
From 5cc02660d239ee38dee00592bee0e2d575e237f5 Mon Sep 17 00:00:00 2001 From: Kiko Fernandez-Reyes <kiko@erlang.org> Date: Fri, 17 Feb 2023 11:29:32 +0100 Subject: [PATCH 1/5] erl_lint: fix unbound singleton types in unions Dialyzer (erl_lint) was accepting code of the following form: ```erlang -spec run_test(Opts) -> term() when Opts :: {join_specs, Bool} | {test, Bool}. run_test(Opts) -> {error, fail}. ``` But this cannot be ever checked by Dialyzer as the type variable `Bool` is in an union, which means that `Bool` happened only once and thus, `Bool` is an unbound type variable. Essentially, the example above should be rejected by Dialyzer in the same manner as this other one below: ```erlang -spec run_test_error(Opts) -> term() when Opts :: {join_specs, Bool}. run_test_error(Opts) -> {error, fail}. ``` This commit fixes GH-6508 and adds a bunch of tests to `erl_lint.erl` so that we can keep track of which singleton type variables should throw an error and which ones are ok. --- lib/stdlib/src/erl_lint.erl | 19 +++-- lib/stdlib/test/erl_lint_SUITE.erl | 110 ++++++++++++++++++++++++++++- 2 files changed, 122 insertions(+), 7 deletions(-) diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index d6e7d768f3..e0d0117b79 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -3033,12 +3033,21 @@ check_type_2({type, A, record, [Name|Fields]}, SeenVars, St) -> check_record_types(A, Atom, Fields, SeenVars, St1); _ -> {SeenVars, add_error(A, {type_syntax, record}, St)} end; -check_type_2({type, _A, Tag, Args}, SeenVars, St) when Tag =:= product; - Tag =:= union; - Tag =:= tuple -> +check_type_2({type, _A, Tag, Args}=_F, SeenVars, St) when Tag =:= product; + Tag =:= tuple -> lists:foldl(fun(T, {AccSeenVars, AccSt}) -> - check_type_1(T, AccSeenVars, AccSt) - end, {SeenVars, St}, Args); + check_type_1(T, AccSeenVars, AccSt) + end, {SeenVars, St}, Args); +check_type_2({type, _A, union, Args}=_F, SeenVars, St) -> + lists:foldl(fun(T, {AccSeenVars, AccSt}) -> + {SeenVars0, St0} = check_type_1(T, SeenVars, AccSt), + UpdatedSeenVars = maps:merge_with(fun (_K, {seen_once, _}, {seen_once, _}=R) -> R; + (_K, {seen_once, _}, Else) -> Else; + (_K, Else, {seen_once, _}) -> Else; + (_K, Else1, _Else2) -> Else1 + end, SeenVars0, AccSeenVars), + {UpdatedSeenVars, St0} + end, {SeenVars, St}, Args); check_type_2({type, Anno, TypeName, Args}, SeenVars, St) -> #lint{module = Module, types=Types} = St, Arity = length(Args), diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 2331e4f395..93595459d4 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -35,7 +35,8 @@ -export([all/0, suite/0, groups/0]). --export([unused_vars_warn_basic/1, +-export([singleton_type_var_errors/1, + unused_vars_warn_basic/1, unused_vars_warn_lc/1, unused_vars_warn_rec/1, unused_vars_warn_fun/1, @@ -111,7 +112,8 @@ all() -> inline_nifs, warn_missing_spec, otp_16824, underscore_match, unused_record, unused_type2, eep49, - redefined_builtin_type]. + redefined_builtin_type, + singleton_type_var_errors]. groups() -> [{unused_vars_warn, [], @@ -903,6 +905,110 @@ unused_import(Config) when is_list(Config) -> [] = run(Config, Ts), ok. +%% Test singleton type variables +singleton_type_var_errors(Config) when is_list(Config) -> + Ts = [ {singleton_error1 + , <<"-spec test_singleton_typevars_in_union(Opts) -> term() when + Opts :: {ok, Unknown} | {error, Unknown}. + test_singleton_typevars_in_union(_) -> + error. + ">> + , [] + , { errors + , [{{2,36},erl_lint,{singleton_typevar,'Unknown'}}] + , [] + } + } + , { singleton_error2 + , <<"-spec test_singleton_list_typevars_in_union([Opts]) -> term() when + Opts :: {ok, Unknown} | {error, Unknown}. + test_singleton_list_typevars_in_union(_) -> + error.">> + , [] + , { errors + , [{{2,36},erl_lint,{singleton_typevar,'Unknown'}}] + , [] + } + } + , { singleton_error3 + , <<"-spec test_singleton_list_typevars_in_list([Opts]) -> term() when + Opts :: {ok, Unknown}. + test_singleton_list_typevars_in_list(_) -> + error.">> + , [] + , { errors + , [{{2,36},erl_lint,{singleton_typevar,'Unknown'}}] + , [] + } + } + , { singleton_error4 + , <<"-spec test_singleton_list_typevars_in_list_with_type_subst([{ok, Unknown}]) -> term(). + test_singleton_list_typevars_in_list_with_type_subst(_) -> + error.">> + , [] + , { errors + , [{{1,86},erl_lint,{singleton_typevar,'Unknown'}}] + , [] + } + } + , { singleton_error5 + , <<"-spec test_singleton_buried_typevars_in_union(Opts) -> term() when + Opts :: {ok, Foo} | {error, Foo}, + Foo :: {true, X} | {false, X}. + test_singleton_buried_typevars_in_union(_) -> + error.">> + , [] + , { errors + , [{{3,38},erl_lint,{singleton_typevar,'X'}}] + , [] + } + } + , { singleton_error6 + , <<"-spec test_multiple_subtypes_to_same_typevar(Opts) -> term() when + Opts :: {Foo, Bar} | Y, + Foo :: X, + Bar :: X, + Y :: Z. + test_multiple_subtypes_to_same_typevar(_) -> + error.">> + , [] + , { errors + , [{{5,31},erl_lint,{singleton_typevar,'Z'}}] + , [] + } + } + , { singleton_error7 + , <<"-spec test_duplicate_non_terminal_var_in_union(Opts) -> term() when + Opts :: {ok, U, U} | {error, U, U}, + U :: Foo. + test_duplicate_non_terminal_var_in_union(_) -> + error.">> + , [] + , { errors + , [{{3,31},erl_lint,{singleton_typevar,'Foo'}}] + , [] + } + } + , { singleton_ok1 + , <<"-spec test_multiple_occurrences_singleton(Opts) -> term() when + Opts :: {Foo, Foo}. + test_multiple_occurrences_singleton(_) -> + ok.">> + , [] + , [] + } + , { singleton_ok2 + , <<"-spec id(X) -> X. + id(X) -> + X.">> + , [] + , [] + } + + ], + [] = run(Config, Ts), + ok. + %% Test warnings for unused functions. unused_function(Config) when is_list(Config) -> Ts = [{func1, -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor