forked from JuliaLang/julia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
experimental.jl
255 lines (213 loc) · 7.64 KB
/
experimental.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# This file is a part of Julia. License is MIT: https://julialang.org/license
"""
Experimental
!!! warning
Types, methods, or macros defined in this module are experimental and subject
to change and will not have deprecations. Caveat emptor.
"""
module Experimental
using Base: Threads, sync_varname
"""
Const(A::Array)
Mark an Array as constant/read-only. The invariant guaranteed is that you will not
modify an Array (through another reference) within an `@aliasscope` scope.
!!! warning
Experimental API. Subject to change without deprecation.
"""
struct Const{T,N} <: DenseArray{T,N}
a::Array{T,N}
end
Base.IndexStyle(::Type{<:Const}) = IndexLinear()
Base.size(C::Const) = size(C.a)
Base.axes(C::Const) = axes(C.a)
@eval Base.getindex(A::Const, i1::Int) =
(Base.@_inline_meta; Core.const_arrayref($(Expr(:boundscheck)), A.a, i1))
@eval Base.getindex(A::Const, i1::Int, i2::Int, I::Int...) =
(Base.@_inline_meta; Core.const_arrayref($(Expr(:boundscheck)), A.a, i1, i2, I...))
"""
@aliasscope expr
Allows the compiler to assume that all `Const`s are not being modified through stores
within this scope, even if the compiler can't prove this to be the case.
!!! warning
Experimental API. Subject to change without deprecation.
"""
macro aliasscope(body)
sym = gensym()
quote
$(Expr(:aliasscope))
$sym = $(esc(body))
$(Expr(:popaliasscope))
$sym
end
end
function sync_end(c::Channel{Any})
if !isready(c)
# there must be at least one item to begin with
close(c)
return
end
nremaining::Int = 0
while true
event = take!(c)
if event === :__completion__
nremaining -= 1
if nremaining == 0
break
end
else
nremaining += 1
schedule(Task(()->begin
try
wait(event)
put!(c, :__completion__)
catch e
close(c, e)
end
end))
end
end
close(c)
nothing
end
"""
Experimental.@sync
Wait until all lexically-enclosed uses of `@async`, `@spawn`, `@spawnat` and `@distributed`
are complete, or at least one of them has errored. The first exception is immediately
rethrown. It is the responsibility of the user to cancel any still-running operations
during error handling.
!!! Note
This interface is experimental and subject to change or removal without notice.
"""
macro sync(block)
var = esc(sync_varname)
quote
let $var = Channel(Inf)
v = $(esc(block))
sync_end($var)
v
end
end
end
"""
Experimental.@optlevel n::Int
Set the optimization level (equivalent to the `-O` command line argument)
for code in the current module. Submodules inherit the setting of their
parent module.
Supported values are 0, 1, 2, and 3.
The effective optimization level is the minimum of that specified on the
command line and in per-module settings.
"""
macro optlevel(n::Int)
return Expr(:meta, :optlevel, n)
end
"""
Experimental.@compiler_options optimize={0,1,2,3} compile={yes,no,all,min} infer={yes,no}
Set compiler options for code in the enclosing module. Options correspond directly to
command-line options with the same name, where applicable. The following options
are currently supported:
* `optimize`: Set optimization level.
* `compile`: Toggle native code compilation. Currently only `min` is supported, which
requests the minimum possible amount of compilation.
* `infer`: Enable or disable type inference. If disabled, implies [`@nospecialize`](@ref).
"""
macro compiler_options(args...)
opts = Expr(:block)
for ex in args
if isa(ex, Expr) && ex.head === :(=) && length(ex.args) == 2
if ex.args[1] === :optimize
push!(opts.args, Expr(:meta, :optlevel, ex.args[2]::Int))
elseif ex.args[1] === :compile
a = ex.args[2]
a = #a === :no ? 0 :
#a === :yes ? 1 :
#a === :all ? 2 :
a === :min ? 3 : error("invalid argument to \"compile\" option")
push!(opts.args, Expr(:meta, :compile, a))
elseif ex.args[1] === :infer
a = ex.args[2]
a = a === false || a === :no ? 0 :
a === true || a === :yes ? 1 : error("invalid argument to \"infer\" option")
push!(opts.args, Expr(:meta, :infer, a))
else
error("unknown option \"$(ex.args[1])\"")
end
else
error("invalid option syntax")
end
end
return opts
end
# UI features for errors
"""
Experimental.register_error_hint(handler, exceptiontype)
Register a "hinting" function `handler(io, exception)` that can
suggest potential ways for users to circumvent errors. `handler`
should examine `exception` to see whether the conditions appropriate
for a hint are met, and if so generate output to `io`.
Packages should call `register_error_hint` from within their
`__init__` function.
For specific exception types, `handler` is required to accept additional arguments:
- `MethodError`: provide `handler(io, exc::MethodError, argtypes, kwargs)`,
which splits the combined arguments into positional and keyword arguments.
When issuing a hint, the output should typically start with `\\n`.
If you define custom exception types, your `showerror` method can
support hints by calling [`Experimental.show_error_hints`](@ref).
# Example
```
julia> module Hinter
only_int(x::Int) = 1
any_number(x::Number) = 2
function __init__()
Base.Experimental.register_error_hint(MethodError) do io, exc, argtypes, kwargs
if exc.f == only_int
# Color is not necessary, this is just to show it's possible.
print(io, "\\nDid you mean to call ")
printstyled(io, "`any_number`?", color=:cyan)
end
end
end
end
```
Then if you call `Hinter.only_int` on something that isn't an `Int` (thereby triggering a `MethodError`), it issues the hint:
```
julia> Hinter.only_int(1.0)
ERROR: MethodError: no method matching only_int(::Float64)
Did you mean to call `any_number`?
Closest candidates are:
...
```
!!! compat "Julia 1.5"
Custom error hints are available as of Julia 1.5.
!!! warning
This interface is experimental and subject to change or removal without notice.
To insulate yourself against changes, consider putting any registrations inside an
`if isdefined(Base.Experimental, :register_error_hint) ... end` block.
"""
function register_error_hint(@nospecialize(handler), @nospecialize(exct::Type))
list = get!(Vector{Any}, _hint_handlers, exct)
push!(list, handler)
return nothing
end
const _hint_handlers = IdDict{Type,Vector{Any}}()
"""
Experimental.show_error_hints(io, ex, args...)
Invoke all handlers from [`Experimental.register_error_hint`](@ref) for the particular
exception type `typeof(ex)`. `args` must contain any other arguments expected by
the handler for that type.
!!! compat "Julia 1.5"
Custom error hints are available as of Julia 1.5.
!!! warning
This interface is experimental and subject to change or removal without notice.
"""
function show_error_hints(io, ex, args...)
hinters = get!(()->[], _hint_handlers, typeof(ex))
for handler in hinters
try
Base.invokelatest(handler, io, ex, args...)
catch err
tn = typeof(handler).name
@error "Hint-handler $handler for $(typeof(ex)) in $(tn.module) caused an error"
end
end
end
end