dart2js: Set inferred return types for async, async*, and sync* methods.

Previously these were assumed to return dynamic. Now the return type is
the concrete class being returned:
  async -> _Future
  async* -> _ControllerStream
  sync* -> _SyncStarIterable

R=johnniwinther@google.com

Review URL: https://codereview.chromium.org/1418043005 .
This commit is contained in:
Asger Feldthaus 2015-11-03 15:02:46 +01:00
parent 7ea2b300f1
commit dff4cc11d7
7 changed files with 107 additions and 16 deletions

View file

@ -250,6 +250,12 @@ abstract class Backend {
ClassElement get uint32Implementation => compiler.coreClasses.intClass;
ClassElement get uint31Implementation => compiler.coreClasses.intClass;
ClassElement get positiveIntImplementation => compiler.coreClasses.intClass;
ClassElement get syncStarIterableImplementation =>
compiler.coreClasses.iterableClass;
ClassElement get asyncFutureImplementation =>
compiler.coreClasses.futureClass;
ClassElement get asyncStarStreamImplementation =>
compiler.coreClasses.streamClass;
ClassElement defaultSuperclass(ClassElement element) {
return compiler.coreClasses.objectClass;

View file

@ -55,6 +55,9 @@ abstract class TypeSystem<T> {
T get constMapType;
T get stringType;
T get typeType;
T get syncStarIterableType;
T get asyncFutureType; // Subtype of Future returned by async methods.
T get asyncStarStreamType;
T stringLiteralType(DartString value);
T boolLiteralType(LiteralBool value);

View file

@ -120,6 +120,9 @@ class TypeMaskSystem implements TypeSystem<TypeMask> {
TypeMask get constMapType => compiler.typesTask.constMapType;
TypeMask get stringType => compiler.typesTask.stringType;
TypeMask get typeType => compiler.typesTask.typeType;
TypeMask get syncStarIterableType => compiler.typesTask.syncStarIterableType;
TypeMask get asyncFutureType => compiler.typesTask.asyncFutureType;
TypeMask get asyncStarStreamType => compiler.typesTask.asyncStarStreamType;
bool isNull(TypeMask mask) => mask.isEmpty && mask.isNullable;
TypeMask stringLiteralType(ast.DartString value) => stringType;
@ -650,21 +653,37 @@ class SimpleTypeInferrerVisitor<T>
locals.update(element, inferrer.typeOfElement(element), node);
});
visit(node.body);
if (function.asyncMarker != AsyncMarker.SYNC) {
// TODO(herhut): Should be type Future/Iterable/Stream instead of
// dynamic.
returnType = inferrer.addReturnTypeFor(
analyzedElement, returnType, types.dynamicType);
} else if (returnType == null) {
// No return in the body.
returnType = locals.seenReturnOrThrow
? types.nonNullEmpty() // Body always throws.
: types.nullType;
} else if (!locals.seenReturnOrThrow) {
// We haven't seen returns on all branches. So the method may
// also return null.
returnType = inferrer.addReturnTypeFor(
analyzedElement, returnType, types.nullType);
switch (function.asyncMarker) {
case AsyncMarker.SYNC:
if (returnType == null) {
// No return in the body.
returnType = locals.seenReturnOrThrow
? types.nonNullEmpty() // Body always throws.
: types.nullType;
} else if (!locals.seenReturnOrThrow) {
// We haven't seen returns on all branches. So the method may
// also return null.
returnType = inferrer.addReturnTypeFor(
analyzedElement, returnType, types.nullType);
}
break;
case AsyncMarker.SYNC_STAR:
// TODO(asgerf): Maybe make a ContainerTypeMask for these? The type
// contained is the method body's return type.
returnType = inferrer.addReturnTypeFor(
analyzedElement, returnType, types.syncStarIterableType);
break;
case AsyncMarker.ASYNC:
returnType = inferrer.addReturnTypeFor(
analyzedElement, returnType, types.asyncFutureType);
break;
case AsyncMarker.ASYNC_STAR:
returnType = inferrer.addReturnTypeFor(
analyzedElement, returnType, types.asyncStarStreamType);
break;
}
}

View file

@ -233,6 +233,27 @@ class TypeInformationSystem extends TypeSystem<TypeInformation> {
getConcreteTypeFor(compiler.typesTask.dynamicType);
}
TypeInformation asyncFutureTypeCache;
TypeInformation get asyncFutureType {
if (asyncFutureTypeCache != null) return asyncFutureTypeCache;
return asyncFutureTypeCache =
getConcreteTypeFor(compiler.typesTask.asyncFutureType);
}
TypeInformation syncStarIterableTypeCache;
TypeInformation get syncStarIterableType {
if (syncStarIterableTypeCache != null) return syncStarIterableTypeCache;
return syncStarIterableTypeCache =
getConcreteTypeFor(compiler.typesTask.syncStarIterableType);
}
TypeInformation asyncStarStreamTypeCache;
TypeInformation get asyncStarStreamType {
if (asyncStarStreamTypeCache != null) return asyncStarStreamTypeCache;
return asyncStarStreamTypeCache =
getConcreteTypeFor(compiler.typesTask.asyncStarStreamType);
}
TypeInformation nonNullEmptyType;
TypeInformation stringLiteralType(ast.DartString value) {

View file

@ -1887,6 +1887,9 @@ class JavaScriptBackend extends Backend {
ClassElement get typeImplementation => helpers.typeLiteralClass;
ClassElement get boolImplementation => helpers.jsBoolClass;
ClassElement get nullImplementation => helpers.jsNullClass;
ClassElement get syncStarIterableImplementation => helpers.syncStarIterable;
ClassElement get asyncFutureImplementation => helpers.futureImplementation;
ClassElement get asyncStarStreamImplementation => helpers.controllerStream;
void registerStaticUse(Element element, Enqueuer enqueuer) {
if (element == helpers.disableTreeShakingMarker) {

View file

@ -586,6 +586,18 @@ class BackendHelpers {
return classElement;
}
Element get futureImplementation {
ClassElement classElement = findAsyncHelper('_Future');
classElement.ensureResolved(resolution);
return classElement;
}
Element get controllerStream {
ClassElement classElement = findAsyncHelper("_ControllerStream");
classElement.ensureResolved(resolution);
return classElement;
}
Element get syncStarIterableConstructor {
ClassElement classElement = syncStarIterable;
classElement.ensureResolved(resolution);
@ -667,4 +679,4 @@ class BackendHelpers {
Element get convertRtiToRuntimeType {
return findHelper('convertRtiToRuntimeType');
}
}
}

View file

@ -87,6 +87,9 @@ class TypesTask extends CompilerTask {
TypeMask constMapTypeCache;
TypeMask stringTypeCache;
TypeMask typeTypeCache;
TypeMask syncStarIterableTypeCache;
TypeMask asyncFutureTypeCache;
TypeMask asyncStarStreamTypeCache;
TypeMask get dynamicType {
if (dynamicTypeCache == null) {
@ -232,6 +235,30 @@ class TypesTask extends CompilerTask {
return typeTypeCache;
}
TypeMask get syncStarIterableType {
if (syncStarIterableTypeCache == null) {
syncStarIterableTypeCache = new TypeMask.nonNullExact(
compiler.backend.syncStarIterableImplementation, compiler.world);
}
return syncStarIterableTypeCache;
}
TypeMask get asyncFutureType {
if (asyncFutureTypeCache == null) {
asyncFutureTypeCache = new TypeMask.nonNullExact(
compiler.backend.asyncFutureImplementation, compiler.world);
}
return asyncFutureTypeCache;
}
TypeMask get asyncStarStreamType {
if (asyncStarStreamTypeCache == null) {
asyncStarStreamTypeCache = new TypeMask.nonNullExact(
compiler.backend.asyncStarStreamImplementation, compiler.world);
}
return asyncStarStreamTypeCache;
}
TypeMask get nullType {
if (nullTypeCache == null) {
// TODO(johnniwinther): Assert that the null type has been resolved.