Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 49686d3

Browse files
ihnortonvtjnash
authored andcommittedMay 10, 2017
pass file and line information as an argument named __source__ to all macros
also emit an explicit push_loc in @generated functions rather than depending on the existence of a LineNumberNode and other lowering heuristics to produce it
1 parent 2496b4e commit 49686d3

33 files changed

+431
-244
lines changed
 

‎base/boot.jl

+3-1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787

8888
#struct LineNumberNode
8989
# line::Int
90+
# file::Any # nominally Union{Symbol,Void}
9091
#end
9192

9293
#struct LabelNode
@@ -281,7 +282,8 @@ _new(:GotoNode, :Int)
281282
_new(:NewvarNode, :SlotNumber)
282283
_new(:QuoteNode, :ANY)
283284
_new(:SSAValue, :Int)
284-
eval(:((::Type{LineNumberNode})(l::Int) = $(Expr(:new, :LineNumberNode, :l))))
285+
eval(:((::Type{LineNumberNode})(l::Int) = $(Expr(:new, :LineNumberNode, :l, nothing))))
286+
eval(:((::Type{LineNumberNode})(l::Int, f::ANY) = $(Expr(:new, :LineNumberNode, :l, :f))))
285287
eval(:((::Type{GlobalRef})(m::Module, s::Symbol) = $(Expr(:new, :GlobalRef, :m, :s))))
286288
eval(:((::Type{SlotNumber})(n::Int) = $(Expr(:new, :SlotNumber, :n))))
287289
eval(:((::Type{TypedSlot})(n::Int, t::ANY) = $(Expr(:new, :TypedSlot, :n, :t))))

‎base/docs/Docs.jl

+7-5
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,11 @@ function initmeta(m::Module = current_module())
8383
end
8484

8585
function signature!(tv, expr::Expr)
86-
if isexpr(expr, [:call, :macrocall])
86+
is_macrocall = isexpr(expr, :macrocall)
87+
if is_macrocall || isexpr(expr, :call)
8788
sig = :(Union{Tuple{}})
88-
for arg in expr.args[2:end]
89+
first_arg = is_macrocall ? 3 : 2 # skip function arguments
90+
for arg in expr.args[first_arg:end]
8991
isexpr(arg, :parameters) && continue
9092
if isexpr(arg, :kw) # optional arg
9193
push!(sig.args, :(Tuple{$(sig.args[end].args[2:end]...)}))
@@ -592,7 +594,7 @@ function __doc__!(meta, def, define)
592594
# the Base image). We just need to convert each `@__doc__` marker to an `@doc`.
593595
finddoc(def) do each
594596
each.head = :macrocall
595-
each.args = [Symbol("@doc"), meta, each.args[end], define]
597+
each.args = [Symbol("@doc"), nothing, meta, each.args[end], define] # TODO: forward line number info
596598
end
597599
else
598600
# `def` has already been defined during Base image gen so we just need to find and
@@ -635,7 +637,7 @@ const BINDING_HEADS = [:typealias, :const, :global, :(=)] # deprecation: remove
635637
isquotedmacrocall(x) =
636638
isexpr(x, :copyast, 1) &&
637639
isa(x.args[1], QuoteNode) &&
638-
isexpr(x.args[1].value, :macrocall, 1)
640+
isexpr(x.args[1].value, :macrocall, 2)
639641
# Simple expressions / atoms the may be documented.
640642
isbasicdoc(x) = isexpr(x, :.) || isa(x, Union{QuoteNode, Symbol})
641643
is_signature(x) = isexpr(x, :call) || (isexpr(x, :(::), 2) && isexpr(x.args[1], :call)) || isexpr(x, :where)
@@ -723,7 +725,7 @@ function docm(ex)
723725
parsedoc(keywords[ex])
724726
elseif isa(ex, Union{Expr, Symbol})
725727
binding = esc(bindingexpr(namify(ex)))
726-
if isexpr(ex, [:call, :macrocall])
728+
if isexpr(ex, :call) || isexpr(ex, :macrocall)
727729
sig = esc(signature(ex))
728730
:($(doc)($binding, $sig))
729731
else

‎base/docs/basedocs.jl

-7
Original file line numberDiff line numberDiff line change
@@ -644,13 +644,6 @@ to be set after construction. See `struct` and the manual for more information.
644644
"""
645645
kw"mutable struct"
646646

647-
"""
648-
@__LINE__ -> Int
649-
650-
`@__LINE__` expands to the line number of the call-site.
651-
"""
652-
kw"@__LINE__"
653-
654647
"""
655648
ans
656649

