public static int allocateSlots(Expression exp, int nextFree, SlotManager frame) {
        if (exp instanceof Assignation) {
            ((Assignation)exp).setSlotNumber(nextFree);
            int count = ((Assignation)exp).getRequiredSlots();
            nextFree += count;
            if (frame != null) {
                frame.allocateSlotNumber(((Assignation)exp).getVariableQName());
                if (count == 2) {
                    frame.allocateSlotNumber(((ForExpression)exp).getPositionVariableName());
                }
            }
        }
        if (exp instanceof VariableReference) {
            VariableReference var = (VariableReference)exp;
            Binding binding = var.getBinding();
            if (exp instanceof LocalVariableReference) {
                ((LocalVariableReference)var).setSlotNumber(binding.getLocalSlotNumber());
            }
            if (binding instanceof Assignation && binding.getLocalSlotNumber() < 0) {
                // This indicates something badly wrong: we've found a variable reference on the tree, that's
                // bound to a variable declaration that is no longer on the tree. All we can do is print diagnostics.
                // The most common reason for this failure is that the declaration of the variable was removed
                // from the tree in the mistaken belief that there were no references to the variable. Variable
                // references are counted during the typeCheck phase, so this can happen if typeCheck() fails to
                // visit some branch of the expression tree.
                Assignation decl = (Assignation)binding;
                String msg = "*** Internal Saxon error: local variable encountered whose binding has been deleted";
                System.err.println(msg);
                System.err.println("Variable name: " + decl.getVariableName());
                System.err.println("Line number of reference: " + var.getLineNumber() + " in " + var.getSystemId());
                System.err.println("Line number of declaration: " + decl.getLineNumber() + " in " + decl.getSystemId());
                System.err.println("DECLARATION:");
                try {
                    decl.explain(System.err);
                } catch (Exception err) {
                    // ignore the secondary error
                }
                throw new IllegalStateException(msg);
            }

        }
        for (Iterator children = exp.iterateSubExpressions(); children.hasNext();) {
            Expression child = (Expression)children.next();
            nextFree = allocateSlots(child, nextFree, frame);
        }

        return nextFree;

        // Note, we allocate a distinct slot to each range variable, even if the
        // scopes don't overlap. This isn't strictly necessary, but might help
        // debugging.
    }