Skip to content

Commit 3eeded0

Browse files
author
José Valim
committed
Ensure we support counters in bitstring size vars
Signed-off-by: José Valim <[email protected]>
1 parent f4c827b commit 3eeded0

File tree

5 files changed

+67
-58
lines changed

5 files changed

+67
-58
lines changed

lib/elixir/src/elixir_bitstring.erl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,17 @@ expand_spec_arg(Expr, E) -> elixir_expand:expand(Expr, E).
253253

254254
validate_spec_arg(Meta, size, Value, E, OriginalE) ->
255255
case Value of
256-
{Var, _, Context} when is_atom(Var) and is_atom(Context) ->
257-
case is_valid_spec_arg_var({Var, Context}, E, OriginalE) of
256+
{Var, VarMeta, Context} when is_atom(Var) and is_atom(Context) ->
257+
Tuple = {Var, elixir_utils:var_context(VarMeta, Context)},
258+
259+
case is_valid_spec_arg_var(Tuple, E, OriginalE) of
258260
true -> ok;
259261
false -> form_error(Meta, ?key(E, file), ?MODULE, {undefined_var_in_spec, Value})
260262
end;
263+
261264
_ when is_integer(Value) ->
262265
ok;
266+
263267
_ ->
264268
form_error(Meta, ?key(E, file), ?MODULE, {bad_size_argument, Value})
265269
end;

lib/elixir/src/elixir_erl_pass.erl

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,15 @@ translate({with, Meta, [_ | _] = Args}, S) ->
178178
%% Variables
179179

