[dart2wasm] Implement await / for as lowering.

Change-Id: Ic41f016490c993f27c3e5873ad1a4b3e8a902f13
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/255822
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Joshua Litt <joshualitt@google.com>
This commit is contained in:
Joshua Litt 2022-08-22 18:08:31 +00:00 committed by Commit Bot
parent ae57447189
commit 6052fe0ca2

View file

@ -110,8 +110,7 @@ class _WasmTransformer extends Transformer {
return super.visitClass(cls);
}
@override
TreeNode visitForInStatement(ForInStatement stmt) {
TreeNode _lowerForIn(ForInStatement stmt) {
// Transform
//
// for ({var/final} T <variable> in <iterable>) { ... }
@ -126,7 +125,21 @@ class _WasmTransformer extends Transformer {
// }
// }
// }
final CoreTypes coreTypes = typeContext.typeEnvironment.coreTypes;
//
// and:
//
// await for ({var/final} T <variable> in <stream>) { ... }
//
// Into
//
// {
// final StreamIterator<T> #forIterator = StreamIterator(<stream>);
// for (; await #forIterator.moveNext() ;) {
// {var/final} T variable = await #forIterator.current;
// ...
// }
// }
// }
// The CFE might invoke this transformation despite the program having
// compile-time errors. So we will not transform this [stmt] if the
@ -140,36 +153,65 @@ class _WasmTransformer extends Transformer {
InvalidExpression('Invalid iterable type in for-in'));
}
final isAsync = stmt.isAsync;
late final Class iteratorClass;
late final Procedure iteratorMoveNext;
late final Member iteratorCurrent;
if (isAsync) {
iteratorClass = coreTypes.streamIteratorClass;
iteratorMoveNext = coreTypes.streamIteratorMoveNext;
iteratorCurrent = coreTypes.streamIteratorCurrent;
} else {
iteratorClass = coreTypes.iteratorClass;
iteratorMoveNext = coreTypes.iteratorMoveNext;
iteratorCurrent = coreTypes.iteratorGetCurrent;
}
final DartType elementType = stmt.getElementType(typeContext);
final iteratorType = InterfaceType(
coreTypes.iteratorClass, Nullability.nonNullable, [elementType]);
final iteratorType =
InterfaceType(iteratorClass, Nullability.nonNullable, [elementType]);
late final Expression iteratorInitializer;
if (isAsync) {
iteratorInitializer = ConstructorInvocation(
coreTypes.streamIteratorDefaultConstructor,
Arguments([iterable], types: [elementType]));
} else {
iteratorInitializer = InstanceGet(
InstanceAccessKind.Instance, iterable, Name('iterator'),
interfaceTarget: coreTypes.iterableGetIterator,
resultType: iteratorType);
}
final iterator = VariableDeclaration("#forIterator",
initializer: InstanceGet(
InstanceAccessKind.Instance, iterable, Name('iterator'),
interfaceTarget: coreTypes.iterableGetIterator,
resultType: iteratorType)
..fileOffset = iterable.fileOffset,
initializer: iteratorInitializer..fileOffset = iterable.fileOffset,
type: iteratorType)
..fileOffset = iterable.fileOffset;
final condition = InstanceInvocation(InstanceAccessKind.Instance,
VariableGet(iterator), Name('moveNext'), Arguments(const []),
interfaceTarget: coreTypes.iteratorMoveNext,
functionType: coreTypes.iteratorMoveNext.getterType as FunctionType)
interfaceTarget: iteratorMoveNext,
functionType: iteratorMoveNext.getterType as FunctionType)
..fileOffset = iterable.fileOffset;
final variable = stmt.variable
..initializer = (InstanceGet(
InstanceAccessKind.Instance, VariableGet(iterator), Name('current'),
interfaceTarget: coreTypes.iteratorGetCurrent,
resultType: elementType)
interfaceTarget: iteratorCurrent, resultType: elementType)
..fileOffset = stmt.bodyOffset);
final Block body = Block([variable, stmt.body])
..fileOffset = stmt.fileOffset;
return Block([iterator, ForStatement(const [], condition, const [], body)])
.accept<TreeNode>(this);
return Block([
iterator,
ForStatement(const [], isAsync ? AwaitExpression(condition) : condition,
const [], body)
]).accept<TreeNode>(this);
}
@override
TreeNode visitForInStatement(ForInStatement stmt) {
return _lowerForIn(stmt);
}
}