Skip to content

Commit b3e3e8c

Browse files
committed
Do not consider variables from pattern in bitstring modifier (#14738)
1 parent 61603a8 commit b3e3e8c

File tree

3 files changed

+32
-3
lines changed

3 files changed

+32
-3
lines changed

lib/elixir/src/elixir_bitstring.erl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ expand(Meta, Args, S, E, RequireSize) ->
3030
expand(_BitstrMeta, _Fun, [], Acc, S, E, Alignment, _RequireSize) ->
3131
{lists:reverse(Acc), Alignment, S, E};
3232
expand(BitstrMeta, Fun, [{'::', Meta, [Left, Right]} | T], Acc, S, E, Alignment, RequireSize) ->
33-
{ELeft, {SL, OriginalS}, EL} = expand_expr(Left, Fun, S, E),
33+
% We don't want to consider variables added in the Left pattern inside the Right specs
34+
{#elixir_ex{vars=BeforeVars}, _} = S,
35+
36+
{ELeft, {#elixir_ex{vars=AfterVars} = SL, OriginalS}, EL} = expand_expr(Left, Fun, S, E),
3437
validate_expr(ELeft, Meta, E),
3538

3639
MatchOrRequireSize = RequireSize or is_match_size(T, EL),
@@ -40,10 +43,11 @@ expand(BitstrMeta, Fun, [{'::', Meta, [Left, Right]} | T], Acc, S, E, Alignment,
4043
{'^', _, [{_, _, _}]} -> {infer, ELeft};
4144
_ -> required
4245
end,
43-
{ERight, EAlignment, SS, ES} = expand_specs(EType, Meta, Right, SL, OriginalS, EL, ExpectSize),
46+
47+
{ERight, EAlignment, SS, ES} = expand_specs(EType, Meta, Right, SL#elixir_ex{vars=BeforeVars}, OriginalS, EL, ExpectSize),
4448

4549
EAcc = concat_or_prepend_bitstring(Meta, ELeft, ERight, Acc, ES, MatchOrRequireSize),
46-
expand(BitstrMeta, Fun, T, EAcc, {SS, OriginalS}, ES, alignment(Alignment, EAlignment), RequireSize);
50+
expand(BitstrMeta, Fun, T, EAcc, {SS#elixir_ex{vars=AfterVars}, OriginalS}, ES, alignment(Alignment, EAlignment), RequireSize);
4751
expand(BitstrMeta, Fun, [H | T], Acc, S, E, Alignment, RequireSize) ->
4852
Meta = extract_meta(H, BitstrMeta),
4953
{ELeft, {SS, OriginalS}, ES} = expand_expr(H, Fun, S, E),

lib/elixir/test/elixir/kernel/expansion_test.exs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2836,6 +2836,17 @@ defmodule Kernel.ExpansionTest do
28362836
end)
28372837
end
28382838

2839+
test "raises for variable used both in pattern and size" do
2840+
assert_compile_error(~r/undefined variable "foo"/, fn ->
2841+
code =
2842+
quote do
2843+
fn <<foo::size(foo)>> -> :ok end
2844+
end
2845+
2846+
expand(code, [])
2847+
end)
2848+
end
2849+
28392850
test "raises for invalid unit" do
28402851
message = ~r"unit in bitstring expects an integer as argument, got: :oops"
28412852

lib/elixir/test/elixir/kernel/warning_test.exs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,6 +2237,20 @@ defmodule Kernel.WarningTest do
22372237
purge(Sample)
22382238
end
22392239

2240+
test "deprecate non-quoted variables in bitstring size modifiers" do
2241+
assert_warn_eval(
2242+
[
2243+
"the variable \"a\" is accessed inside size(...) of a bitstring but it was defined outside of the match",
2244+
"You must precede it with the pin operator"
2245+
],
2246+
"""
2247+
a = "foo"
2248+
<<a::binary-size(byte_size(a) - 1)>> <> _ = a
2249+
"fo" = a
2250+
"""
2251+
)
2252+
end
2253+
22402254
defp assert_compile_error(messages, string) do
22412255
captured =
22422256
capture_err(fn ->

0 commit comments

Comments
 (0)