Strange Revise error

I have run into a strange error that appears to be related to Revise. Revise reports a problem with a function

Revise error message
julia> Revise.retry()
┌ Error: Failed to revise /home/brian/repos/Differentiation/src/Factoring.jl
│   exception =
│    function type in method definition is not a type
│    Stacktrace:
│     [1] top-level scope @ ~/repos/Differentiation/src/Factoring.jl:108
│    Revise evaluation error at /home/brian/repos/Differentiation/src/Factoring.jl:108
│    
└ @ Revise ~/.julia/packages/Revise/do2nH/src/packagedef.jl:715
┌ Error: Failed to revise /home/brian/repos/Differentiation/src/Factoring.jl
│   exception =
│    function type in method definition is not a type
│    Stacktrace:
│     [1] top-level scope @ ~/repos/Differentiation/src/Factoring.jl:108
│    Revise evaluation error at /home/brian/repos/Differentiation/src/Factoring.jl:108
│    
└ @ Revise ~/.julia/packages/Revise/do2nH/src/packagedef.jl:715

and once this error occurs once it seems impossible to get rid of it no matter how the code in the function is altered. The error message is exactly the same at the same line number even if that line number is no longer in the function.

Tried making a MWE but it’s difficult; can’t just comment out parts of the code until the error goes away because it never goes away.

Here is the function causing the problem:

Function causing the problem
function frontier_nodes(graph::DerivativeGraph, base_node::T, dom_node::T) where {T<:Integer}
    # condition for a frontier node for the dominance case, i.e., base_node > dom_node. Post dominance conditions in parentheses: 
    #     frontier node is contained in the domainance subgraph (base_node,dom_node) and
    #     frontier node has a child that is not part of the dominance subgraph
    # Edges on the path from frontier node to base_node have to be preserved after factorization because these paths are not part of the factored subgraph.

    nodes_on_frontier = Set{T}()

    validate_node_numbers(graph, base_node, dom_node)

    if base_node > dom_node
        if !dom(graph, base_node, dom_node)
            throw(ErrorException("tried to find frontier nodes in an invalid subgraph. Should have dom(base_node,dom_node) == true but it isn't."))
        end

        function dom_frontier_test(x) 
            if x == dom_node || x == base_node
                return false
            else
                for child_num in node_children_numbers(graph, x)
                    if !in_subgraph(graph, base_node, dom_node, child_num)
                        return true
                    end
                end

                return false
            end
        end

        inside_test = (x) -> dom(graph, base_node, x) && x <= base_node
        relation = (x) -> (x == base_node) ? T[] : node_parent_numbers(graph, x)
        _frontier_nodes(dom_node, relation, dom_frontier_test, inside_test, nodes_on_frontier)
    else
        if !pdom(graph, base_node, dom_node) #maybe should throw an exception here?
            throw(ErrorException("tried to find frontier nodes in an invalid subgraph. Should have pdom(base_node,dom_node) == true but it isn't."))
        end

        function pdom_frontier_test(x)
            if x == dom_node || x == base_node
                return false
            else
                for parent_num in node_parent_numbers(graph, x)
                    if !in_subgraph(graph, base_node, dom_node, parent_num)
                        return true
                    end
                end

                return false
            end
        end

        #this might be inefficient if the inside_test function has to be compiled each time because it captures base_node.
        inside_test = (x) -> x >= base_node && pdom(graph, base_node, x)  #base_node can satisfy the frontier test but it doesn't matter because no edges will be preserved. So base node shouldn't be in list of frontier nodes.
        relation = (x) -> node_children_numbers(graph, x)
        _frontier_nodes(dom_node, relation, pdom_frontier_test, inside_test, nodes_on_frontier)
    end

    return nodes_on_frontier
end
export frontier_nodes

Once the error is triggered no code change seems able to make Revise not report the error. If almost every line of code inside the function is commented out

Function with most code commented out

