Skip to content

An inherited method on a class defined inside a function is never dispatched #945

Description

@khatchad

Summary

An inherited method on a class defined inside a function is never dispatched: the class's superclass resolves, but a call of the inherited method on an instance of the nested class reaches no call-graph node for it, and a parameter of that method reads as absent.

Measured on master c94b03d0a and again with the module-order barrier from #944 applied, with the same result, so this is not the order defect.

The Fixture

One module, so no import and no module order is involved:

import tensorflow as tf


class Base:
    def scale(self, x):
        return x * 2.0


def scale_inside(x):
    class Inner(Base):
        pass

    return Inner().scale(x)


b = scale_inside(tf.ones((4,)))
assert b.shape == (4,)

The harness pin on Base.scale (one tensor parameter, x of (4,) float32) fails with Function must exist in call graph: Base.scale has no node at all, so the call inside scale_inside never dispatched to it.

What Is Not The Cause

  • The class hierarchy is right. In a three-module variant of the same shape (the base imported from another module, subclasses at top level, inside a function and inside a class), the function-nested class's superclass resolves to the base in both module orders once the order barrier is in place, so the entity walk does register a class defined inside a function and its base link is not the gap.
  • Module order is not involved. The single-module fixture above fails identically with and without the barrier, and the top-level and class-nested siblings in the three-module variant dispatch their inherited method and deliver their parameter shapes, (2, 3) and (5, 6, 7), while the function-nested sibling's (4,) is absent.

So the miss is in how the inherited member reaches the nested class's instances: the class-object emission for a class defined in a function body, or the read of the base's class object from that scope, does not carry the inherited method the way a top-level or class-nested definition does.

Expected

Base.scale has a node, and its x parameter reads (4,) float32.

Test

TestCrossModuleBaseOrder.testFunctionNestedSubclassSameModule carries the fixture as an expected failure with a TODO naming this issue, beside the three-module variant whose function-nested arm documents the same absence.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions