call method
Object?
call(
- InterpreterVisitor visitor,
- List<
Object?> positionalArguments, [ - Map<
String, Object?> namedArguments = const {}, - List<
RuntimeType> ? typeArguments,
override
Implementation
@override
Object? call(
InterpreterVisitor visitor,
List<Object?> positionalArguments, [
Map<String, Object?> namedArguments = const {},
List<RuntimeType>? typeArguments,
]) {
// Establish `D4.activeVisitor` for the duration of every interpreted
// function call. This makes the visitor available to any native code
// path that the user function triggers — most importantly the
// `InterpretedInstance.==` / `.hashCode` overrides, which dispatch
// through the active visitor when native Dart collections
// (`Map<UserCell, …>`, `Set<UserCell>`, …) look up keys. Without this
// wrap, native container operations downstream of a `targetValue[key]`
// (visitIndexExpression) read `D4.activeVisitor == null` and silently
// fall back to identity hashing, breaking content-equality lookups.
//
// Hot path: push/pop the active visitor directly rather than via
// `withActiveVisitor`, whose `T Function()` argument allocates a closure on
// every interpreted function call. The save/set/restore semantics are
// identical (nesting included).
final previousActiveVisitor = D4.pushActiveVisitor(visitor);
// The interpreted call stack (D4rtCallStack): an error leaving this call
// is snapshotted against the stack as it stood when it was raised.
final callStack = visitor.callStack;
callStack.enter(_name ?? '<anonymous>');
// Until the body's first statement runs, the frame is at the body — which
// is all an expression-bodied function ever has.
callStack.current = _body;
try {
return _callImpl(
visitor,
positionalArguments,
namedArguments,
typeArguments,
);
} catch (error) {
callStack.recordEscape(error);
rethrow;
} finally {
callStack.exit();
D4.popActiveVisitor(previousActiveVisitor);
}
}