foo.bar.<TAB> Completion Not Working

I’ve got a type

struct Configuration
    p::Ptr{configuration_t}
    key::id_t
end

which wraps a nested configuration type from C.

I can look up the subkeys of this type with keys(c::Configuration) , and I allow tab completion by overloading Base.getproperty(c::Configuration, v::Symbol) where v is one of the symbols returned by keys . getproperty will return a new Configuration struct with the same pointer, but the new key.

The problem I’m having is with Base.propertynames , or really with tab completion. At the first level this is fine. I can run cf = Configuration() and then cf.<TAB> and I get a list of the available properties.

However , if I take one of those properties, like solve and do cf.solve.<TAB> nothing happens. If I do cf.solve I get the correct object, and if I do propertynames(cf.solve) I get the correct list of symbols. Any idea where the disconnect is happening here? I’m not sure how I would debug the autocompletion, especially since propertynames works correctly.

The getproperty is:

function Base.getproperty(c::Configuration, v::Symbol)
    if v ∈ fieldnames(Configuration)
        return getfield(c, v)
    end
    s = String(v)
    k = subkey(c,s)
    k === nothing && error("Configuration has no field $s")
    return Configuration(c.p, k)
end

subkey gets the integer key for a string like “solve”.

The propertynames is:

function Base.propertynames(c::Configuration)
    return Symbol.(keys(c))
end

There’s not a super great MWE since there’s a lot of ccalls. I will say, though, that the simplest possible example

struct A
    i
end
x = A(A(1))
x.i.<TAB>

works just find and x.i.<TAB> becomes x.i.i.

1 Like

It seems I’ve found the issue. getproperty is not type stable. The full function is

function Base.getproperty(c::Configuration, v::Symbol)
    if v ∈ fieldnames(Configuration)
        return getfield(c, v)
    end
    s = String(v)
    k = subkey(c,s)
    k === nothing && error("Configuration has no field $s")
    if checktype(c,k, configuration_type_value)
        if configuration_value_is_assigned(c, k)
            return configuration_value_get(c, k)
        else
            return nothing
        end
    end
    return Configuration(c.p, k)
end

And nothing is creating type instability which might be the source of the issue? I’m not sure it’s possible to make this type stable…

1 Like

Alright so removing the nothing doesn’t really help here. If I do like this:

function Base.getproperty(c::Configuration, v::Symbol)
    if v === :p
        return Base.getfield(c, :p)
    elseif v === :key
        return Base.getfield(c, :key)
    elseif v === :name
        return Base.getfield(c, :name)
    end
    s = String(v)
    k = subkey(c,s)
    k === nothing && error("type Configuration has no field $s")

    return Configuration(c.p, k, s)
end

I still can’t get auto-complete working. I assume it’s because this still isn’t technically type stable? Is there any way to get nested auto-complete with an overloaded getproperty?