‎base/docs/utils.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ function repl(io::IO, s::Symbol)
190190
$(_repl(s))
191191
end
192192
end
193-
isregex(x) = isexpr(x, :macrocall, 2) && x.args[1] === Symbol("@r_str") && !isempty(x.args[2])
193+
isregex(x) = isexpr(x, :macrocall, 3) && x.args[1] === Symbol("@r_str") && !isempty(x.args[3])
194194
repl(io::IO, ex::Expr) = isregex(ex) ? :(apropos($io, $ex)) : _repl(ex)
195195
repl(io::IO, str::AbstractString) = :(apropos($io, $str))
196196
repl(io::IO, other) = :(@doc $(esc(other)))

‎base/exports.jl

+1
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,7 @@ export
12471247
# parser internal
12481248
@__FILE__,
12491249
@__DIR__,
1250+
@__LINE__,
12501251
@int128_str,
12511252
@uint128_str,
12521253
@big_str,

‎base/expr.jl

+9-2
Original file line numberDiff line numberDiff line change
@@ -276,9 +276,16 @@ end
276276

277277
remove_linenums!(ex) = ex
278278
function remove_linenums!(ex::Expr)
279-
filter!(x->!((isa(x,Expr) && x.head === :line) || isa(x,LineNumberNode)), ex.args)
279+
if ex.head === :body || ex.head === :block || ex.head === :quote
280+
# remove line number expressions from metadata (not argument literal or inert) position
281+
filter!(ex.args) do x
282+
isa(x, Expr) && x.head === :line && return false
283+
isa(x, LineNumberNode) && return false
284+
return true
285+
end
286+
end
280287
for subex in ex.args
281288
remove_linenums!(subex)
282289
end
283-
ex
290+
return ex
284291
end

‎base/inference.jl

+18-19
Original file line numberDiff line numberDiff line change
@@ -4176,39 +4176,38 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
41764176
end
41774177

