Spec for t:token/0 was missing on element in the tuple
this created a series of Dialyzer errors when running `make dialyze`
/elixir/lib/eex/lib/eex/compiler.ex:44: The pattern <[{'expr', _line@1, _mark@1, _chars@1, _} | _rest@1], _buffer@1, _scope@1, _state@1> can never match the type <[{'text',binary() | maybe_improper_list(any(),binary() | [])} | {'end_expr',non_neg_integer(),[any()],binary() | maybe_improper_list(any(),binary() | [])} | {'expr',non_neg_integer(),[any()],binary() | maybe_improper_list(any(),binary() | [])} | {'middle_expr',non_neg_integer(),[any()],binary() | maybe_improper_list(any(),binary() | [])} | {'start_expr',non_neg_integer(),[any()],binary() | maybe_improper_list(any(),binary() | [])}],_,[],#{'engine':=_, 'file':=_, 'line':=non_neg_integer(), 'quoted':=[], 'start_line':='nil'}>
Consider the following template:
one
<%= arg1 %>
two
<% var2 = String.duplicate(arg2, 1) %>
three
<%= var2 %>
four
<% var3 = String.duplicate(arg3, 1) %>
five
<%= var3 %>
six
Before this patch, it would compile to:
(
tmp1 = (
tmp2 = (
tmp1 = (
tmp2 = (
tmp1 = "" <> "one\n"
tmp1 <> String.Chars.to_string(arg1)
) <> "\ntwo\n"
var2 = String.duplicate(arg2, 1)
tmp2
) <> "\nthree\n"
tmp1 <> String.Chars.to_string(var2)
) <> "\nfour\n"
var3 = String.duplicate(arg3, 1)
tmp2
) <> "\nfive\n"
tmp1 <> String.Chars.to_string(var3)
) <> "\nsix\n"
The issue with this approach is that it emits binary append
instructions, frequently copying binaries. This commit changes
it to extract all of the dynamic contents out, as originally
suggested by @tmbb:
tmp0 = String.Chars.to_string(arg1)
var2 = String.duplicate(arg2, 1)
tmp1 = String.Chars.to_string(var2)
var3 = String.duplicate(arg3, 1)
tmp2 = String.Chars.to_string(var3)
<<"one\n", tmp0::binary, "\ntwo\n", "\nthree\n", tmp1::binary, "\nfour\n", "\nfive\n", tmp2::binary, "\nsix\n">>
Which leads to code that compiles faster and also run faster
as there are less instructions.
Erlang/OTP 20 warns if the stacktrace is read outside of a
catch/rescue. This commit mirrors this behaviour by consistently
warning on `System.stacktrace/0` being used outside of a
catch/rescue.
Erlang/OTP 21 warns whenever System.stacktrace/:erlang.get_stacktrace
are used. Therefore we need to promote the usage of `__STACKTRACE__`
and make sure to conditionally compile it according to the OTP version.
This requires changes to the Exception normalization mechanism
so we compute `__STACKTRACE__` only when strictly required.
In future Elixir releases, `System.stacktrace/0` will warn when
used even inside catch/rescue.
* Whitelist which operators support next_break_fits
* No longer consider tuples as part of next_break_fits
* Do not consider eol for = and ::
* Do not consider eol for calls with one next_break_fits arg
Elixir v1.5.0 attempted to repurpose the value of init
to use throughout the engine but such was a breaking change.
To address this problem, we added handle_begin and
handle_end which were designed exactly to handle inner
buffers.
This comes with the benefit that EEx.Engine can now have
any data structure as state and no longer only quoted
expressions.
Closes#6391.
Whenever EEx templates are used to pass variables via "assigns" whatever
this data structure is will be passed into "EEx.Engine.fetch_assign" and
then into "Access.fetch/2".
So it makes sense to use the same typespec for the both. Otherwise
dialyzer will complain about every instance where keyword lists are
passed into functions like "eval_string", "function_from_file" and
"function_from_string".