diff --git a/bootstrap b/bootstrap index 3a05a1b6..994b8d6b 100755 --- a/bootstrap +++ b/bootstrap @@ -634,6 +634,7 @@ format_error(AbsSource, Extra, {Mod, Desc}) -> additional_defines() -> [{d, D} || {Re, D} <- [{"^[0-9]+", namespaced_types}, + {"^18", no_maps_update_with}, {"^R1[4|5]", deprecated_crypto}, {"^2", unicode_str}, {"^(R|1|20)", fun_stacktrace}, diff --git a/rebar.config b/rebar.config index e194284d..1becefce 100644 --- a/rebar.config +++ b/rebar.config @@ -30,6 +30,7 @@ {"rebar/priv/templates/*", "_build/default/lib/"}]}. {erl_opts, [{platform_define, "^(19|2)", rand_only}, + {platform_define, "^18", no_maps_update_with}, {platform_define, "^2", unicode_str}, {platform_define, "^(2[1-9])|(20\\\\.3)", filelib_find_source}, {platform_define, "^(R|1|20)", fun_stacktrace}, diff --git a/src/rebar_compiler.erl b/src/rebar_compiler.erl index c61bdeb4..cdecce86 100644 --- a/src/rebar_compiler.erl +++ b/src/rebar_compiler.erl @@ -17,11 +17,11 @@ -type extension() :: string(). -type out_mappings() :: [{extension(), file:filename()}]. --callback context(rebar_app_info:t()) -> #{src_dirs := [file:dirname()], - include_dirs := [file:dirname()], - src_ext := extension(), - out_mappings := out_mappings(), - dependencies_opts => term()}. +-callback context(rebar_app_info:t()) -> #{src_dirs => [file:dirname()], % mandatory + include_dirs => [file:dirname()], % mandatory + src_ext => extension(), % mandatory + out_mappings => out_mappings(), % mandatory + dependencies_opts => term()}. % optional -callback needed_files(digraph:graph(), [file:filename()], out_mappings(), rebar_app_info:t()) -> {{[file:filename()], term()}, % ErlFirstFiles (erl_opts global priority) diff --git a/src/rebar_compiler_epp.erl b/src/rebar_compiler_epp.erl index 8be954fa..121e6f31 100644 --- a/src/rebar_compiler_epp.erl +++ b/src/rebar_compiler_epp.erl @@ -15,12 +15,13 @@ Opts :: [Opt, ...], Opt :: {includes, [file:filename_all()]} | {macros, [file:filename_all()]}, - Attributes :: #{include := [file:filename_all()], - missing_include_file := [file:filename_all()], - missing_include_lib := [file:filename_all()], - behaviour := [atom()], - parse_transform := [atom()], - is_behaviour := boolean()}. + %% following are all required, OTP-18 don't like it though + Attributes :: #{include => [file:filename_all()], + missing_include_file => [file:filename_all()], + missing_include_lib => [file:filename_all()], + behaviour => [atom()], + parse_transform => [atom()], + is_behaviour => boolean()}. deps(File, Opts) -> {EppOpts, ExtraOpts} = split_opts(Opts), {ok, Forms} = epp:parse_file(File, EppOpts), @@ -90,13 +91,13 @@ handle_form({attribute, _Line, file, {Path, Ln}}, Map, Opts) -> %% thing. case filename:absname(Path) of Path -> - maps:update_with(include, fun(L) -> [Path|L] end, [Path], Map); + update_with(include, fun(L) -> [Path|L] end, [Path], Map); _ -> % argh! handle_form({error, {Ln, {epp, {include, file, Path}}}}, Map, Opts) end; %% Include files that EPP couldn't resolve handle_form({error, {_Line, epp, {include, file, Name}}}, Map, _Opts) -> - maps:update_with(missing_include_file, fun(L) -> [Name|L] end, [Name], Map); + update_with(missing_include_file, fun(L) -> [Name|L] end, [Name], Map); handle_form({error, {_Line, epp, {include, lib, Path}}}, Map, Opts) -> %% This file might still exist in the regular paths not in %% code:lib_dir, which depend on options we pass to this module. @@ -107,15 +108,15 @@ handle_form({error, {_Line, epp, {include, lib, Path}}}, Map, Opts) -> %% file because we'd need its own compiler opts and app opts %% to do it safely. Tracking that file is still better %% than nothing though. - maps:update_with(include, fun(L) -> [File|L] end, [File], Map); + update_with(include, fun(L) -> [File|L] end, [File], Map); {error, not_found} -> - maps:update_with(missing_include_lib, fun(L) -> [Path|L] end, [Path], Map) + update_with(missing_include_lib, fun(L) -> [Path|L] end, [Path], Map) end; %% Behaviour implementation declaration handle_form({attribute, _Line, behaviour, Name}, Map, _Opts) -> - maps:update_with(behaviour, fun(L) -> [Name|L] end, [Name], Map); + update_with(behaviour, fun(L) -> [Name|L] end, [Name], Map); handle_form({attribute, _Line, behavior, Name}, Map, _Opts) -> - maps:update_with(behaviour, fun(L) -> [Name|L] end, [Name], Map); + update_with(behaviour, fun(L) -> [Name|L] end, [Name], Map); %% Extract parse transforms handle_form({attribute, Line, compile, Attr}, Map, _Opts) when not is_list(Attr) -> handle_form({attribute, Line, compile, [Attr]}, Map, _Opts); @@ -124,7 +125,7 @@ handle_form({attribute, _Line, compile, Attrs}, Map, _Opts) -> {_, {M,_}} -> M; {_, M} -> M end || T <- proplists:lookup_all(parse_transform, Attrs)], - maps:update_with(parse_transform, fun(L) -> Mods++L end, Mods, Map); + update_with(parse_transform, fun(L) -> Mods++L end, Mods, Map); %% Current style behaviour specification declaration handle_form({attribute, _Line, callback, _}, Map, _Opts) -> Map#{is_behaviour => true}; @@ -162,4 +163,14 @@ find_include_lib([H|T], File) -> false -> find_include_lib(T, File) end. +-ifdef(no_maps_update_with). +update_with(Key, Fun, Default, Map) -> + case Map of + #{Key := Value} -> Map#{Key := Fun(Value)}; + _ -> Map#{Key => Default} + end. +-else. +update_with(Key, Fun, Default, Map) -> + maps:update_with(Key, Fun, Default, Map). +-endif.