180180
translate({'^', Meta, [{Name, VarMeta, Kind}]}, #elixir_erl{context=match} = S) when is_atom(Name), is_atom(Kind) ->
181-
Tuple = {Name, var_context(VarMeta, Kind)},
181+
Tuple = {Name, elixir_utils:var_context(VarMeta, Kind)},
182182
{ok, {_Counter, Value}} = maps:find(Tuple, S#elixir_erl.backup_vars),
183183

184184
PAnn = ?ann(?generated(Meta)),
185185
PVar = {var, PAnn, Value},
186186

187187
case S#elixir_erl.extra of
188188
pin_guard ->
189-
{TVar, TS} = elixir_erl_var:translate(VarMeta, Name, var_context(VarMeta, Kind), S),
189+
{TVar, TS} = elixir_erl_var:translate(VarMeta, Name, elixir_utils:var_context(VarMeta, Kind), S),
190190
Guard = {op, PAnn, '=:=', PVar, TVar},
191191
{TVar, TS#elixir_erl{extra_guards=[Guard | TS#elixir_erl.extra_guards]}};
192192
_ ->
@@ -197,7 +197,7 @@ translate({'_', Meta, Kind}, #elixir_erl{context=match} = S) when is_atom(Kind)
197197
{{var, ?ann(Meta), '_'}, S};
198198

199199
translate({Name, Meta, Kind}, S) when is_atom(Name), is_atom(Kind) ->
200-
elixir_erl_var:translate(Meta, Name, var_context(Meta, Kind), S);
200+
elixir_erl_var:translate(Meta, Name, elixir_utils:var_context(Meta, Kind), S);
201201

202202
%% Local calls
203203

@@ -283,12 +283,6 @@ build_list([H | T], Acc) ->
283283
build_list([], Acc) ->
284284
Acc.
285285

286-
var_context(Meta, Kind) ->
287-
case lists:keyfind(counter, 1, Meta) of
288-
{counter, Counter} -> Counter;
289-
false -> Kind
290-
end.
291-
292286
%% Pack a list of expressions from a block.
293287
unblock({'block', _, Exprs}) -> Exprs;
294288
unblock(Expr) -> [Expr].

lib/elixir/src/elixir_expand.erl

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ expand({'_', Meta, Kind}, E) when is_atom(Kind) ->
353353

354354
expand({Name, Meta, Kind} = Var, #{context := match} = E) when is_atom(Name), is_atom(Kind) ->
355355
#{unused_vars := Unused, current_vars := Current, prematch_vars := Prematch} = E,
356-
Pair = {Name, var_context(Meta, Kind)},
356+
Pair = {Name, elixir_utils:var_context(Meta, Kind)},
357357
PrematchVersion = var_version(Prematch, Pair),
358358

359359
EE =
@@ -381,7 +381,7 @@ expand({Name, Meta, Kind} = Var, #{context := match} = E) when is_atom(Name), is
381381
{Var, EE};
382382
expand({Name, Meta, Kind} = Var, E) when is_atom(Name), is_atom(Kind) ->
383383
#{unused_vars := Unused, current_vars := Current} = E,
384-
Pair = {Name, var_context(Meta, Kind)},
384+
Pair = {Name, elixir_utils:var_context(Meta, Kind)},
385385

386386
case Current of
387387
#{Pair := {Version, _}} ->
@@ -618,12 +618,6 @@ var_version(Map, Pair) ->
618618
_ -> -1
619619
end.
620620

621-
var_context(Meta, Kind) ->
622-
case lists:keyfind(counter, 1, Meta) of
623-
{counter, Counter} -> Counter;
624-
false -> Kind
625-
end.
626-
627621
maybe_warn_underscored_var_repeat(Meta, Name, Kind, E) ->
628622
case should_warn(Meta) andalso atom_to_list(Name) of
629623
"_" ++ _ ->

lib/elixir/src/elixir_utils.erl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
%% Convenience functions used throughout elixir source code
22
%% for ast manipulation and querying.
33
-module(elixir_utils).
4-
-export([get_line/1, split_last/1, noop/0,
4+
-export([get_line/1, split_last/1, noop/0, var_context/2,
55
characters_to_list/1, characters_to_binary/1, relative_to_cwd/1,
66
macro_name/1, returns_boolean/1, caller/4, meta_keep/1,
77
read_file_type/1, read_file_type/2, read_link_type/1, read_posix_mtime_and_size/1,
@@ -37,6 +37,12 @@ erlang_comparison_op_to_elixir('=:=') -> '===';
3737
erlang_comparison_op_to_elixir('=/=') -> '!==';
3838
erlang_comparison_op_to_elixir(Other) -> Other.
3939

40+
var_context(Meta, Kind) ->
41+
case lists:keyfind(counter, 1, Meta) of
42+
{counter, Counter} -> Counter;
43+
false -> Kind
44+
end.
45+
4046
% Extract guards
4147

4248
extract_guards({'when', _, [Left, Right]}) -> {Left, extract_or_guards(Right)};

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

Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2160,6 +2160,17 @@ defmodule Kernel.ExpansionTest do
21602160
assert expand(before_expansion) |> clean_meta([:alignment]) == after_expansion
21612161
end
21622162

2163+
defmacro offset(size, binary) do
2164+
quote do
2165+
offset = unquote(size)
2166+
<<_::size(offset)>> = unquote(binary)
2167+
end
2168+
end
2169+
2170+
test "supports size from counters" do
2171+
assert offset(8, <<0>>)
2172+
end
2173+
21632174
test "merges bitstrings" do
21642175
import Kernel, except: [-: 2]
21652176

@@ -2233,6 +2244,44 @@ defmodule Kernel.ExpansionTest do
22332244
assert_raise CompileError, message, fn ->
22342245
expand(quote(do: <<"foo"::size(:oops)>>))
22352246
end
2247+
2248+
assert_raise CompileError, ~r/undefined variable "foo"/, fn ->
2249+
code =
2250+
quote do
2251+
fn <<_::size(foo)>> -> :ok end
2252+
end
2253+
2254+
expand(code)
2255+
end
2256+
2257+
assert_raise CompileError, ~r/undefined variable "foo"/, fn ->
2258+
code =
2259+
quote do
2260+
fn <<_::size(foo), foo::size(8)>> -> :ok end
2261+
end
2262+
2263+
expand(code)
2264+
end
2265+
2266+
assert_raise CompileError, ~r/undefined variable "foo" in bitstring segment/, fn ->
2267+
code =
2268+
quote do
2269+
fn foo, <<_::size(foo)>> -> :ok end
2270+
end
2271+
2272+
expand(code)
2273+
end
2274+
2275+
message = ~r"size in bitstring expects an integer or a variable as argument, got: foo()"
2276+
2277+
assert_raise CompileError, message, fn ->
2278+
code =
2279+
quote do
2280+
fn <<_::size(foo())>> -> :ok end
2281+
end
2282+
2283+
expand(code)
2284+
end
22362285
end
22372286

22382287
test "raises for invalid unit" do
@@ -2384,44 +2433,6 @@ defmodule Kernel.ExpansionTest do
23842433

23852434
expand(code)
23862435
end
2387-
2388-
assert_raise CompileError, ~r/undefined variable "foo"/, fn ->
2389-
code =
2390-
quote do
2391-
fn <<_::size(foo)>> -> :ok end
2392-
end
2393-
2394-
expand(code)
2395-
end
2396-
2397-
assert_raise CompileError, ~r/undefined variable "foo"/, fn ->
2398-
code =
2399-
quote do
2400-
fn <<_::size(foo), foo::size(8)>> -> :ok end
2401-
end
2402-
2403-
expand(code)
2404-
end
2405-
2406-
assert_raise CompileError, ~r/undefined variable "foo" in bitstring segment/, fn ->
2407-
code =
2408-
quote do
2409-
fn foo, <<_::size(foo)>> -> :ok end
2410-
end
2411-
2412-
expand(code)
2413-
end
2414-
2415-
message = ~r"size in bitstring expects an integer or a variable as argument, got: foo()"
2416-
2417-
assert_raise CompileError, message, fn ->
2418-
code =
2419-
quote do
2420-
fn <<_::size(foo())>> -> :ok end
2421-
end
2422-
2423-
expand(code)
2424-
end
24252436
end
24262437

24272438
## Helpers

0 commit comments

Comments
 (0)