visitAwaitExpression method
Object?
visitAwaitExpression(
- 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}");
}
}