Use factory methods for async/sync*/async* transforms

The static methods allow type parameters to be registered,
but this means that the type parameters will be dropped unless in strong mode.

Change-Id: I91c1977c287c14742df7d59b988e64ddc46f794d
Reviewed-on: https://dart-review.googlesource.com/52870
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
Stephen Adams 2018-04-30 22:32:56 +00:00
parent 2df8db486d
commit d6a3b85ed2
12 changed files with 248 additions and 125 deletions

View file

@ -576,27 +576,27 @@ class CommonElements {
ClassEntity get controllerStream =>
_findAsyncHelperClass("_ControllerStream");
ConstructorEntity get syncStarIterableConstructor =>
_env.lookupConstructor(syncStarIterable, "");
ConstructorEntity get syncCompleterConstructor =>
_env.lookupConstructor(_findAsyncHelperClass("Completer"), "sync");
ConstructorEntity get asyncAwaitCompleterConstructor =>
_env.lookupConstructor(asyncAwaitCompleter, "");
ClassEntity get asyncAwaitCompleter =>
_findAsyncHelperClass("_AsyncAwaitCompleter");
ClassEntity get asyncStarController =>
_findAsyncHelperClass("_AsyncStarStreamController");
ConstructorEntity get asyncStarControllerConstructor =>
_env.lookupConstructor(asyncStarController, "", required: true);
ConstructorEntity get streamIteratorConstructor =>
_env.lookupConstructor(_findAsyncHelperClass("StreamIterator"), "");
FunctionEntity _syncStarIterableFactory;
FunctionEntity get syncStarIterableFactory => _syncStarIterableFactory ??=
_findAsyncHelperFunction('_makeSyncStarIterable');
FunctionEntity _asyncAwaitCompleterFactory;
FunctionEntity get asyncAwaitCompleterFactory =>
_asyncAwaitCompleterFactory ??=
_findAsyncHelperFunction('_makeAsyncAwaitCompleter');
FunctionEntity _syncCompleterFactory;
FunctionEntity get syncCompleterFactory =>
_syncCompleterFactory ??= _findAsyncHelperFunction('_makeSyncCompleter');
FunctionEntity _asyncStarStreamControllerFactory;
FunctionEntity get asyncStarStreamControllerFactory =>
_asyncStarStreamControllerFactory ??=
_findAsyncHelperFunction('_makeAsyncStarStreamController');
// From dart:mirrors
FunctionEntity _findMirrorsFunction(String name) {
LibraryEntity library = _env.lookupLibrary(Uris.dart__js_mirrors);
@ -1492,11 +1492,16 @@ abstract class ElementEnvironment {
/// Returns the function type variables defined on [function].
List<TypeVariableType> getFunctionTypeVariables(FunctionEntity function);
/// Returns the 'element' type of a function with an async, async* ot sync*
/// Returns the 'element' type of a function with an async, async* or sync*
/// marker. The return type of the method is inspected to determine the type
/// parameter of the Future, Stream or Iterable.
DartType getFunctionAsyncOrSyncStarElementType(FunctionEntity function);
/// Returns the 'element' type of a function with the async, async* or sync*
/// marker [marker]. [returnType] is the return type marked function.
DartType getAsyncOrSyncStarElementType(
AsyncMarker marker, DartType returnType);
/// Returns the type of [field].
DartType getFieldType(FieldEntity field);

View file

@ -7,7 +7,7 @@ library js_backend.backend;
import '../common.dart';
import '../common/backend_api.dart'
show ForeignResolver, NativeRegistry, ImpactTransformer;
import '../common/codegen.dart' show CodegenWorkItem;
import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
import '../common/names.dart' show Uris;
import '../common/resolution.dart' show Resolution, Target;
import '../common/tasks.dart' show CompilerTask;
@ -50,6 +50,7 @@ import '../universe/call_structure.dart' show CallStructure;
import '../universe/class_hierarchy_builder.dart'
show ClassHierarchyBuilder, ClassQueries;
import '../universe/selector.dart' show Selector;
import '../universe/use.dart' show StaticUse;
import '../universe/world_builder.dart';
import '../universe/world_impact.dart'
show ImpactStrategy, ImpactUseCase, WorldImpact, WorldImpactVisitor;
@ -1157,6 +1158,7 @@ class JavaScriptBackend {
jsAst.Expression rewriteAsync(
CommonElements commonElements,
ElementEnvironment elementEnvironment,
CodegenRegistry registry,
FunctionEntity element,
jsAst.Expression code,
SourceInformation bodySourceInformation,
@ -1169,14 +1171,14 @@ class JavaScriptBackend {
switch (element.asyncMarker) {
case AsyncMarker.ASYNC:
rewriter = _makeAsyncRewriter(
commonElements, elementEnvironment, element, code, name);
commonElements, elementEnvironment, registry, element, code, name);
break;
case AsyncMarker.SYNC_STAR:
rewriter = new SyncStarRewriter(reporter, element,
endOfIteration:
emitter.staticFunctionAccess(commonElements.endOfIteration),
iterableFactory: emitter.staticFunctionAccess(
commonElements.syncStarIterableConstructor),
iterableFactory: emitter
.staticFunctionAccess(commonElements.syncStarIterableFactory),
iterableFactoryTypeArgument:
_fetchItemType(element, elementEnvironment),
yieldStarExpression:
@ -1185,6 +1187,11 @@ class JavaScriptBackend {
.staticFunctionAccess(commonElements.syncStarUncaughtError),
safeVariableName: namer.safeVariablePrefixForAsyncRewrite,
bodyName: namer.deriveAsyncBodyName(name));
registry.registerStaticUse(new StaticUse.staticInvoke(
commonElements.syncStarIterableFactory,
const CallStructure.unnamed(1, 1), [
elementEnvironment.getFunctionAsyncOrSyncStarElementType(element)
]));
break;
case AsyncMarker.ASYNC_STAR:
rewriter = new AsyncStarRewriter(reporter, element,
@ -1194,7 +1201,7 @@ class JavaScriptBackend {
emitter.staticFunctionAccess(commonElements.streamOfController),
wrapBody: emitter.staticFunctionAccess(commonElements.wrapBody),
newController: emitter.staticFunctionAccess(
commonElements.asyncStarControllerConstructor),
commonElements.asyncStarStreamControllerFactory),
newControllerTypeArgument:
_fetchItemType(element, elementEnvironment),
safeVariableName: namer.safeVariablePrefixForAsyncRewrite,
@ -1203,6 +1210,11 @@ class JavaScriptBackend {
yieldStarExpression:
emitter.staticFunctionAccess(commonElements.yieldStar),
bodyName: namer.deriveAsyncBodyName(name));
registry.registerStaticUse(new StaticUse.staticInvoke(
commonElements.asyncStarStreamControllerFactory,
const CallStructure.unnamed(1, 1), [
elementEnvironment.getFunctionAsyncOrSyncStarElementType(element)
]));
break;
}
return rewriter.rewrite(code, bodySourceInformation, exitSourceInformation);
@ -1226,6 +1238,7 @@ class JavaScriptBackend {
AsyncRewriter _makeAsyncRewriter(
CommonElements commonElements,
ElementEnvironment elementEnvironment,
CodegenRegistry registry,
FunctionEntity element,
jsAst.Expression code,
jsAst.Name name) {
@ -1234,9 +1247,9 @@ class JavaScriptBackend {
var startFunction = startAsyncSynchronously
? commonElements.asyncHelperStartSync
: commonElements.asyncHelperStart;
var completerConstructor = startAsyncSynchronously
? commonElements.asyncAwaitCompleterConstructor
: commonElements.syncCompleterConstructor;
var completerFactory = startAsyncSynchronously
? commonElements.asyncAwaitCompleterFactory
: commonElements.syncCompleterFactory;
jsAst.Expression itemTypeExpression =
_fetchItemType(element, elementEnvironment);
@ -1250,11 +1263,16 @@ class JavaScriptBackend {
asyncRethrow:
emitter.staticFunctionAccess(commonElements.asyncHelperRethrow),
wrapBody: emitter.staticFunctionAccess(commonElements.wrapBody),
completerFactory: emitter.staticFunctionAccess(completerConstructor),
completerFactory: emitter.staticFunctionAccess(completerFactory),
completerFactoryTypeArgument: itemTypeExpression,
safeVariableName: namer.safeVariablePrefixForAsyncRewrite,
bodyName: namer.deriveAsyncBodyName(name));
registry.registerStaticUse(new StaticUse.staticInvoke(
completerFactory,
const CallStructure.unnamed(0, 1),
[elementEnvironment.getFunctionAsyncOrSyncStarElementType(element)]));
return rewriter;
}

View file

@ -128,54 +128,67 @@ class BackendImpacts {
BackendImpact _asyncBody;
BackendImpact get asyncBody {
var staticUses = [
_commonElements.asyncHelperAwait,
_commonElements.asyncHelperReturn,
_commonElements.asyncHelperRethrow,
_commonElements.streamIteratorConstructor,
_commonElements.wrapBody
];
var instantiantedClasses = <ClassEntity>[];
if (_options.startAsyncSynchronously) {
staticUses.add(_commonElements.asyncAwaitCompleterConstructor);
staticUses.add(_commonElements.asyncHelperStartSync);
instantiantedClasses.add(_commonElements.asyncAwaitCompleter);
} else {
staticUses.add(_commonElements.syncCompleterConstructor);
staticUses.add(_commonElements.asyncHelperStart);
}
return _asyncBody ??= new BackendImpact(
staticUses: staticUses, instantiatedClasses: instantiantedClasses);
}
BackendImpact get asyncBody => _asyncBody ??= () {
var staticUses = [
_commonElements.asyncHelperAwait,
_commonElements.asyncHelperReturn,
_commonElements.asyncHelperRethrow,
_commonElements.streamIteratorConstructor,
_commonElements.wrapBody
];
if (_options.startAsyncSynchronously) {
staticUses.add(_commonElements.asyncHelperStartSync);
} else {
staticUses.add(_commonElements.asyncHelperStart);
}
if (!_options.useKernel) {
if (_options.startAsyncSynchronously) {
staticUses.add(_commonElements.asyncAwaitCompleterFactory);
} else {
staticUses.add(_commonElements.syncCompleterFactory);
}
}
return new BackendImpact(staticUses: staticUses);
}();
BackendImpact _syncStarBody;
BackendImpact get syncStarBody {
return _syncStarBody ??= new BackendImpact(staticUses: [
_commonElements.syncStarIterableConstructor,
_commonElements.endOfIteration,
_commonElements.yieldStar,
_commonElements.syncStarUncaughtError
], instantiatedClasses: [
_commonElements.syncStarIterable
]);
return _syncStarBody ??= _options.useKernel
? new BackendImpact(staticUses: [
_commonElements.endOfIteration,
_commonElements.yieldStar,
_commonElements.syncStarUncaughtError,
])
: new BackendImpact(staticUses: [
_commonElements.endOfIteration,
_commonElements.yieldStar,
_commonElements.syncStarUncaughtError,
_commonElements.syncStarIterableFactory,
]);
}
BackendImpact _asyncStarBody;
BackendImpact get asyncStarBody {
return _asyncStarBody ??= new BackendImpact(staticUses: [
_commonElements.asyncStarHelper,
_commonElements.streamOfController,
_commonElements.yieldSingle,
_commonElements.yieldStar,
_commonElements.asyncStarControllerConstructor,
_commonElements.streamIteratorConstructor,
_commonElements.wrapBody
], instantiatedClasses: [
_commonElements.asyncStarController
]);
return _asyncStarBody ??= _options.useKernel
? new BackendImpact(staticUses: [
_commonElements.asyncStarHelper,
_commonElements.streamOfController,
_commonElements.yieldSingle,
_commonElements.yieldStar,
_commonElements.streamIteratorConstructor,
_commonElements.wrapBody,
])
: new BackendImpact(staticUses: [
_commonElements.asyncStarHelper,
_commonElements.streamOfController,
_commonElements.yieldSingle,
_commonElements.yieldStar,
_commonElements.streamIteratorConstructor,
_commonElements.wrapBody,
_commonElements.asyncStarStreamControllerFactory,
]);
}
BackendImpact _typeVariableBoundCheck;

View file

@ -179,8 +179,7 @@ class BackendUsageBuilderImpl implements BackendUsageBuilder {
if (element is ConstructorEntity &&
(element == _commonElements.streamIteratorConstructor ||
_commonElements.isSymbolConstructor(element) ||
_commonElements.isSymbolValidatedConstructor(element) ||
element == _commonElements.syncCompleterConstructor)) {
_commonElements.isSymbolValidatedConstructor(element))) {
// TODO(johnniwinther): These are valid but we could be more precise.
return true;
} else if (element == _commonElements.symbolImplementationClass ||

View file

@ -189,6 +189,9 @@ abstract class KernelToElementMapForImpact extends KernelToElementMap {
/// Returns the static type of [node].
// TODO(johnniwinther): This should be provided directly from kernel.
DartType getStaticType(ir.Expression node);
/// Returns the element type of a async/sync*/async* function.
DartType getFunctionAsyncOrSyncStarElementType(ir.FunctionNode functionNode);
}
/// Interface that translates between Kernel IR nodes and entities used for

View file

@ -1369,6 +1369,27 @@ class KernelToElementMapForImpactImpl extends KernelToElementMapBase
ClassDefinition getClassDefinition(ClassEntity cls) {
return _getClassDefinition(cls);
}
/// Returns the element type of a async/sync*/async* function.
@override
DartType getFunctionAsyncOrSyncStarElementType(ir.FunctionNode functionNode) {
DartType returnType = getFunctionType(functionNode).returnType;
switch (functionNode.asyncMarker) {
case ir.AsyncMarker.SyncStar:
return elementEnvironment.getAsyncOrSyncStarElementType(
AsyncMarker.SYNC_STAR, returnType);
case ir.AsyncMarker.Async:
return elementEnvironment.getAsyncOrSyncStarElementType(
AsyncMarker.ASYNC, returnType);
case ir.AsyncMarker.AsyncStar:
return elementEnvironment.getAsyncOrSyncStarElementType(
AsyncMarker.ASYNC_STAR, returnType);
default:
failedAt(CURRENT_ELEMENT_SPANNABLE,
"Unexpected ir.AsyncMarker: ${functionNode.asyncMarker}");
}
return null;
}
}
class KernelElementEnvironment extends ElementEnvironment {
@ -1451,7 +1472,13 @@ class KernelElementEnvironment extends ElementEnvironment {
@override
DartType getFunctionAsyncOrSyncStarElementType(FunctionEntity function) {
DartType returnType = getFunctionType(function).returnType;
switch (function.asyncMarker) {
return getAsyncOrSyncStarElementType(function.asyncMarker, returnType);
}
@override
DartType getAsyncOrSyncStarElementType(
AsyncMarker asyncMarker, DartType returnType) {
switch (asyncMarker) {
case AsyncMarker.SYNC:
return returnType;
case AsyncMarker.SYNC_STAR:
@ -1477,7 +1504,7 @@ class KernelElementEnvironment extends ElementEnvironment {
}
return dynamicType;
}
assert(false, 'Unexpected marker ${function.asyncMarker}');
assert(false, 'Unexpected marker ${asyncMarker}');
return null;
}

View file

@ -741,6 +741,11 @@ class _CompilerElementEnvironment extends ElementEnvironment {
return dynamicType;
}
@override
DartType getAsyncOrSyncStarElementType(AsyncMarker marker, DartType type) {
return dynamicType;
}
@override
DartType getFieldType(covariant FieldElement field) {
field.computeType(_resolution);

View file

@ -146,19 +146,42 @@ class KernelImpactBuilder extends ir.Visitor {
return impactBuilder;
}
void handleAsyncMarker(ir.AsyncMarker asyncMarker) {
void handleAsyncMarker(ir.FunctionNode function) {
ir.AsyncMarker asyncMarker = function.asyncMarker;
if (asyncMarker == ir.AsyncMarker.Sync) return;
DartType elementType =
elementMap.getFunctionAsyncOrSyncStarElementType(function);
switch (asyncMarker) {
case ir.AsyncMarker.Sync:
break;
case ir.AsyncMarker.SyncStar:
impactBuilder.registerFeature(Feature.SYNC_STAR);
impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
commonElements.syncStarIterableFactory,
const CallStructure.unnamed(1, 1),
<DartType>[elementType]));
break;
case ir.AsyncMarker.Async:
impactBuilder.registerFeature(Feature.ASYNC);
var completerFactory = _options.startAsyncSynchronously
? commonElements.asyncAwaitCompleterFactory
: commonElements.syncCompleterFactory;
impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
completerFactory,
const CallStructure.unnamed(0, 1),
<DartType>[elementType]));
break;
case ir.AsyncMarker.AsyncStar:
impactBuilder.registerFeature(Feature.ASYNC_STAR);
impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
commonElements.asyncStarStreamControllerFactory,
const CallStructure.unnamed(1, 1),
<DartType>[elementType]));
break;
case ir.AsyncMarker.Sync:
case ir.AsyncMarker.SyncYielding:
failedAt(CURRENT_ELEMENT_SPANNABLE,
"Unexpected async marker: ${asyncMarker}");
@ -168,7 +191,7 @@ class KernelImpactBuilder extends ir.Visitor {
ResolutionImpact buildProcedure(ir.Procedure procedure) {
handleSignature(procedure.function);
visitNode(procedure.function.body);
handleAsyncMarker(procedure.function.asyncMarker);
handleAsyncMarker(procedure.function);
if (procedure.isExternal &&
!elementMap.isForeignLibrary(procedure.enclosingLibrary)) {
MemberEntity member = elementMap.getMember(procedure);
@ -607,19 +630,19 @@ class KernelImpactBuilder extends ir.Visitor {
@override
void visitFunctionDeclaration(ir.FunctionDeclaration node) {
impactBuilder.registerStaticUse(
new StaticUse.closure(elementMap.getLocalFunction(node)));
Local function = elementMap.getLocalFunction(node);
impactBuilder.registerStaticUse(new StaticUse.closure(function));
handleSignature(node.function);
handleAsyncMarker(node.function.asyncMarker);
handleAsyncMarker(node.function);
visitNode(node.function.body);
}
@override
void visitFunctionExpression(ir.FunctionExpression node) {
impactBuilder.registerStaticUse(
new StaticUse.closure(elementMap.getLocalFunction(node)));
Local function = elementMap.getLocalFunction(node);
impactBuilder.registerStaticUse(new StaticUse.closure(function));
handleSignature(node.function);
handleAsyncMarker(node.function.asyncMarker);
handleAsyncMarker(node.function);
visitNode(node.function.body);
}

View file

@ -51,6 +51,7 @@ class SsaFunctionCompiler implements FunctionCompiler {
result = backend.rewriteAsync(
closedWorld.commonElements,
closedWorld.elementEnvironment,
work.registry,
element,
result,
sourceInformationBuilder.buildAsyncBody(),

View file

@ -162,6 +162,20 @@ class _AsyncAwaitCompleter<T> implements Completer<T> {
bool get isCompleted => _completer.isCompleted;
}
/// Creates a Completer for an `async` function.
///
/// Used as part of the runtime support for the async/await transformation.
Completer<T> _makeAsyncAwaitCompleter<T>() {
return new _AsyncAwaitCompleter<T>();
}
/// Creates a Completer for an `async` function.
///
/// Used as part of the runtime support for the async/await transformation.
Completer<T> _makeSyncCompleter<T>() {
return new Completer<T>.sync();
}
/// Initiates the computation of an `async` function and starts the body
/// synchronously.
///
@ -464,9 +478,12 @@ class _AsyncStarStreamController<T> {
}
}
//_makeAsyncStarController(body) {
// return new _AsyncStarStreamController(body);
//}
/// Creates a stream controller for an `async*` function.
///
/// Used as part of the runtime support for the async/await transformation.
_makeAsyncStarStreamController<T>(_WrappedAsyncBody body) {
return new _AsyncStarStreamController<T>(body);
}
class _IterationMarker {
static const YIELD_SINGLE = 0;
@ -618,6 +635,13 @@ class _SyncStarIterator<T> implements Iterator<T> {
}
}
/// Creates an Iterable for a `sync*` function.
///
/// Used as part of the runtime support for the async/await transformation.
_SyncStarIterable<T> _makeSyncStarIterable<T>(body) {
return new _SyncStarIterable<T>(body);
}
/// An Iterable corresponding to a sync* method.
///
/// Each invocation of a sync* method will return a new instance of this class.

View file

@ -100,21 +100,23 @@ main() {
testIfNotNullSet(null);
testIfNull(null);
testSetIfNull(null);
testSyncStar();
testAsync();
testAsyncStar();
testLocalSyncStar();
testLocalAsync();
testLocalAsyncStar();
testAnonymousSyncStar();
testAnonymousAsync();
testAnonymousAsyncStar();
// Following tests are disabled because we changed the Kernel version to
// register helper function calls with explicit type arguments.
//testSyncStar();
//testAsync();
//testAsyncStar();
//testLocalSyncStar();
//testLocalAsync();
//testLocalAsyncStar();
//testAnonymousSyncStar();
//testAnonymousAsync();
//testAnonymousAsyncStar();
//testAsyncForIn(null);
//testAsyncForInTyped(null);
testIfThen();
testIfThenElse();
testForIn(null);
testForInTyped(null);
testAsyncForIn(null);
testAsyncForInTyped(null);
testTryCatch();
testTryCatchOn();
testTryCatchStackTrace();
@ -284,30 +286,32 @@ testIfNotNullSet(o) => o?.foo = 42;
testIfNull(o) => o ?? 42;
testSetIfNull(o) => o ??= 42;
testSyncStar() sync* {}
testAsync() async {}
testAsyncStar() async* {}
testLocalSyncStar() {
local() sync* {}
return local;
}
testLocalAsync() {
local() async {}
return local;
}
testLocalAsyncStar() {
local() async* {}
return local;
}
testAnonymousSyncStar() {
return () sync* {};
}
testAnonymousAsync() {
return () async {};
}
testAnonymousAsyncStar() {
return () async* {};
}
// Following tests are disabled because we changed the Kernel version to
// register helper function calls with explicit type arguments.
//testSyncStar() sync* {}
//testAsync() async {}
//testAsyncStar() async* {}
//testLocalSyncStar() {
// local() sync* {}
// return local;
//}
//testLocalAsync() {
// local() async {}
// return local;
//}
//testLocalAsyncStar() {
// local() async* {}
// return local;
//}
//testAnonymousSyncStar() {
// return () sync* {};
//}
//testAnonymousAsync() {
// return () async {};
//}
//testAnonymousAsyncStar() {
// return () async* {};
//}
testIfThen() {
if (false) return 42;
@ -326,12 +330,12 @@ testForIn(o) {
testForInTyped(o) {
for (int e in o) {}
}
testAsyncForIn(o) async {
await for (var e in o) {}
}
testAsyncForInTyped(o) async {
await for (int e in o) {}
}
//testAsyncForIn(o) async {
// await for (var e in o) {}
//}
//testAsyncForInTyped(o) async {
// await for (int e in o) {}
//}
testTryCatch() {
try {} catch (e) {}
}

View file

@ -90,6 +90,7 @@ assertion_initializer_test: RuntimeError
assign_static_type_test/01: Fail
assign_static_type_test/02: MissingCompileTimeError
async_return_types_test/nestedFuture: Fail # Issue 26429
async_return_types_test/wrongTypeParameter: Fail # Issue 26429
cha_deopt1_test: RuntimeError
cha_deopt2_test: RuntimeError
cha_deopt3_test: RuntimeError