diff --git a/pkg/dart2wasm/lib/transformers.dart b/pkg/dart2wasm/lib/transformers.dart index fe9d23ef848..41bc19b39e3 100644 --- a/pkg/dart2wasm/lib/transformers.dart +++ b/pkg/dart2wasm/lib/transformers.dart @@ -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 in ) { ... } @@ -126,7 +125,21 @@ class _WasmTransformer extends Transformer { // } // } // } - final CoreTypes coreTypes = typeContext.typeEnvironment.coreTypes; + // + // and: + // + // await for ({var/final} T in ) { ... } + // + // Into + // + // { + // final StreamIterator #forIterator = StreamIterator(); + // 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(this); + return Block([ + iterator, + ForStatement(const [], isAsync ? AwaitExpression(condition) : condition, + const [], body) + ]).accept(this); + } + + @override + TreeNode visitForInStatement(ForInStatement stmt) { + return _lowerForIn(stmt); } }