From b609aa4f66caaac843867d7dc30c414e2e6b62da Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 27 Jun 2020 07:14:20 -0500 Subject: [PATCH 1/2] Specify interface for LibGit2 abstract types This improves inference results for a number LibGit2 operations, and reduces invalidations from methods (notably, `peel`) that operate on the values extracted from these fields. --- stdlib/LibGit2/src/types.jl | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/stdlib/LibGit2/src/types.jl b/stdlib/LibGit2/src/types.jl index 6276544100888..c94bc01acaaf0 100644 --- a/stdlib/LibGit2/src/types.jl +++ b/stdlib/LibGit2/src/types.jl @@ -966,11 +966,43 @@ function split_cfg_entry(ce::ConfigEntry) end # Abstract object types + +""" + AbstractGitObject + +`AbstractGitObject`s must obey the following interface: +- `obj.owner`, if present, must be a `Union{Nothing,GitRepo,GitTree}` +- `obj.ptr`, if present, must be a `Union{Ptr{Cvoid},Ptr{SignatureStruct}}` +""" abstract type AbstractGitObject end + +function Base.getproperty(obj::AbstractGitObject, name::Symbol) + if name === :owner + return getfield(obj, :owner)::Union{Nothing,GitRepo,GitTree} + elseif name === :ptr + return getfield(obj, :ptr)::Union{Ptr{Cvoid},Ptr{SignatureStruct}} + else + return getfield(obj, name) + end +end + Base.isempty(obj::AbstractGitObject) = (obj.ptr == C_NULL) +# `GitObject`s must obey the following interface: +# - `obj.owner` must be a `GitRepo` +# - `obj.ptr` must be a Ptr{Cvoid} abstract type GitObject <: AbstractGitObject end +function Base.getproperty(obj::GitObject, name::Symbol) + if name === :owner + return getfield(obj, :owner)::GitRepo + elseif name === :ptr + return getfield(obj, :ptr)::Ptr{Cvoid} + else + return getfield(obj, name) + end +end + for (typ, owntyp, sup, cname) in [ (:GitRepo, nothing, :AbstractGitObject, :git_repository), (:GitConfig, :(Union{GitRepo, Nothing}), :AbstractGitObject, :git_config), From 9b0c0386b82825e10fc4720221b3259f3709edb9 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Mon, 13 Jul 2020 05:13:02 -0500 Subject: [PATCH 2/2] Explain the getproperty methods --- stdlib/LibGit2/src/types.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stdlib/LibGit2/src/types.jl b/stdlib/LibGit2/src/types.jl index c94bc01acaaf0..fb76331c04e55 100644 --- a/stdlib/LibGit2/src/types.jl +++ b/stdlib/LibGit2/src/types.jl @@ -977,6 +977,10 @@ end abstract type AbstractGitObject end function Base.getproperty(obj::AbstractGitObject, name::Symbol) + # These type-assertions enforce the interface requirements above. + # They assist type-inference in cases where the compiler only knows that it + # has an `AbstractGitObject` without being certain about the concrete type. + # See detailed explanation in https://github.com/JuliaLang/julia/pull/36452. if name === :owner return getfield(obj, :owner)::Union{Nothing,GitRepo,GitTree} elseif name === :ptr