visitAwaitExpression method

  1. @override
Object? visitAwaitExpression(
  1. AwaitExpression node
)
override

Implementation

@override
Object? visitAwaitExpression(AwaitExpression node) {
  // Check for async state machine: do we have an async state?
  if (currentAsyncState == null) {
    // This shouldn't happen if the call is properly orchestrated
    throw StateD4rtException(
        "Internal error: 'await' encountered outside of a managed async execution state.");
  }

  // Initial check: Are we in an async function?
  if (!currentAsyncState!.function.isAsync) {
    throw RuntimeD4rtException(
        "'await' can only be used inside an async function.");
  }

  // Check if we are in invocation resumption mode
  if (currentAsyncState!.isInvocationResumptionMode) {
    Logger.debug(
        "[AwaitExpression] In invocation resumption mode, returning last await result: ${currentAsyncState!.lastAwaitResult}");
    return currentAsyncState!.lastAwaitResult;
  }

  Logger.debug("[AwaitExpression] Evaluating expression for await...");
  final expressionValue = node.expression.accept<Object?>(this);

  // HANDLING NESTED SUSPENSIONS
  if (expressionValue is AsyncSuspensionRequest) {
    // If the awaited expression itself is an await, just propagate its suspension request.
    Logger.debug(
        "[AwaitExpression] Awaited expression itself suspended. Propagating AsyncSuspensionRequest.");
    return expressionValue;
  }

  // Bug-92: Unwrap BridgedInstance containing a Future
  // When Future is created via bridged constructor, it gets wrapped in BridgedInstance
  // We need to unwrap it to get the actual Future for await
  Object? futureValue = expressionValue;
  if (expressionValue is BridgedInstance &&
      expressionValue.nativeObject is Future) {
    futureValue = expressionValue.nativeObject;
    Logger.debug(
        "[AwaitExpression] Unwrapped BridgedInstance to get native Future.");
  }

  if (futureValue is Future) {
    Logger.debug(
        "[AwaitExpression] Expression evaluated to a Future. Returning AsyncSuspensionRequest.");
    final future = futureValue as Future<Object?>;

    // CRUCIAL: Return the suspension request with the future and the current state.
    // The async state machine will use this information.
    // Note: currentAsyncState cannot be null here because of the previous check.
    return AsyncSuspensionRequest(future, currentAsyncState!);
  } else {
    // The argument to 'await' MUST be a Future.
    throw RuntimeD4rtException(
        "The argument to 'await' must be a Future, but received type: ${expressionValue?.runtimeType}");
  }
}