File 3572-features-Clean-up-naming-and-more.patch of Package erlang
From 14c58f82e7c229e3d34eb99af3188521f2c25add Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cons=20T=20=C3=85hs?= <cons@erlang.org>
Date: Tue, 26 Apr 2022 15:57:22 +0200
Subject: [PATCH 2/6] [features] Clean up naming and more
* Improve naming in erl_features
* feature_info/1 -> info/1
* features/0 -> all/0
* features_used/1 -> used/1
* features_enabled/0 -> enabled/0
* Rename and unexport internal functions
* Add specs and improve typing
* Testing
* Improve possibilities to debug tests on failure
* Add simple tests for info/1 and features/0
* Add tests for long/short feature descriptions
* Fix typos in test features
---
erts/test/lux/bad_feature_erlc.lux | 4 +-
erts/test/lux/feature_erl.lux | 38 ++++++--
erts/test/lux/feature_erlc.lux | 26 ++++-
erts/test/lux/feature_runtime.lux | 14 +--
erts/test/lux/features.luxinc | 10 +-
lib/stdlib/src/epp.erl | 5 +-
lib/stdlib/src/erl_compile.erl | 11 ++-
lib/stdlib/src/erl_features.erl | 152 +++++++++++++++--------------
lib/stdlib/src/erl_lint.erl | 2 +-
9 files changed, 159 insertions(+), 103 deletions(-)
diff --git a/erts/test/lux/bad_feature_erlc.lux b/erts/test/lux/bad_feature_erlc.lux
index 903696d2ce..bd8b8b76e8 100644
--- a/erts/test/lux/bad_feature_erlc.lux
+++ b/erts/test/lux/bad_feature_erlc.lux
@@ -186,14 +186,14 @@
[shell erl]
# Verify that only ifn_expr is used
- !Fs = erl_features:features_used(f_directives_2).
+ !Fs = erl_features:used(f_directives_2).
?$ERLPROMPT
[invoke same-members Fs "[ifn_expr,cond_expr,maps]"]
!f(Fs).
?$ERLPROMPT
# Verify that only ifn_expr is used
- !Fs = erl_features:features_used(f_directives_3).
+ !Fs = erl_features:used(f_directives_3).
?$ERLPROMPT
[invoke same-members Fs "[ifn_expr,cond_expr,maps]"]
!f(Fs).
diff --git a/erts/test/lux/feature_erl.lux b/erts/test/lux/feature_erl.lux
index 88d71a06a6..1205f9a601 100644
--- a/erts/test/lux/feature_erl.lux
+++ b/erts/test/lux/feature_erl.lux
@@ -10,39 +10,59 @@
-undefined function
[invoke start-erl ""]
- [invoke same-members "erl_features:enabled_features()" "[maps,cond_expr]"]
+ # Verify that the known test features are returned
+ [invoke same-members "erl_features:all()" "[maps,cond_expr,while_expr,ifn_expr,ifnot_expr,unless_expr]"]
+
+ # Verify that we get an error if trying to get information about
+ # an unknown feature.
+ !erl_features:info(loop_expr).
+ ?error.*invalid_feature
+ ?unknown feature
+ ?$ERLPROMPT
+
+ # Verify that we get a map with info for a known feature
+ !IMap = erl_features:info(maps).
+ ?$ERLPROMPT
+ !is_map(IMap).
+ ?true
+ ?$ERLPROMPT
+ !lists:all(fun(K) -> is_map_key(K, IMap) end, [status,type,description,short,experimental]).
+ ?true
+ ?$ERLPROMPT
+
+ [invoke same-members "erl_features:enabled()" "[maps,cond_expr]"]
[invoke quit-erl]
[invoke start-erl "-enable-feature ifn_expr"]
- [invoke same-members "erl_features:enabled_features()" "[maps,cond_expr,ifn_expr]"]
+ [invoke same-members "erl_features:enabled()" "[maps,cond_expr,ifn_expr]"]
[invoke quit-erl]
[invoke start-erl "-enable-feature ifn_expr -enable-feature while_expr"]
- [invoke same-members "erl_features:enabled_features()" "[maps,cond_expr,while_expr,ifn_expr]"]
+ [invoke same-members "erl_features:enabled()" "[maps,cond_expr,while_expr,ifn_expr]"]
[invoke quit-erl]
[invoke start-erl "-enable-feature ifn_expr while_expr"]
- [invoke same-members "erl_features:enabled_features()" "[cond_expr,maps,while_expr,ifn_expr]"]
+ [invoke same-members "erl_features:enabled()" "[cond_expr,maps,while_expr,ifn_expr]"]
[invoke quit-erl]
[invoke start-erl "-enable-feature ifn_expr while_expr -enable-feature ifnot_expr"]
- [invoke same-members "erl_features:enabled_features()" "[cond_expr,maps,while_expr,ifn_expr,ifnot_expr]"]
+ [invoke same-members "erl_features:enabled()" "[cond_expr,maps,while_expr,ifn_expr,ifnot_expr]"]
[invoke quit-erl]
# Enabling the same feature twice does not hurt
[invoke start-erl "-enable-feature ifn_expr while_expr -enable-feature ifnot_expr ifn_expr"]
- [invoke same-members "erl_features:enabled_features()" "[cond_expr,maps,while_expr,ifn_expr,ifnot_expr]"]
+ [invoke same-members "erl_features:enabled()" "[cond_expr,maps,while_expr,ifn_expr,ifnot_expr]"]
[invoke quit-erl]
@@ -52,18 +72,18 @@
# problem since we have a lazy init of the feature set.
[invoke start-erl "-enable-feature no_ftr"]
- [invoke same-members "erl_features:enabled_features()" "[cond_expr,maps]"]
+ [invoke same-members "erl_features:enabled()" "[cond_expr,maps]"]
[invoke quit-erl]
[invoke start-erl "-disable-feature cond_expr"]
- [invoke same-members "erl_features:enabled_features()" "[maps]"]
+ [invoke same-members "erl_features:enabled()" "[maps]"]
# FIXME Need to check that keywords have changed as well!
[invoke quit-erl]
[invoke start-erl "-disable-feature all"]
- !erl_features:enabled_features().
+ !erl_features:enabled().
??[]
?$ERLPROMPT
diff --git a/erts/test/lux/feature_erlc.lux b/erts/test/lux/feature_erlc.lux
index 3a033d0aad..5082f56ad1 100644
--- a/erts/test/lux/feature_erlc.lux
+++ b/erts/test/lux/feature_erlc.lux
@@ -196,7 +196,7 @@
??{error,not_allowed}
?$ERLPROMPT
- !Fs = erl_features:features_used(f_maybe_ifn).
+ !Fs = erl_features:used(f_maybe_ifn).
[invoke same-members Fs "[cond_expr,maps,while_expr,ifn_expr]"]
!f(Fs).
?$ERLPROMPT
@@ -249,7 +249,7 @@
?$ERLPROMPT
# Check which features were used during compilation
- !Fs = erl_features:features_used(f_macros).
+ !Fs = erl_features:used(f_macros).
?$ERLPROMPT
[invoke same-members Fs "[maps,cond_expr,ifn_expr]"]
!f(Fs).
@@ -405,7 +405,7 @@
[invoke ok]
[shell erl]
- !Fs = erl_features:features_used(foo).
+ !Fs = erl_features:used(foo).
?$ERLPROMPT
[invoke same-members Fs "[unless_expr,ifn_expr,while_expr,cond_expr,maps,ifnot_expr]"]
!f(Fs).
@@ -419,7 +419,7 @@
[invoke ok]
[shell erl]
- !Fs = erl_features:features_used(foo).
+ !Fs = erl_features:used(foo).
?$ERLPROMPT
!maps:from_keys([ifn_expr,while_expr,cond_expr,maps,ifnot_expr], foo) == maps:from_keys(Fs, foo).
?true
@@ -427,6 +427,24 @@
!f(Fs).
?$ERLPROMPT
+[shell cmds]
+ !erlc -list-features
+ ?cond_expr
+ ?ifn_expr
+ ?ifnot_expr
+ ?maps
+ ?unless_expr
+ ?while_expr
+ ?SH-PROMPT:
+
+ !erlc -describe-feature maps
+ ?Add new data type for maps
+ ?SH-PROMPT:
+
+ !erlc -describe-feature loop_macro
+ ?Unknown feature: loop_macro
+ [invoke notok]
+
[cleanup]
[invoke no-dump]
!rm -fr $outdir
diff --git a/erts/test/lux/feature_runtime.lux b/erts/test/lux/feature_runtime.lux
index 723d650d5a..1048164a52 100644
--- a/erts/test/lux/feature_runtime.lux
+++ b/erts/test/lux/feature_runtime.lux
@@ -11,7 +11,7 @@
!erl
?$ERLPROMPT
- [invoke same-members "erl_features:enabled_features()" "[cond_expr,maps]"]
+ [invoke same-members "erl_features:enabled()" "[cond_expr,maps]"]
!erl_features:keywords().
??[]
@@ -33,14 +33,14 @@
[invoke same-members "erl_features:enable_feature(while_expr)" "[cond_expr,maps,ifn_expr,while_expr]"]
- [invoke same-members "erl_features:enabled_features()" "[cond_expr,maps,ifn_expr,while_expr]"]
+ [invoke same-members "erl_features:enabled()" "[cond_expr,maps,ifn_expr,while_expr]"]
!erl_features:keywords().
??['while','until','ifn']
[invoke same-members "erl_features:disable_feature(ifn_expr)" "[cond_expr,maps,while_expr]"]
- [invoke same-members "erl_features:enabled_features()" "[cond_expr,maps,while_expr]"]
+ [invoke same-members "erl_features:enabled()" "[cond_expr,maps,while_expr]"]
!erl_features:keywords().
??['while','until']
@@ -68,21 +68,21 @@
# If there is no Meta chunk, we should just get [] as answer,
# not a failure. We use a file compiled with an older release to be
# sure no meta chunk is present
- !erl_features:features_used(older).
+ !erl_features:used(older).
???[]
?$ERLPROMPT
- !erl_features:features_used("older.beam").
+ !erl_features:used("older.beam").
???[]
?$ERLPROMPT
# Test getting used features for unknown modules and files
- !erl_features:features_used(no_module).
+ !erl_features:used(no_module).
??not_found
?$ERLPROMPT
- !erl_features:features_used("none.beam").
+ !erl_features:used("none.beam").
??not_found
?$ERLPROMPT
diff --git a/erts/test/lux/features.luxinc b/erts/test/lux/features.luxinc
index 2998f67dd9..376aca4b97 100644
--- a/erts/test/lux/features.luxinc
+++ b/erts/test/lux/features.luxinc
@@ -68,12 +68,18 @@
[endmacro]
# Nifty way to compare that two lists have the same members
-# One drawback is that it os not easy to debug, i.e., see the actual
+# One drawback is that it is not easy to debug, i.e., see the actual
# members.
[macro same-members l1 l2]
- !maps:from_keys($l1,foo) == maps:from_keys($l2,foo).
+ !{L1, L2} = {$l1, $l2}.
+ ?$ERLPROMPT
+ !maps:from_keys(L1,foo) == maps:from_keys(L2,foo).
?true
?$ERLPROMPT
+ !f(L1).
+ ?$ERLPROMPT
+ !f(L2).
+ ?$ERLPROMPT
[endmacro]
[macro no-dump]
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 066b02f483..95a933c9fa 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -647,7 +647,7 @@ predef_macros(File, EnabledFeatures) ->
Machine = list_to_atom(erlang:system_info(machine)),
Anno = line1(),
OtpVersion = list_to_integer(erlang:system_info(otp_release)),
- AvailableFeatures = erl_features:features(),
+ AvailableFeatures = erl_features:all(),
Defs = [{'FILE', {none,[{string,Anno,File}]}},
{'FUNCTION_NAME', undefined},
{'FUNCTION_ARITY', undefined},
@@ -1038,10 +1038,9 @@ update_features(St0, Ind, Ftr, Loc) ->
case erl_features:keyword_fun(Ind, Ftr, Ftrs0, KeywordFun) of
{error, Reason} ->
{error, {Reason, Loc}};
- {ok, ResWordFun1, Ftrs1} ->
+ {ok, {Ftrs1, ResWordFun1}} ->
Macs0 = St0#epp.macs,
Macs1 = Macs0#{'FEATURE_ENABLED' => [ftr_macro(Ftrs1)]},
- %% ?liof("ok!\n", []),
%% FIXME WE need to keep any other scan_opts
%% present. Right now, there are no other, but
%% that might change.
diff --git a/lib/stdlib/src/erl_compile.erl b/lib/stdlib/src/erl_compile.erl
index 6cb8590f13..84923f21fb 100644
--- a/lib/stdlib/src/erl_compile.erl
+++ b/lib/stdlib/src/erl_compile.erl
@@ -329,13 +329,20 @@ show_info(#options{specific = Spec}) ->
case G([list_features, describe_feature]) of
{list_features, true} ->
- Features = erl_features:features(),
+ Features = erl_features:all(),
Msg = ["Available features:\n",
[io_lib:format(" ~-13s ~s\n", [Ftr, erl_features:short(Ftr)])
|| Ftr <- Features]],
{ok, Msg};
{describe_feature, Ftr} ->
- {ok, erl_features:long(Ftr)};
+ Description =
+ try
+ erl_features:long(Ftr)
+ catch
+ error:invalid_feature ->
+ io_lib:format("Unknown feature: ~p\n", [Ftr])
+ end,
+ {ok, Description};
_ ->
false
end.
diff --git a/lib/stdlib/src/erl_features.erl b/lib/stdlib/src/erl_features.erl
index 77ada029cb..edb1e71d52 100644
--- a/lib/stdlib/src/erl_features.erl
+++ b/lib/stdlib/src/erl_features.erl
@@ -19,15 +19,11 @@
%%
-module(erl_features).
-%% FIXME divide the exported functions in public and internal for the
-%% sake of documentation.
--export([features/0,
- feature_info/1,
- collect_features/1,
+-export([all/0,
+ info/1,
short/1,
long/1,
- enabled_features/0,
- is_valid_feature/1,
+ enabled/0,
load_allowed/1,
keywords/0,
keywords/1,
@@ -35,21 +31,21 @@
keyword_fun/4,
enable_feature/1,
disable_feature/1,
+ used/1,
format_error/1,
format_error/2]).
--export([features_used/1]).
-
-type type() :: 'extension' | 'backwards_incompatible_change'.
-type status() :: 'experimental'
| 'approved'
| 'permanent'
| 'rejected'.
-type release() :: non_neg_integer().
+-type feature() :: atom().
-type error() :: {?MODULE, {'invalid_features', [atom()]}}.
-define(VALID_FEATURE(Feature),
- (case is_valid_feature(Feature) of
+ (case is_valid(Feature) of
false ->
error(invalid_feature, [Feature],
[{error_info,
@@ -70,31 +66,32 @@ feature_specs() ->
keywords => ['maybe', 'else'],
type => extension}}.
-%% Currently known features
--spec features() -> [atom()].
-features() ->
+%% Return all currently known features.
+-spec all() -> [feature()].
+all() ->
Map = case persistent_term:get({?MODULE, feature_specs}, none) of
none -> init_specs();
M -> M
end,
maps:keys(Map).
-is_valid_feature(Ftr) ->
- lists:member(Ftr, features()).
+is_valid(Ftr) ->
+ lists:member(Ftr, all()).
--spec short(atom()) -> iolist().
+-spec short(feature()) -> iolist() | no_return().
short(Feature) ->
#{short := Short,
- status := Status} = Info = feature_info(Feature),
+ status := Status} = Info = info(Feature),
#{Status := Release} = Info,
io_lib:format("~-40s ~-12s (~p)", [Short, Status, Release]).
+-spec long(feature()) -> iolist() | no_return().
long(Feature) ->
#{short := Short,
description := Description,
status := Status,
keywords := Keywords,
- type := Type} = Info = feature_info(Feature),
+ type := Type} = Info = info(Feature),
StatusFmt = " ~-10s ~-12s (~p)\n",
History = [io_lib:format(StatusFmt, [T, S, R])
|| {T, S, R} <- history(Status, Info)],
@@ -148,7 +145,7 @@ adjust(Col, [{W, L}| WLs], Ws) ->
end.
--spec feature_info(atom()) -> FeatureInfoMap | no_return()
+-spec info(feature()) -> FeatureInfoMap | no_return()
when
Description :: string(),
FeatureInfoMap ::
@@ -162,19 +159,18 @@ adjust(Col, [{W, L}| WLs], Ws) ->
permanent => release(),
rejected => release()
}.
-feature_info(Feature) ->
+info(Feature) ->
?VALID_FEATURE(Feature),
Map = persistent_term:get({?MODULE, feature_specs}),
maps:get(Feature, Map).
-%% New keywords for a feature. The current set is just for
-%% tests and development.
--spec keywords(atom()) -> [atom()].
+%% New keywords introduced by a feature.
+-spec keywords(feature()) -> [atom()] | no_return().
keywords(Ftr) ->
?VALID_FEATURE(Ftr),
- #{keywords := Keywords} = feature_info(Ftr),
+ #{keywords := Keywords} = info(Ftr),
Keywords.
%% Internal - Ftr is valid
@@ -183,9 +179,9 @@ keywords(Ftr, Map) ->
%% Utilities
%% Returns list of enabled features and a new keywords function
-%% -spec keyword_fun_add_feature(atom(), fun((atom()) -> boolean())) ->
-%% {'ok', fun((atom()) -> boolean())}
-%% | {'error', error()}.
+-spec keyword_fun([term()], fun((atom()) -> boolean())) ->
+ {'ok', {[feature()], fun((atom()) -> boolean())}}
+ | {'error', error()}.
keyword_fun(Opts, KeywordFun) ->
%% Get items enabling or disabling features, preserving order.
IsFtr = fun({feature, _, enable}) -> true;
@@ -197,9 +193,9 @@ keyword_fun(Opts, KeywordFun) ->
%% FIXME check that all features are known at this stage so we
%% don't miss out on reporting any unknown features.
- case keyword_fun_add_features(AddFeatures, KeywordFun) of
+ case add_features_fun(AddFeatures, KeywordFun) of
{ok, Fun} ->
- case keyword_fun_remove_features(DelFeatures, Fun) of
+ case remove_features_fun(DelFeatures, Fun) of
{ok, FunX} ->
{ok, {AddFeatures -- DelFeatures, FunX}};
{error, _} = Error ->
@@ -211,36 +207,33 @@ keyword_fun(Opts, KeywordFun) ->
Error
end.
-%% -spec keyword_fun_add_feature(atom(), fun((atom()) -> boolean())) ->
-%% {'ok', fun((atom()) -> boolean())}
-%% | {'error', error()}.
+-spec keyword_fun('enable' | 'disable', feature(), [feature()],
+ fun((atom()) -> boolean())) ->
+ {'ok', {[feature()], fun((atom()) -> boolean())}}
+ | {'error', error()}.
keyword_fun(Ind, Feature, Ftrs, KeywordFun) ->
- case is_valid_feature(Feature) of
+ case is_valid(Feature) of
true ->
case Ind of
enable ->
- {ok,
- add_feature(Feature, KeywordFun),
- [Feature | Ftrs]};
+ {ok, {[Feature | Ftrs],
+ add_feature_fun(Feature, KeywordFun)}};
disable ->
- {ok,
- remove_feature(Feature, KeywordFun),
- Ftrs -- [Feature]}
+ {ok, {Ftrs -- [Feature],
+ remove_feature_fun(Feature, KeywordFun)}}
end;
false ->
{error, {?MODULE, {invalid_features, [Feature]}}}
end.
-%% FIXME Rename this to reflect that it returns a function!
-add_feature(Feature, F) ->
+add_feature_fun(Feature, F) ->
Words = keywords(Feature),
fun(Word) ->
lists:member(Word, Words)
orelse F(Word)
end.
-%% FIXME Rename this to reflect that it returns a function!
-remove_feature(Feature, F) ->
+remove_feature_fun(Feature, F) ->
Words = keywords(Feature),
fun(Word) ->
case lists:member(Word, Words) of
@@ -249,37 +242,46 @@ remove_feature(Feature, F) ->
end
end.
--spec keyword_fun_add_features([atom()], fun((atom()) -> boolean())) ->
+-spec add_features_fun([feature()], fun((atom()) -> boolean())) ->
{'ok', fun((atom()) -> boolean())}
| {'error', error()}.
-keyword_fun_add_features(Features, F) ->
- case lists:all(fun is_valid_feature/1, Features) of
+add_features_fun(Features, F) ->
+ case lists:all(fun is_valid/1, Features) of
true ->
- {ok, lists:foldl(fun add_feature/2, F, Features)};
+ {ok, lists:foldl(fun add_feature_fun/2, F, Features)};
false ->
- IsInvalid = fun(Ftr) -> not is_valid_feature(Ftr) end,
+ IsInvalid = fun(Ftr) -> not is_valid(Ftr) end,
Invalid = lists:filter(IsInvalid, Features),
{error, {?MODULE, {invalid_features, Invalid}}}
end.
--spec keyword_fun_remove_features([atom()], fun((atom()) -> boolean())) ->
+-spec remove_features_fun([feature()], fun((atom()) -> boolean())) ->
{'ok', fun((atom()) -> boolean())}
| {'error', error()}.
-keyword_fun_remove_features(Features, F) ->
- case lists:all(fun is_valid_feature/1, Features) of
+remove_features_fun(Features, F) ->
+ case lists:all(fun is_valid/1, Features) of
true ->
- {ok, lists:foldl(fun remove_feature/2, F, Features)};
+ {ok, lists:foldl(fun remove_feature_fun/2, F, Features)};
false ->
- IsInvalid = fun(Ftr) -> not is_valid_feature(Ftr) end,
+ IsInvalid = fun(Ftr) -> not is_valid(Ftr) end,
Invalid = lists:filter(IsInvalid, Features),
{error, {?MODULE, {invalid_features, Invalid}}}
end.
+-spec format_error(Reason, StackTrace) -> ErrorDescription
+ when Reason :: term(),
+ StackTrace :: erlang:stacktrace(),
+ ArgumentPosition :: pos_integer(),
+ ErrorDescription :: #{ArgumentPosition => unicode:chardata(),
+ general => unicode:chardata(),
+ reason => unicode:chardata()}.
format_error(Reason, [{_M, _F, _Args, Info}| _St]) ->
ErrorInfo = proplists:get_value(error_info, Info, #{}),
ErrorMap = maps:get(cause, ErrorInfo),
ErrorMap#{reason => io_lib:format("~p: ~p", [?MODULE, Reason])}.
+-spec format_error(Reason) -> iolist()
+ when Reason :: term().
format_error({invalid_features, Features}) ->
Fmt = fun F([Ftr]) -> io_lib:fwrite("'~p'", [Ftr]);
F([Ftr1, Ftr2]) ->
@@ -326,7 +328,7 @@ init_features() ->
F = fun({Tag, String}) ->
try
Atom = list_to_atom(String),
- case is_valid_feature(Atom) of
+ case is_valid(Atom) of
true -> {true, {feature, Atom, Cnv(Tag)}};
false when Atom == all ->
{true, {feature, Atom, Cnv(Tag)}};
@@ -377,7 +379,7 @@ ensure_init() ->
enable_feature(Feature) ->
?VALID_FEATURE(Feature),
- Features = enabled_features(),
+ Features = enabled(),
case lists:member(Feature, Features) of
true ->
%% already there, maybe raise an error
@@ -394,7 +396,7 @@ enable_feature(Feature) ->
disable_feature(Feature) ->
?VALID_FEATURE(Feature),
- Features = enabled_features(),
+ Features = enabled(),
case lists:member(Feature, Features) of
true ->
NewFeatures = Features -- [Feature],
@@ -408,13 +410,17 @@ disable_feature(Feature) ->
Features
end.
-enabled_features() ->
+%% Return list of currently enabled features
+-spec enabled() -> [feature()].
+enabled() ->
ensure_init(),
persistent_term:get({?MODULE, enabled_features}).
enabled_features(Ftrs) ->
persistent_term:put({?MODULE, enabled_features}, Ftrs).
+%% Return list of keywords activated by enabled features
+-spec keywords() -> [atom()].
keywords() ->
ensure_init(),
persistent_term:get({?MODULE, keywords}).
@@ -434,7 +440,7 @@ load_allowed(Binary) ->
undefined ->
true;
Used ->
- Enabled = enabled_features(),
+ Enabled = enabled(),
lists:all(fun(UFtr) ->
lists:member(UFtr, Enabled)
end,
@@ -444,14 +450,15 @@ load_allowed(Binary) ->
%% Return features used by module or beam file
-features_used(Module) when is_atom(Module) ->
+-spec used(module() | file:filename()) -> [feature()].
+used(Module) when is_atom(Module) ->
case code:get_object_code(Module) of
error ->
not_found;
{_Mod, Bin, _Fname} ->
features_in(Bin)
end;
-features_used(FName) when is_list(FName) ->
+used(FName) when is_list(FName) ->
features_in(FName).
features_in(NameOrBin) ->
@@ -465,33 +472,33 @@ features_in(NameOrBin) ->
not_found
end.
-approved_features() ->
- [Ftr || Ftr <- features(),
- maps:get(status, feature_info(Ftr)) == approved].
+approved() ->
+ [Ftr || Ftr <- all(),
+ maps:get(status, info(Ftr)) == approved].
-permanent_features() ->
- [Ftr || Ftr <- features(),
- maps:get(status, feature_info(Ftr)) == permanent].
+permanent() ->
+ [Ftr || Ftr <- all(),
+ maps:get(status, info(Ftr)) == permanent].
%% Interpret feature ops (enable or disable) to build the full set of
%% features. The meta feature 'all' is expanded to all known
%% features.
collect_features(FOps) ->
%% Features enabled by default
- Enabled = approved_features() ++ permanent_features(),
+ Enabled = approved() ++ permanent(),
collect_features(FOps, Enabled, []).
collect_features([], Add, Del) ->
{Add, Del};
collect_features([{feature, all, enable}| FOps], Add, _Del) ->
- All = features(),
+ All = all(),
Add1 = lists:foldl(fun add_ftr/2, Add, All),
collect_features(FOps, Add1, []);
collect_features([{feature, Feature, enable}| FOps], Add, Del) ->
collect_features(FOps, add_ftr(Feature, Add), Del -- [Feature]);
collect_features([{feature, all, disable}| FOps], _Add, Del) ->
%% Start over
- All = features(),
+ All = all(),
collect_features(FOps, [], Del -- All);
collect_features([{feature, Feature, disable}| FOps], Add, Del) ->
collect_features(FOps, Add -- [Feature],
@@ -532,7 +539,7 @@ test_features() ->
keywords => ['ifnot'],
type => extension},
unless_expr =>
- #{short => "`unless <cond> -> <bodby> end",
+ #{short => "`unless <cond> -> <body> end",
description =>
"Introduction of new expression `unless <cond> -> <body> end."
" Truly experimental.",
@@ -542,9 +549,8 @@ test_features() ->
type => extension},
maps =>
#{short => "Add maps as new data type",
- description => "Add new low data type maps with syntactic "
- "support in Erlang as well native support in the beam. "
- "Insert, lookup and delete are asymptotically constant.",
+ description => "Add new data type for maps with syntactic "
+ "support in Erlang as well native support in the beam.",
status => permanent,
experimental => 17,
approved => 18,
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 3ae2bc41c4..cc76090c59 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -4174,7 +4174,7 @@ test_overriden_by_local(Anno, OldTest, Arity, St) ->
keyword_warning(Anno, Atom, St) ->
case is_warn_enabled(keyword_warning, St) of
true ->
- Ftrs = erl_features:features(),
+ Ftrs = erl_features:all(),
Reserved =
fun(Ftr) ->
lists:member(Atom, erl_features:keywords(Ftr))
--
2.35.3