function frontier_nodes(graph::DerivativeGraph, base_node::T, dom_node::T) where {T<:Integer}
    # condition for a frontier node for the dominance case, i.e., base_node > dom_node. Post dominance conditions in parentheses: 
    #     frontier node is contained in the domainance subgraph (base_node,dom_node) and
    #     frontier node has a child that is not part of the dominance subgraph
    # Edges on the path from frontier node to base_node have to be preserved after factorization because these paths are not part of the factored subgraph.

    nodes_on_frontier = Set{T}()

    # validate_node_numbers(graph, base_node, dom_node)

    # if base_node > dom_node
    #     if !dom(graph, base_node, dom_node)
    #         throw(ErrorException("tried to find frontier nodes in an invalid subgraph. Should have dom(base_node,dom_node) == true but it isn't."))
    #     end

    #     function dom_frontier_test(x) 
    #         if x == dom_node || x == base_node
    #             return false
    #         else
    #             for child_num in node_children_numbers(graph, x)
    #                 if !in_subgraph(graph, base_node, dom_node, child_num)
    #                     return true
    #                 end
    #             end

    #             return false
    #         end
    #     end

    #     inside_test = (x) -> dom(graph, base_node, x) && x <= base_node
    #     relation = (x) -> (x == base_node) ? T[] : node_parent_numbers(graph, x)
    #     _frontier_nodes(dom_node, relation, dom_frontier_test, inside_test, nodes_on_frontier)
    # else
    #     if !pdom(graph, base_node, dom_node) #maybe should throw an exception here?
    #         throw(ErrorException("tried to find frontier nodes in an invalid subgraph. Should have pdom(base_node,dom_node) == true but it isn't."))
    #     end

    #     function pdom_frontier_test(x)
    #         if x == dom_node || x == base_node
    #             return false
    #         else
    #             for parent_num in node_parent_numbers(graph, x)
    #                 if !in_subgraph(graph, base_node, dom_node, parent_num)
    #                     return true
    #                 end
    #             end

    #             return false
    #         end
    #     end

    #     #this might be inefficient if the inside_test function has to be compiled each time because it captures base_node.
    #     inside_test = (x) -> x >= base_node && pdom(graph, base_node, x)  #base_node can satisfy the frontier test but it doesn't matter because no edges will be preserved. So base node shouldn't be in list of frontier nodes.
    #     relation = (x) -> node_children_numbers(graph, x)
    #     _frontier_nodes(dom_node, relation, pdom_frontier_test, inside_test, nodes_on_frontier)
    # end

    return nodes_on_frontier
end
export frontier_nodes

Revise still gives the same error message, with the same line number. If I then kill and restart the REPL and call this same function it runs fine with no Revise errors.

If the commented code is uncommented then the error appears again. Recommenting exactly the same lines that were uncommented doesn’t cause the error to go away.

If all the commented code is deleted then Revise reports the same error at the same line number, 108, even though that line number isn’t in the function anymore.

Has anybody encountered this problem before?

Just a hunch. pdom_frontier_test is defined and used on both branches of the if statement. Perhaps having a different function name for each branch will unconfuse Revise. This should not matter to the logic of the code.

If that is not an option, maybe defining a ‘stub’ function and assigning to pdom_frontier_test before the if split. Then inside the if, reassig to the specifc branch version.

Totally hunch based and untested suggestion.

Thanks for the suggestion but I think pdom_frontier_test is only defined in one branch of the if. dom_frontier_test is defined in the other.

But your suggestion got me thinking that Revise might be having trouble tracking the functions being defined inside frontier_nodes. So I moved dom_frontier_test and pdom_frontier_test outside of frontier_nodes. Now Revise is happy and everything works.

Thanks for the nudge in the right direction.

1 Like

I won’t pretend I’ve actually read your code or understand the solution, but if you think it might have been reasonable to expect of Revise to track the definitions in their original place it might be worth an issue?

I spoke too soon. The same revise error is back now, even after I moved the function definitions outside of the frontier_nodes function.

This looks like a bug. The code compiles and runs fine the first time. Then after any change that causes Revise to look at the file the error pops up and doesn’t go away, apparently no matter what changes are made to the code including completely deleting the function that caused the Revise error. Same error, same line number.

The only way to make it go away is to kill the REPL and restart. That doesn’t seem like the way Revise should work.

I’ll file an issue.