tryCreateInterfaceProxyWithVisitor<T> static method

T? tryCreateInterfaceProxyWithVisitor<T>(
  1. InterpretedInstance instance,
  2. InterpreterVisitor visitor
)

Try to create an interface proxy with a visitor context.

This is the full version that can actually create proxies. Called from contexts where the visitor is available.

Implementation

static T? tryCreateInterfaceProxyWithVisitor<T>(
  InterpretedInstance instance,
  InterpreterVisitor visitor,
) {
  // Walk hierarchy starting from `instance.klass` and recursively traverse
  // the interpreted superclass chain plus all interpreted mixins and
  // interpreted interfaces. At every level collect:
  //   - the bridgedSuperclass name (direct)
  //   - bridgedInterfaces / bridgedMixins names
  //   - transitively registered supertypes of each (Bug-102b)
  // Then try each candidate against the interface-proxy registry.
  //
  // Prior to Bug-102c, only the outermost klass's bridgedSuperclass
  // was considered — so a script like
  //   abstract class _BaseDelegate extends MultiChildLayoutDelegate { ... }
  //   class _DashboardDelegate extends _BaseDelegate { ... }
  // failed to resolve because _DashboardDelegate.bridgedSuperclass is
  // null (its bridged super is one interpreted hop away).
  //
  // Cluster-18 (bucket #8) extends this further: scripts may use an
  // interpreted mixin to satisfy a bridged interface, e.g.
  //   mixin _TickerProviderShim<T extends StatefulWidget> on State<T>
  //       implements TickerProvider { ... }
  //   class _DemoState extends State<...> with _TickerProviderShim
  // Without recursing into `walk.mixins` and `walk.interfaces`, the
  // bridged contributions of the interpreted mixin (here TickerProvider)
  // are invisible to proxy resolution.
  final seen = <String>{};
  final candidates = <String>[];
  void add(String n) {
    if (seen.add(n)) candidates.add(n);
  }
  void addBridged(BridgedClass bc) {
    add(bc.name);
    for (final s in BridgedClass.transitiveSupertypeNames(bc.name)) {
      add(s);
    }
  }

  final visitedClasses = <InterpretedClass>{};
  void collectFromInterpreted(InterpretedClass? c) {
    if (c == null) return;
    if (!visitedClasses.add(c)) return;
    if (c.bridgedSuperclass != null) {
      addBridged(c.bridgedSuperclass!);
    }
    for (final iface in c.bridgedInterfaces) {
      addBridged(iface);
    }
    for (final mixin in c.bridgedMixins) {
      addBridged(mixin);
    }
    // Recurse into interpreted ancestors so an interpreted mixin's or
    // interface's bridged contributions are also discovered.
    collectFromInterpreted(c.superclass);
    for (final m in c.mixins) {
      collectFromInterpreted(m);
    }
    for (final i in c.interfaces) {
      collectFromInterpreted(i);
    }
  }

  collectFromInterpreted(instance.klass);

  for (final name in candidates) {
    final factory = _interfaceProxies[name];
    if (factory != null) {
      final proxy = factory(visitor, instance);
      if (proxy is T) return proxy;
    }
  }

  return null;
}