Skip to content

Commit 1018f3c

Browse files
committed
Compute alignment
1 parent 42e3dd4 commit 1018f3c

6 files changed

Lines changed: 67 additions & 22 deletions

File tree

lib/elixir/lib/module/types/apply.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ defmodule Module.Types.Apply do
174174
{:erlang, :bsl, [{[integer(), integer()], integer()}]},
175175
{:erlang, :bsr, [{[integer(), integer()], integer()}]},
176176
{:erlang, :bxor, [{[integer(), integer()], integer()}]},
177-
{:erlang, :byte_size, [{[binary()], integer()}]},
177+
{:erlang, :byte_size, [{[bitstring()], integer()}]},
178178
{:erlang, :ceil, [{[union(integer(), float())], integer()}]},
179179
{:erlang, :div, [{[integer(), integer()], integer()}]},
180180
{:erlang, :error, [{[term()], none()}]},

lib/elixir/lib/module/types/expr.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@ defmodule Module.Types.Expr do
122122
end
123123

124124
# <<...>>>
125-
def of_expr({:<<>>, _meta, args}, _expected, _expr, stack, context) do
126-
Of.bitstring(args, :expr, stack, context)
125+
def of_expr({:<<>>, meta, args}, _expected, _expr, stack, context) do
126+
Of.bitstring(meta, args, :expr, stack, context)
127127
end
128128

129129
def of_expr({:__CALLER__, _meta, var_context}, _expected, _expr, _stack, context)

lib/elixir/lib/module/types/of.ex

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -476,27 +476,36 @@ defmodule Module.Types.Of do
476476
In the stack, we add nodes such as <<expr>>, <<..., expr>>, etc,
477477
based on the position of the expression within the binary.
478478
"""
479-
# TODO: Return binary, bitstring or bitstring_no_binary
480-
def bitstring([], _kind, _stack, context) do
481-
{binary(), context}
479+
def bitstring(meta, parts, kind, stack, context) do
480+
context = bitstring(parts, kind, stack, context)
481+
482+
case Keyword.get(meta, :alignment, :unknown) do
483+
:unknown -> {bitstring(), context}
484+
0 -> {binary(), context}
485+
_ -> {bitstring_no_binary(), context}
486+
end
487+
end
488+
489+
defp bitstring([], _kind, _stack, context) do
490+
context
482491
end
483492

484-
def bitstring([head], kind, stack, context) do
485-
{binary(), bitstring_segment(head, kind, [head], stack, context)}
493+
defp bitstring([head], kind, stack, context) do
494+
bitstring_segment(head, kind, [head], stack, context)
486495
end
487496

488-
def bitstring([head | tail], kind, stack, context) do
497+
defp bitstring([head | tail], kind, stack, context) do
489498
context = bitstring_segment(head, kind, [head, @suffix], stack, context)
490-
{binary(), bitstring_many(tail, kind, stack, context)}
499+
bitstring_tail(tail, kind, stack, context)
491500
end
492501

493-
defp bitstring_many([last], kind, stack, context) do
502+
defp bitstring_tail([last], kind, stack, context) do
494503
bitstring_segment(last, kind, [@prefix, last], stack, context)
495504
end
496505

497-
defp bitstring_many([head | tail], kind, stack, context) do
506+
defp bitstring_tail([head | tail], kind, stack, context) do
498507
context = bitstring_segment(head, kind, [@prefix, head, @suffix], stack, context)
499-
bitstring_many(tail, kind, stack, context)
508+
bitstring_tail(tail, kind, stack, context)
500509
end
501510

502511
# If the segment is a literal, the compiler has already checked its validity,

lib/elixir/lib/module/types/pattern.ex

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,8 @@ defmodule Module.Types.Pattern do
401401
end
402402
end
403403

404-
def of_match_var({:<<>>, _meta, args}, _expected, _expr, stack, context) do
405-
Of.bitstring(args, :match, stack, context)
404+
def of_match_var({:<<>>, meta, args}, _expected, _expr, stack, context) do
405+
Of.bitstring(meta, args, :match, stack, context)
406406
end
407407

408408
def of_match_var({:^, _meta, [{_, meta, _}]}, expected, expr, stack, context) do
@@ -592,8 +592,8 @@ defmodule Module.Types.Pattern do
592592
end
593593

594594
# <<...>>>
595-
defp of_pattern({:<<>>, _meta, args}, _path, stack, context) do
596-
Of.bitstring(args, :match, stack, context)
595+
defp of_pattern({:<<>>, meta, args}, _path, stack, context) do
596+
Of.bitstring(meta, args, :match, stack, context)
597597
end
598598

599599
# left ++ right
@@ -851,8 +851,8 @@ defmodule Module.Types.Pattern do
851851
end
852852

853853
# <<>>
854-
def of_guard({:<<>>, _meta, args}, _expected, _expr, stack, context) do
855-
Of.bitstring(args, :guard, stack, context)
854+
def of_guard({:<<>>, meta, args}, _expected, _expr, stack, context) do
855+
Of.bitstring(meta, args, :guard, stack, context)
856856
end
857857

858858
# ^var

lib/elixir/test/elixir/module/types/expr_test.exs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ defmodule Module.Types.ExprTest do
3131
assert typecheck!([x = 1], generated(x)) == dynamic()
3232
end
3333

34+
describe "bitstrings" do
35+
test "alignment" do
36+
assert typecheck!(<<round(:rand.uniform())>>) == binary()
37+
assert typecheck!(<<round(:rand.uniform())::1>>) == difference(bitstring(), binary())
38+
assert typecheck!(<<round(:rand.uniform())::4, round(:rand.uniform())::4>>) == binary()
39+
assert typecheck!([size], <<round(:rand.uniform())::size(size)>>) == bitstring()
40+
end
41+
end
42+
3443
describe "lists" do
3544
test "creating lists" do
3645
assert typecheck!([1, 2]) == non_empty_list(integer())
@@ -678,7 +687,7 @@ defmodule Module.Types.ExprTest do
678687
end
679688

680689
test "size ok" do
681-
assert typecheck!([<<x, y>>, z], <<z::size(x - y)>>) == binary()
690+
assert typecheck!([<<x, y>>, z], <<z::size(x - y)>>) == bitstring()
682691
end
683692

684693
test "size error" do

lib/elixir/test/elixir/module/types/pattern_test.exs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,14 @@ defmodule Module.Types.PatternTest do
328328
end
329329
end
330330

331-
describe "binaries" do
331+
describe "bitstrings" do
332+
test "alignment" do
333+
assert typecheck!([<<_>> = x], x) == dynamic(binary())
334+
assert typecheck!([<<_::1>> = x], x) == dynamic(difference(bitstring(), binary()))
335+
assert typecheck!([<<_::4, _::4>> = x], x) == dynamic(binary())
336+
assert typecheck!([<<size, _::size(size)>> = x], x) == dynamic(bitstring())
337+
end
338+
332339
test "ok" do
333340
assert typecheck!([<<x>>], x) == integer()
334341
assert typecheck!([<<x::float>>], x) == float()
@@ -337,7 +344,27 @@ defmodule Module.Types.PatternTest do
337344
end
338345

339346
test "nested" do
340-
assert typecheck!([<<0, <<x::bitstring>>::binary>>], x) == binary()
347+
assert typecheck!([<<0, <<x::binary>>::binary>>], x) == binary()
348+
349+
assert typeerror!([<<0, <<x::bitstring>>::binary>>], x) == ~l"""
350+
incompatible types in binary matching:
351+
352+
<<..., <<x::bitstring>>::binary>>
353+
354+
got type:
355+
356+
bitstring()
357+
358+
but expected type:
359+
360+
binary()
361+
362+
where "x" was given the type:
363+
364+
# type: bitstring()
365+
# from: types_test.ex:LINE
366+
<<x::bitstring>>
367+
"""
341368
end
342369

343370
test "error" do

0 commit comments

Comments
 (0)