Jet utilise le système d'inférence de type de Julia pour détecter les bogues potentiels et les instabilités de type.
Avertissement
Veuillez noter qu'en raison de l'intégration serrée de Jet avec le compilateur Julia, les résultats présentés par Jet peuvent varier considérablement en fonction de la version de Julia que vous utilisez. De plus, la mise en œuvre du module Base et des bibliothèques standard regroupées avec Julia peut également affecter les résultats.
De plus, le système de plugin du compilateur Julia est toujours instable et son interface change fréquemment, donc chaque version de Jet est compatible avec seulement des versions limitées de Julia. Le Julia Package Manager sélectionnera automatiquement et installera la dernière version de Jet qui est compatible avec votre version Julia. Cependant, si vous utilisez la version nocturne de Julia, veuillez noter qu'une version compatible de Jet n'a peut-être pas encore été publiée, et le jet installé via le gestionnaire de package Julia peut ne pas fonctionner correctement.
Voir plus de commandes, d'options et d'explications dans la documentation.
Jet est un package Julia standard. Vous pouvez donc simplement l'installer via le gestionnaire de packages intégré de Julia et l'utiliser comme n'importe quel autre package:
julia> using Pkg; Pkg . add ( " JET " )
[ some output elided ]
julia> using JET@report_opt Les instabilités de type peuvent être détectées dans les appels de fonction à l'aide de la macro @report_opt , qui fonctionne similaire à la macro @code_warntype . Notez que, parce que Jet repose sur l'inférence du type de Julia, si une chaîne d'inférence est rompue en raison d'un répartition dynamique, tous les appels de fonction en aval seront inconnus du compilateur, et donc Jet ne peut pas les analyser.
julia> @report_opt foldl ( + , Any[]; init = 0 )
═════ 2 possible errors found ═════
┌ kwcall(::@NamedTuple{init::Int64}, ::typeof(foldl), op::typeof(+), itr::Vector{Any}) @ Base ./reduce.jl:198
│┌ foldl(op::typeof(+), itr::Vector{Any}; kw::@Kwargs{init::Int64}) @ Base ./reduce.jl:198
││┌ kwcall(::@NamedTuple{init::Int64}, ::typeof(mapfoldl), f::typeof(identity), op::typeof(+), itr::Vector{Any}) @ Base ./reduce.jl:175
│││┌ mapfoldl(f::typeof(identity), op::typeof(+), itr::Vector{Any}; init::Int64) @ Base ./reduce.jl:175
││││┌ mapfoldl_impl(f::typeof(identity), op::typeof(+), nt::Int64, itr::Vector{Any}) @ Base ./reduce.jl:44
│││││┌ foldl_impl(op::Base.BottomRF{typeof(+)}, nt::Int64, itr::Vector{Any}) @ Base ./reduce.jl:48
││││││┌ _foldl_impl(op::Base.BottomRF{typeof(+)}, init::Int64, itr::Vector{Any}) @ Base ./reduce.jl:58
│││││││┌ (::Base.BottomRF{typeof(+)})(acc::Int64, x::Any) @ Base ./reduce.jl:86
││││││││ runtime dispatch detected: +(acc::Int64, x::Any)::Any
│││││││└────────────────────
││││││┌ _foldl_impl(op::Base.BottomRF{typeof(+)}, init::Int64, itr::Vector{Any}) @ Base ./reduce.jl:62
│││││││┌ (::Base.BottomRF{typeof(+)})(acc::Any, x::Any) @ Base ./reduce.jl:86
││││││││ runtime dispatch detected: +(acc::Any, x::Any)::Any
│││││││└────────────────────@report_call Cela fonctionne mieux sur le code stable de type, alors utilisez @report_opt généreusement avant d'utiliser @report_call .
julia> @report_call foldl ( + , Char[])
═════ 2 possible errors found ═════
┌ foldl(op::typeof(+), itr::Vector{Char}) @ Base ./reduce.jl:198
│┌ foldl(op::typeof(+), itr::Vector{Char}; kw::@Kwargs{}) @ Base ./reduce.jl:198
││┌ mapfoldl(f::typeof(identity), op::typeof(+), itr::Vector{Char}) @ Base ./reduce.jl:175
│││┌ mapfoldl(f::typeof(identity), op::typeof(+), itr::Vector{Char}; init::Base._InitialValue) @ Base ./reduce.jl:175
││││┌ mapfoldl_impl(f::typeof(identity), op::typeof(+), nt::Base._InitialValue, itr::Vector{Char}) @ Base ./reduce.jl:44
│││││┌ foldl_impl(op::Base.BottomRF{typeof(+)}, nt::Base._InitialValue, itr::Vector{Char}) @ Base ./reduce.jl:48
││││││┌ _foldl_impl(op::Base.BottomRF{typeof(+)}, init::Base._InitialValue, itr::Vector{Char}) @ Base ./reduce.jl:62
│││││││┌ (::Base.BottomRF{typeof(+)})(acc::Char, x::Char) @ Base ./reduce.jl:86
││││││││ no matching method found `+(::Char, ::Char)`: (op::Base.BottomRF{typeof(+)}).rf::typeof(+)(acc::Char, x::Char)
│││││││└────────────────────
│││││┌ foldl_impl(op::Base.BottomRF{typeof(+)}, nt::Base._InitialValue, itr::Vector{Char}) @ Base ./reduce.jl:49
││││││┌ reduce_empty_iter(op::Base.BottomRF{typeof(+)}, itr::Vector{Char}) @ Base ./reduce.jl:383
│││││││┌ reduce_empty_iter(op::Base.BottomRF{typeof(+)}, itr::Vector{Char}, ::Base.HasEltype) @ Base ./reduce.jl:384
││││││││┌ reduce_empty(op::Base.BottomRF{typeof(+)}, ::Type{Char}) @ Base ./reduce.jl:360
│││││││││┌ reduce_empty(::typeof(+), ::Type{Char}) @ Base ./reduce.jl:343
││││││││││ no matching method found `zero(::Type{Char})`: zero(T::Type{Char})
│││││││││└────────────────────report_package Cela recherche toutes les définitions de méthode et analyse les appels de fonction en fonction de leurs signatures. Notez que cela est moins précis que @report_call , car les types d'entrée réels ne peuvent pas être connus pour les méthodes génériques.
julia> using Pkg; Pkg . activate (; temp = true , io = devnull ); Pkg . add ( " AbstractTrees " ; io = devnull );
julia> Pkg . status ()
Status `/private/var/folders/xh/6zzly9vx71v05_y67nm_s9_c0000gn/T/jl_h07K2m/Project.toml`
[1520ce14] AbstractTrees v0.4.4
julia> report_package ( " AbstractTrees " )
[ some output elided ]
═════ 7 possible errors found ═════
┌ isroot(root::Any, x::Any) @ AbstractTrees ~/.julia/packages/AbstractTrees/EUx8s/src/base.jl:102
│ no matching method found `parent(::Any, ::Any)`: AbstractTrees.parent(root::Any, x::Any)
└────────────────────
┌ AbstractTrees.IndexNode(tree::Any) @ AbstractTrees ~/.julia/packages/AbstractTrees/EUx8s/src/indexing.jl:117
│ no matching method found `rootindex(::Any)`: rootindex(tree::Any)
└────────────────────
┌ parent(idx::AbstractTrees.IndexNode) @ AbstractTrees ~/.julia/packages/AbstractTrees/EUx8s/src/indexing.jl:127
│ no matching method found `parentindex(::Any, ::Any)`: pidx = parentindex((idx::AbstractTrees.IndexNode).tree::Any, (idx::AbstractTrees.IndexNode).index::Any)
└────────────────────
┌ nextsibling(idx::AbstractTrees.IndexNode) @ AbstractTrees ~/.julia/packages/AbstractTrees/EUx8s/src/indexing.jl:132
│ no matching method found `nextsiblingindex(::Any, ::Any)`: sidx = nextsiblingindex((idx::AbstractTrees.IndexNode).tree::Any, (idx::AbstractTrees.IndexNode).index::Any)
└────────────────────
┌ prevsibling(idx::AbstractTrees.IndexNode) @ AbstractTrees ~/.julia/packages/AbstractTrees/EUx8s/src/indexing.jl:137
│ no matching method found `prevsiblingindex(::Any, ::Any)`: sidx = prevsiblingindex((idx::AbstractTrees.IndexNode).tree::Any, (idx::AbstractTrees.IndexNode).index::Any)
└────────────────────
┌ prevsibling(csr::AbstractTrees.IndexedCursor) @ AbstractTrees ~/.julia/packages/AbstractTrees/EUx8s/src/cursors.jl:234
│ no matching method found `getindex(::Nothing, ::Int64)` (1/2 union split): (AbstractTrees.parent(csr::AbstractTrees.IndexedCursor)::Union{Nothing, AbstractTrees.IndexedCursor})[idx::Int64]
└────────────────────
┌ (::AbstractTrees.var"#17#18")(n::Any) @ AbstractTrees ~/.julia/packages/AbstractTrees/EUx8s/src/iteration.jl:323
│ no matching method found `parent(::Any, ::Any)`: AbstractTrees.parent(getfield(#self#::AbstractTrees.var"#17#18", :tree)::Any, n::Any)
└──────────────────── Jet explore les fonctions que vous appelez directement ainsi que leurs callees déduites . Cependant, si les types d'arguments pour un appel ne peuvent pas être déduits, Jet n'analyse pas la Callee. Par conséquent, un rapport de No errors detected n'implique pas que toute votre base de code est exempte d'erreurs. Pour accroître la confiance dans les résultats de Jet, utilisez @report_opt pour vous assurer que votre code est inferrible.
Jet s'intègre à SnoopCompile, et vous pouvez parfois utiliser SnoopCompile pour collecter les données pour effectuer des analyses plus complètes. La limitation de SnoopCompile est qu'elle ne collecte que des données pour les appels qui n'ont pas été déduits auparavant, vous devez donc effectuer ce type d'analyse dans une nouvelle session.
Voir la documentation d'intégration de jet de SnoopCompile pour plus de détails.
Ce projet a commencé comme mon projet de thèse de premier cycle à l'Université de Kyoto, supervisé par le professeur Takashi Sakuragawa. Nous avons été fortement inspirés par Ruby / TypeProf, un outil de compréhension / vérification de type expérimental pour Ruby. La thèse des diplômés sur ce projet est publiée sur https://github.com/aviatesk/grad-thesis, mais actuellement, elle n'est disponible qu'en japonais.