41784178
do_coverage = coverage_enabled()
4179-
if do_coverage
4180-
line = method.line
4181-
if !isempty(stmts) && isa(stmts[1], LineNumberNode)
4182-
line = (shift!(stmts)::LineNumberNode).line
4179+
line::Int = method.line
4180+
file = method.file
4181+
if !isempty(stmts)
4182+
if !do_coverage && all(inlining_ignore, stmts)
4183+
empty!(stmts)
4184+
elseif isa(stmts[1], LineNumberNode)
4185+
linenode = shift!(stmts)::LineNumberNode
4186+
line = linenode.line
4187+
isa(linenode.file, Symbol) && (file = linenode.file)
41834188
end
4189+
end
4190+
if do_coverage
41844191
# Check if we are switching module, which is necessary to catch user
41854192
# code inlined into `Base` with `--code-coverage=user`.
41864193
# Assume we are inlining directly into `enclosing` instead of another
41874194
# function inlined in it
41884195
mod = method.module
41894196
if mod === sv.mod
4190-
unshift!(stmts, Expr(:meta, :push_loc, method.file,
4197+
unshift!(stmts, Expr(:meta, :push_loc, file,
41914198
method.name, line))
41924199
else
4193-
unshift!(stmts, Expr(:meta, :push_loc, method.file,
4200+
unshift!(stmts, Expr(:meta, :push_loc, file,
41944201
method.name, line, mod))
41954202
end
41964203
push!(stmts, Expr(:meta, :pop_loc))
41974204
elseif !isempty(stmts)
4198-
if all(inlining_ignore, stmts)
4199-
empty!(stmts)
4205+
unshift!(stmts, Expr(:meta, :push_loc, file,
4206+
method.name, line))
4207+
if isa(stmts[end], LineNumberNode)
4208+
stmts[end] = Expr(:meta, :pop_loc)
42004209
else
4201-
line::Int = method.line
4202-
if isa(stmts[1], LineNumberNode)
4203-
line = (shift!(stmts)::LineNumberNode).line
4204-
end
4205-
unshift!(stmts, Expr(:meta, :push_loc, method.file,
4206-
method.name, line))
4207-
if isa(stmts[end], LineNumberNode)
4208-
stmts[end] = Expr(:meta, :pop_loc)
4209-
else
4210-
push!(stmts, Expr(:meta, :pop_loc))
4211-
end
4210+
push!(stmts, Expr(:meta, :pop_loc))
42124211
end
42134212
end
42144213
if !isempty(stmts) && !propagate_inbounds

‎base/interactiveutil.jl

+3-3
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ function code_warntype(io::IO, f, t::ANY)
349349
end
350350
code_warntype(f, t::ANY) = code_warntype(STDOUT, f, t)
351351

352-
typesof(args...) = Tuple{map(a->(isa(a,Type) ? Type{a} : typeof(a)), args)...}
352+
typesof(args...) = Tuple{Any[ Core.Typeof(a) for a in args ]...}
353353

354354
gen_call_with_extracted_types(fcn, ex0::Symbol) = Expr(:call, fcn, Meta.quot(ex0))
355355
function gen_call_with_extracted_types(fcn, ex0)
@@ -371,9 +371,9 @@ function gen_call_with_extracted_types(fcn, ex0)
371371
exret = Expr(:none)
372372
is_macro = false
373373
ex = expand(ex0)
374-
if isa(ex0, Expr) && ex0.head == :macrocall # Make @edit @time 1+2 edit the macro
374+
if isa(ex0, Expr) && ex0.head == :macrocall # Make @edit @time 1+2 edit the macro by using the types of the *expressions*
375375
is_macro = true
376-
exret = Expr(:call, fcn, esc(ex0.args[1]), typesof(ex0.args[2:end]...))
376+
exret = Expr(:call, fcn, esc(ex0.args[1]), Tuple{#=__source__=#LineNumberNode, Any[ Core.Typeof(a) for a in ex0.args[3:end] ]...})
377377
elseif !isa(ex, Expr)
378378
exret = Expr(:call, :error, "expression is not a function call or symbol")
379379
elseif ex.head == :call

‎base/loading.jl

+34-18
Original file line numberDiff line numberDiff line change
@@ -521,24 +521,6 @@ function source_dir()
521521
p === nothing ? p : dirname(p)
522522
end
523523

524-
"""
525-
@__FILE__ -> AbstractString
526-
527-
`@__FILE__` expands to a string with the absolute file path of the file containing the
528-
macro. Returns `nothing` if run from a REPL or an empty string if evaluated by
529-
`julia -e <expr>`. Alternatively see [`PROGRAM_FILE`](@ref).
530-
"""
531-
macro __FILE__() source_path() end
532-
533-
"""
534-
@__DIR__ -> AbstractString
535-
536-
`@__DIR__` expands to a string with the directory part of the absolute path of the file
537-
containing the macro. Returns `nothing` if run from a REPL or an empty string if
538-
evaluated by `julia -e <expr>`.
539-
"""
540-
macro __DIR__() source_dir() end
541-
542524
include_from_node1(path::AbstractString) = include_from_node1(String(path))
543525
function include_from_node1(_path::String)
544526
path, prev = _include_dependency(_path)
@@ -806,3 +788,37 @@ function stale_cachefile(modpath::String, cachefile::String)
806788
close(io)
807789
end
808790
end
791+
792+
"""
793+
@__LINE__ -> Int
794+
795+
`@__LINE__` expands to the line number of the location of the macrocall.
796+
Returns `0` if the line number could not be determined.
797+
"""
798+
macro __LINE__()
799+
return __source__.line
800+
end
801+
802+
"""
803+
@__FILE__ -> AbstractString
804+
805+
`@__FILE__` expands to a string with the absolute file path of the file containing the
806+
macrocall. Returns `nothing` if run from a REPL or an empty string if evaluated by
807+
`julia -e <expr>`. Alternatively see [`PROGRAM_FILE`](@ref).
808+
"""
809+
macro __FILE__()
810+
__source__.file === nothing && return nothing
811+
return String(__source__.file)
812+
end
813+
814+
"""
815+
@__DIR__ -> AbstractString
816+
817+
`@__DIR__` expands to a string with the directory part of the absolute path of the file
818+
containing the macrocall. Returns `nothing` if run from a REPL or an empty string if
819+
evaluated by `julia -e <expr>`.
820+
"""
821+
macro __DIR__()
822+
__source__.file === nothing && return nothing
823+
return dirname(String(__source__.file))
824+
end

‎base/math.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ macro evalpoly(z, p...)
124124
:(s = muladd(x, x, y*y)),
125125
as...,
126126
:(muladd($ai, tt, $b)))
127-
R = Expr(:macrocall, Symbol("@horner"), :tt, map(esc, p)...)
127+
R = Expr(:macrocall, Symbol("@horner"), (), :tt, map(esc, p)...)
128128
:(let tt = $(esc(z))
129129
isa(tt, Complex) ? $C : $R
130130
end)

‎base/show.jl

+22-14
Original file line numberDiff line numberDiff line change
@@ -495,10 +495,6 @@ const prec_decl = operator_precedence(:(::))
495495
is_expr(ex, head::Symbol) = (isa(ex, Expr) && (ex.head == head))
496496
is_expr(ex, head::Symbol, n::Int) = is_expr(ex, head) && length(ex.args) == n
497497

498-
is_linenumber(ex::LineNumberNode) = true
499-
is_linenumber(ex::Expr) = (ex.head == :line)
500-
is_linenumber(ex) = false
501-
502498
is_quoted(ex) = false
503499
is_quoted(ex::QuoteNode) = true
504500
is_quoted(ex::Expr) = is_expr(ex, :quote, 1) || is_expr(ex, :inert, 1)
@@ -528,18 +524,22 @@ end
528524

529525
emphasize(io, str::AbstractString) = have_color ? print_with_color(Base.error_color(), io, str; bold = true) : print(io, uppercase(str))
530526

531-
show_linenumber(io::IO, line) = print(io," # line ",line,':')
532-
show_linenumber(io::IO, line, file) = print(io," # ", file,", line ",line,':')
527+
show_linenumber(io::IO, line) = print(io, "#= line ", line, " =#")
528+
show_linenumber(io::IO, line, file) = print(io, "#= ", file, ":", line, " =#")
529+
show_linenumber(io::IO, line, file::Void) = show_linenumber(io, line)
533530

534531
# show a block, e g if/for/etc
535532
function show_block(io::IO, head, args::Vector, body, indent::Int)
536-
print(io, head, ' ')
537-
show_list(io, args, ", ", indent)
533+
print(io, head)
534+
if !isempty(args)
535+
print(io, ' ')
536+
show_list(io, args, ", ", indent)
537+
end
538538

539539
ind = head === :module || head === :baremodule ? indent : indent + indent_width
540540
exs = (is_expr(body, :block) || is_expr(body, :body)) ? body.args : Any[body]
541541
for ex in exs
542-
if !is_linenumber(ex); print(io, '\n', " "^ind); end
542+
print(io, '\n', " "^ind)
543543
show_unquoted(io, ex, ind, -1)
544544
end
545545
print(io, '\n', " "^indent)
@@ -556,7 +556,7 @@ end
556556
# show an indented list
557557
function show_list(io::IO, items, sep, indent::Int, prec::Int=0, enclose_operators::Bool=false)
558558
n = length(items)
559-
if n == 0; return end
559+
n == 0 && return
560560
indent += indent_width
561561
first = true
562562
for item in items
@@ -603,7 +603,7 @@ end
603603
## AST printing ##
604604

605605
show_unquoted(io::IO, sym::Symbol, ::Int, ::Int) = print(io, sym)
606-
show_unquoted(io::IO, ex::LineNumberNode, ::Int, ::Int) = show_linenumber(io, ex.line)
606+
show_unquoted(io::IO, ex::LineNumberNode, ::Int, ::Int) = show_linenumber(io, ex.line, ex.file)
607607
show_unquoted(io::IO, ex::LabelNode, ::Int, ::Int) = print(io, ex.label, ": ")
608608
show_unquoted(io::IO, ex::GotoNode, ::Int, ::Int) = print(io, "goto ", ex.label)
609609
show_unquoted(io::IO, ex::GlobalRef, ::Int, ::Int) = print(io, ex.mod, '.', ex.name)
@@ -903,12 +903,20 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int)
903903
print(io, head, ' ')
904904
show_list(io, args, ", ", indent)
905905

906-
elseif head === :macrocall && nargs >= 1
906+
elseif head === :macrocall && nargs >= 2
907+
# first show the line number argument as a comment
908+
if isa(args[2], LineNumberNode) || is_expr(args[2], :line)
909+
print(io, args[2], ' ')
910+
end
907911
# Use the functional syntax unless specifically designated with prec=-1
912+
# and hide the line number argument from the argument list
908913
if prec >= 0
909-
show_call(io, :call, ex.args[1], ex.args[2:end], indent)
914+
show_call(io, :call, args[1], args[3:end], indent)
910915
else
911-
show_list(io, args, ' ', indent)
916+
show_args = Vector{Any}(length(args) - 1)
917+
show_args[1] = args[1]
918+
show_args[2:end] = args[3:end]
919+
show_list(io, show_args, ' ', indent)
912920
end
913921

914922
elseif head === :line && 1 <= nargs <= 2

‎doc/Makefile

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Makefile for building documentation
22

3+
skip:
4+
@echo SKIPPING BUILD DOCS
5+
mkdir -p _build/html
6+
7+
38
default: html
49

510
# You can set these variables from the command line.

0 commit comments

Comments
 (0)
Please sign in to comment.