เจ็ทใช้ระบบการอนุมานประเภทของจูเลียเพื่อตรวจจับข้อบกพร่องที่อาจเกิดขึ้นและประเภทความไม่แน่นอน
คำเตือน
โปรดทราบว่าเนื่องจากการรวมกันอย่างแน่นหนาของเจ็ทกับคอมไพเลอร์จูเลียผลลัพธ์ที่นำเสนอโดยเจ็ทอาจแตกต่างกันอย่างมีนัยสำคัญขึ้นอยู่กับรุ่นของจูเลียที่คุณใช้ นอกจากนี้การใช้โมดูล Base และไลบรารีมาตรฐานที่รวมกับจูเลียยังสามารถส่งผลกระทบต่อผลลัพธ์
ยิ่งไปกว่านั้นระบบปลั๊กอินของ Julia Compiler ยังคงไม่เสถียรและอินเทอร์เฟซมีการเปลี่ยนแปลงบ่อยครั้งดังนั้นเจ็ทแต่ละรุ่นจึงเข้ากันได้กับจูเลียรุ่น จำกัด เท่านั้น Julia Package Manager จะเลือกและติดตั้ง Jet เวอร์ชันล่าสุดโดยอัตโนมัติซึ่งเข้ากันได้กับเวอร์ชัน Julia ของคุณ อย่างไรก็ตามหากคุณใช้ Julia เวอร์ชันกลางคืนโปรดทราบว่าเจ็ทเวอร์ชันที่เข้ากันได้อาจยังไม่ได้เปิดตัวและเจ็ทติดตั้งผ่าน Julia Package Manager อาจทำงานได้อย่างถูกต้อง
ดูคำสั่งเพิ่มเติมตัวเลือกและคำอธิบายในเอกสารประกอบ
Jet เป็นแพ็คเกจ Julia มาตรฐาน ดังนั้นคุณสามารถติดตั้งได้ผ่านตัวจัดการแพ็คเกจในตัวของ Julia และใช้งานเหมือนกับแพ็คเกจอื่น ๆ :
julia> using Pkg; Pkg . add ( " JET " )
[ some output elided ]
julia> using JET@report_opt ประเภทความไม่แน่นอนสามารถตรวจพบได้ในการเรียกใช้ฟังก์ชันโดยใช้มาโคร @report_opt ซึ่งทำงานคล้ายกับ macro @code_warntype โปรดทราบว่าเนื่องจากเจ็ทขึ้นอยู่กับการอนุมานประเภทของจูเลียหากห่วงโซ่การอนุมานเสียเนื่องจากการส่งแบบไดนามิกการเรียกใช้ฟังก์ชันดาวน์สตรีมทั้งหมดจะไม่เป็นที่รู้จักของคอมไพเลอร์และเจ็ทจึงไม่สามารถวิเคราะห์ได้
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 วิธีนี้ใช้งานได้ดีที่สุดในประเภทรหัสเสถียรดังนั้นให้ใช้ @report_opt อย่างอิสระก่อนที่จะใช้ @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 สิ่งนี้จะค้นหาคำจำกัดความของวิธีการทั้งหมดและวิเคราะห์การเรียกใช้ฟังก์ชันตามลายเซ็นของพวกเขา โปรดทราบว่าสิ่งนี้มีความแม่นยำน้อยกว่า @report_call เนื่องจากประเภทอินพุตจริงไม่สามารถทราบได้สำหรับวิธีการทั่วไป
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)
└──────────────────── เจ็ทสำรวจฟังก์ชั่นที่คุณเรียกโดยตรงเช่นเดียวกับ callees ที่อนุมานได้ อย่างไรก็ตามหากประเภทอาร์กิวเมนต์สำหรับการโทรไม่สามารถอนุมานได้เจ็ทจะไม่วิเคราะห์ Callee ดังนั้นรายงานที่ No errors detected ไม่ได้หมายความว่า codebase ทั้งหมดของคุณไม่มีข้อผิดพลาด เพื่อเพิ่มความมั่นใจในผลลัพธ์ของเจ็ทให้ใช้ @report_opt เพื่อให้แน่ใจว่ารหัสของคุณไม่สามารถด้อยกว่าได้
เจ็ทรวมเข้ากับ Snoopcompile และบางครั้งคุณสามารถใช้ Snoopcompile เพื่อรวบรวมข้อมูลเพื่อทำการวิเคราะห์ที่ครอบคลุมมากขึ้น ข้อ จำกัด ของ Snoopcompile คือมันรวบรวมข้อมูลสำหรับการโทรที่ไม่เคยอนุมานมาก่อนดังนั้นคุณต้องทำการวิเคราะห์ประเภทนี้ในเซสชั่นใหม่
ดูเอกสารประกอบการรวมเจ็ทของ SnoopCompile สำหรับรายละเอียดเพิ่มเติม
โครงการนี้เริ่มต้นเป็นโครงการวิทยานิพนธ์ระดับปริญญาตรีของฉันที่มหาวิทยาลัยเกียวโตภายใต้การดูแลของศาสตราจารย์ทาคาชิซากุรากาวะ เราได้รับแรงบันดาลใจอย่างมากจาก Ruby/Typeprof เครื่องมือทำความเข้าใจ/ตรวจสอบประเภทการทดลองสำหรับทับทิม วิทยานิพนธ์ระดับบัณฑิตศึกษาเกี่ยวกับโครงการนี้เผยแพร่ที่ https://github.com/aviatesk/grad-thesis แต่ปัจจุบันมีเฉพาะในภาษาญี่ปุ่นเท่านั้น