diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl index 992bd3e0476..2c157686053 100644 --- a/lib/stdlib/src/erl_eval.erl +++ b/lib/stdlib/src/erl_eval.erl @@ -1253,30 +1253,37 @@ eval_bc1(E, [], Bs, Lf, Ef, FUVs, Acc) -> {value,V,_} = expr(E, Bs, Lf, Ef, none, FUVs), <>. -%% eval_mc(Expr, [Qualifier], Bindings, LocalFunctionHandler, +%% eval_mc(ExprOrExprs, [Qualifier], Bindings, LocalFunctionHandler, %% ExternalFuncHandler, RetBindings) -> %% {value,Value,Bindings} | Value -eval_mc(E, Qs, Bs, Lf, Ef, RBs, FUVs) -> - L = eval_mc1(E, Qs, Bs, Lf, Ef, FUVs, []), +eval_mc(Es, Qs, Bs, Lf, Ef, RBs, FUVs) when is_list(Es) -> + L = eval_mc1(Es, Qs, Bs, Lf, Ef, FUVs, []), Map = maps:from_list(reverse(L)), - ret_expr(Map, Bs, RBs). + ret_expr(Map, Bs, RBs); +eval_mc(E, Qs, Bs, Lf, Ef, RBs, FUVs) -> + eval_mc([E], Qs, Bs, Lf, Ef, RBs, FUVs). -eval_mc1(E, [{zip, Anno, Gens}|Qs], Bs0, Lf, Ef, FUVs, Acc0) -> +eval_mc1(Es, [{zip, Anno, Gens}|Qs], Bs0, Lf, Ef, FUVs, Acc0) -> {VarList, Bs1} = convert_gen_values(Gens, [], Bs0, Lf, Ef, FUVs), - eval_zip(E, [{zip, Anno, VarList}|Qs], Bs1, Lf, Ef, FUVs, Acc0, fun eval_mc1/7); -eval_mc1(E, [Q|Qs], Bs0, Lf, Ef, FUVs, Acc0) -> + eval_zip(Es, [{zip, Anno, VarList}|Qs], Bs1, Lf, Ef, FUVs, Acc0, fun eval_mc1/7); +eval_mc1(Es, [Q|Qs], Bs0, Lf, Ef, FUVs, Acc0) -> case is_generator(Q) of true -> - CF = fun(Bs, Acc) -> eval_mc1(E, Qs, Bs, Lf, Ef, FUVs, Acc) end, + CF = fun(Bs, Acc) -> eval_mc1(Es, Qs, Bs, Lf, Ef, FUVs, Acc) end, eval_generator(Q, Bs0, Lf, Ef, FUVs, Acc0, CF); false -> - CF = fun(Bs) -> eval_mc1(E, Qs, Bs, Lf, Ef, FUVs, Acc0) end, + CF = fun(Bs) -> eval_mc1(Es, Qs, Bs, Lf, Ef, FUVs, Acc0) end, eval_filter(Q, Bs0, Lf, Ef, CF, FUVs, Acc0) end; -eval_mc1({map_field_assoc,Lfa,K0,V0}, [], Bs, Lf, Ef, FUVs, Acc) -> - {value,KV,_} = expr({tuple,Lfa,[K0,V0]}, Bs, Lf, Ef, none, FUVs), - [KV|Acc]. +eval_mc1(Es, [], Bs, Lf, Ef, FUVs, Acc) -> + eval_mc2(Es, Bs, Lf, Ef, FUVs, Acc). + +eval_mc2([{map_field_assoc,_,K0,V0}|Es], Bs, Lf, Ef, FUVs, Acc) -> + {[K,V],_} = expr_list([K0,V0], Bs, Lf, Ef, FUVs), + eval_mc2(Es, Bs, Lf, Ef, FUVs, [{K,V}|Acc]); +eval_mc2([], _Bs, _Lf, _Ef, _FUVs, Acc) -> + Acc. eval_zip(E, [{zip, Anno, VarList}|Qs], Bs0, Lf, Ef, FUVs, Acc0, Fun) -> Gens = case check_bad_generators(VarList, {Bs0, Lf, Ef}, []) of diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index 018682e0563..9b8248300e1 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -402,6 +402,8 @@ format_error_1(update_literal) -> ~"expression updates a literal"; format_error_1(illegal_zip_generator) -> ~"only generators are allowed in a zip generator."; +format_error_1(illegal_map_exact_in_comprehension) -> + ~"illegal map association, did you mean to use `=>`?"; %% --- patterns and guards --- format_error_1(illegal_map_assoc_in_pattern) -> ~"illegal pattern, did you mean to use `:=`?"; format_error_1(illegal_pattern) -> ~"illegal pattern"; @@ -4060,6 +4062,9 @@ comprehension_exprs(E, Vt, St) -> comprehension_expr({map_field_assoc,_,K,V}, Vt0, St0) -> expr_list([K,V], Vt0, St0); +comprehension_expr({map_field_exact,A,K,V}, Vt0, St0) -> + St = add_error(A, illegal_map_exact_in_comprehension, St0), + expr_list([K,V], Vt0, St); comprehension_expr(E, Vt, St) -> expr(E, Vt, St). diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl index 7005d2bad62..65473a7cc6f 100644 --- a/lib/stdlib/test/erl_eval_SUITE.erl +++ b/lib/stdlib/test/erl_eval_SUITE.erl @@ -33,6 +33,7 @@ zbc/1, zmc/1, multi_lc/1, + multi_mc/1, simple_cases/1, unary_plus/1, apply_atom/1, @@ -105,7 +106,7 @@ all() -> funs, custom_stacktrace, try_catch, eval_expr_5, zero_width, eep37, eep43, otp_15035, otp_16439, otp_14708, otp_16545, otp_16865, eep49, binary_and_map_aliases, eep58, strict_generators, binary_skip, - zlc, zbc, zmc, multi_lc]. + zlc, zbc, zmc, multi_lc, multi_mc]. groups() -> []. @@ -447,6 +448,16 @@ multi_lc(Config) when is_list(Config) -> "[1, 2 || _ <- [1, 2]].", [1, 2, 1, 2]). +multi_mc(Config) when is_list(Config) -> + check(fun() -> #{A => B || X <- [1, 5], {A, B} <- [{X, X+1}, {X+2, X+3}]} end, + "#{X => X+1, X+2 => X+3 || X <- [1, 5]}.", + #{1 => 2, 3 => 4, 5 => 6, 7 => 8}), + check(fun() -> #{A => B || X <- [1, 5], {A, B} <- [{X, X+1}, {X, X+3}]} end, + "#{X => X+1, X => X+3 || X <- [1, 5]}.", + #{1 => 4, 5 => 8}), + error_check("#{1 := 2 || _ <- []}.", illegal_map_exact_in_comprehension), + error_check("#{1 => 2, 3 := 4 || _ <- []}.", illegal_map_exact_in_comprehension). + %% Simple cases, just to cover some code. simple_cases(Config) when is_list(Config) -> check(fun() -> A = $C end, "A = $C.", $C),