Skip to content

Commit

Permalink
Redo "Pass type argument into rewritten marked function"
Browse files Browse the repository at this point in the history
TBR=sigmund@google.com

Change-Id: I0999ab52f76da185c601ce7105e4a8491c5e4edf
Reviewed-on: https://dart-review.googlesource.com/52262
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
  • Loading branch information
rakudrama authored and commit-bot@chromium.org committed Apr 21, 2018
1 parent ebcd876 commit 81d779c
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 85 deletions.
5 changes: 5 additions & 0 deletions pkg/compiler/lib/src/common_elements.dart
Expand Up @@ -1426,6 +1426,11 @@ 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*
/// 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 type of [field].
DartType getFieldType(FieldEntity field);

Expand Down
6 changes: 6 additions & 0 deletions pkg/compiler/lib/src/elements/resolution_types.dart
Expand Up @@ -162,6 +162,12 @@ abstract class ResolutionDartType implements DartType {
/// Is [: true :] if this type contains any type variables.
bool get containsTypeVariables => typeVariableOccurrence != null;

bool get containsFreeTypeVariables {
assert(!containsMethodTypeVariableType,
'Used only after removing method type variables');
return containsTypeVariables;
}

/// Returns a textual representation of this type as if it was the type
/// of a member named [name].
String getStringAsDeclared(String name) {
Expand Down
52 changes: 52 additions & 0 deletions pkg/compiler/lib/src/elements/types.dart
Expand Up @@ -74,6 +74,12 @@ abstract class DartType {
/// Whether this type contains a type variable.
bool get containsTypeVariables => false;

/// Whether this type contains a free class type variable or function type
/// variable.
// TODO(sra): Review uses of [containsTypeVariables] for update with
// [containsFreeTypeVariables].
bool get containsFreeTypeVariables => _containsFreeTypeVariables(null);

/// Is `true` if this type is the 'Object' type defined in 'dart:core'.
bool get isObject => false;

Expand All @@ -96,6 +102,8 @@ abstract class DartType {
R accept<R, A>(DartTypeVisitor<R, A> visitor, A argument);

bool _equals(DartType other, _Assumptions assumptions);

bool _containsFreeTypeVariables(List<FunctionTypeVariable> bindings) => false;
}

/// Pairs of [FunctionTypeVariable]s that are currently assumed to be equivalent.
Expand Down Expand Up @@ -173,6 +181,11 @@ class InterfaceType extends DartType {
typeArguments.forEach((type) => type.forEachTypeVariable(f));
}

bool _containsFreeTypeVariables(List<FunctionTypeVariable> bindings) {
return typeArguments
.any((type) => type._containsFreeTypeVariables(bindings));
}

InterfaceType subst(List<DartType> arguments, List<DartType> parameters) {
if (typeArguments.isEmpty) {
// Return fast on non-generic types.
Expand Down Expand Up @@ -263,6 +276,9 @@ class TypedefType extends DartType {
typeArguments.forEach((type) => type.forEachTypeVariable(f));
}

bool _containsFreeTypeVariables(List<FunctionTypeVariable> bindings) =>
typeArguments.any((type) => type._containsFreeTypeVariables(bindings));

TypedefType subst(List<DartType> arguments, List<DartType> parameters) {
if (typeArguments.isEmpty) {
// Return fast on non-generic types.
Expand Down Expand Up @@ -350,6 +366,8 @@ class Dart1MethodTypeVariableType extends TypeVariableType {

@override
bool get isMalformed => true;

bool _containsFreeTypeVariables(List<FunctionTypeVariable> bindings) => false;
}

class TypeVariableType extends DartType {
Expand All @@ -365,6 +383,8 @@ class TypeVariableType extends DartType {
f(this);
}

bool _containsFreeTypeVariables(List<FunctionTypeVariable> bindings) => true;

DartType subst(List<DartType> arguments, List<DartType> parameters) {
assert(arguments.length == parameters.length);
if (parameters.isEmpty) {
Expand Down Expand Up @@ -433,6 +453,12 @@ class FunctionTypeVariable extends DartType {
@override
bool get isFunctionTypeVariable => true;

bool _containsFreeTypeVariables(List<FunctionTypeVariable> bindings) {
if (bindings == null) return true;
if (bindings.indexOf(this) >= 0) return false;
return true;
}

DartType subst(List<DartType> arguments, List<DartType> parameters) {
assert(arguments.length == parameters.length);
if (parameters.isEmpty) {
Expand Down Expand Up @@ -564,6 +590,29 @@ class FunctionType extends DartType {
namedParameterTypes.forEach((type) => type.forEachTypeVariable(f));
}

bool _containsFreeTypeVariables(List<FunctionTypeVariable> bindings) {
int restore;
if (typeVariables.isNotEmpty) {
if (bindings == null) {
bindings = <FunctionTypeVariable>[];
} else {
restore = bindings.length;
}
bindings.addAll(typeVariables);
}

bool hasFree(DartType type) => type._containsFreeTypeVariables(bindings);

bool result = hasFree(returnType) ||
typeVariables.any((type) => hasFree(type.bound)) ||
parameterTypes.any(hasFree) ||
optionalParameterTypes.any(hasFree) ||
namedParameterTypes.any(hasFree);

if (restore != null) bindings.length = restore;
return result;
}

bool get isFunctionType => true;

DartType subst(List<DartType> arguments, List<DartType> parameters) {
Expand Down Expand Up @@ -778,6 +827,9 @@ class FutureOrType extends DartType {
typeArgument.forEachTypeVariable(f);
}

bool _containsFreeTypeVariables(List<FunctionTypeVariable> bindings) =>
typeArgument._containsFreeTypeVariables(bindings);

R accept<R, A>(DartTypeVisitor<R, A> visitor, A argument) =>
visitor.visitFutureOrType(this, argument);

Expand Down
22 changes: 17 additions & 5 deletions pkg/compiler/lib/src/js/rewrite_async.dart
Expand Up @@ -1739,6 +1739,7 @@ class AsyncRewriter extends AsyncRewriterBase {
///
/// Specific to async methods.
final js.Expression completerFactory;
final js.Expression completerFactoryTypeArgument;

final js.Expression wrapBody;

Expand All @@ -1748,6 +1749,7 @@ class AsyncRewriter extends AsyncRewriterBase {
this.asyncReturn,
this.asyncRethrow,
this.completerFactory,
this.completerFactoryTypeArgument,
this.wrapBody,
String safeVariableName(String proposedName),
js.Name bodyName})
Expand Down Expand Up @@ -1799,8 +1801,10 @@ class AsyncRewriter extends AsyncRewriterBase {
List<js.VariableInitialization> variables = <js.VariableInitialization>[];
variables.add(_makeVariableInitializer(
completer,
new js.Call(completerFactory, [])
.withSourceInformation(sourceInformation),
js.js('#(#)', [
completerFactory,
completerFactoryTypeArgument
]).withSourceInformation(sourceInformation),
sourceInformation));
if (analysis.hasExplicitReturns) {
variables
Expand Down Expand Up @@ -1900,6 +1904,7 @@ class SyncStarRewriter extends AsyncRewriterBase {
/// Constructor creating the Iterable for a sync* method. Called with
/// [bodyName].
final js.Expression iterableFactory;
final js.Expression iterableFactoryTypeArgument;

/// A JS Expression that creates a marker showing that iteration is over.
///
Expand All @@ -1917,6 +1922,7 @@ class SyncStarRewriter extends AsyncRewriterBase {
SyncStarRewriter(DiagnosticReporter diagnosticListener, spannable,
{this.endOfIteration,
this.iterableFactory,
this.iterableFactoryTypeArgument,
this.yieldStarExpression,
this.uncaughtErrorExpression,
String safeVariableName(String proposedName),
Expand Down Expand Up @@ -2009,8 +2015,9 @@ class SyncStarRewriter extends AsyncRewriterBase {
"returnInnerInnerFunction": returnInnerInnerFunction,
}).withSourceInformation(functionSourceInformation);
js.Expression callIterableFactory =
js.js("#iterableFactory(#innerFunction)", {
js.js("#iterableFactory(#innerFunction, #type)", {
"iterableFactory": iterableFactory,
"type": iterableFactoryTypeArgument,
"innerFunction": innerFunction,
}).withSourceInformation(bodySourceInformation);
js.Statement returnCallIterableFactory = new js.Return(callIterableFactory)
Expand Down Expand Up @@ -2108,6 +2115,7 @@ class AsyncStarRewriter extends AsyncRewriterBase {
///
/// Specific to async* methods.
final js.Expression newController;
final js.Expression newControllerTypeArgument;

/// Used to get the `Stream` out of the [controllerName] variable.
final js.Expression streamOfController;
Expand All @@ -2128,6 +2136,7 @@ class AsyncStarRewriter extends AsyncRewriterBase {
{this.asyncStarHelper,
this.streamOfController,
this.newController,
this.newControllerTypeArgument,
this.yieldExpression,
this.yieldStarExpression,
this.wrapBody,
Expand Down Expand Up @@ -2317,8 +2326,11 @@ class AsyncStarRewriter extends AsyncRewriterBase {
List<js.VariableInitialization> variables = <js.VariableInitialization>[];
variables.add(_makeVariableInitializer(
controller,
js.js('#(#)', [newController, bodyName]).withSourceInformation(
sourceInformation),
js.js('#(#, #)', [
newController,
bodyName,
newControllerTypeArgument
]).withSourceInformation(sourceInformation),
sourceInformation));
if (analysis.hasYield) {
variables.add(
Expand Down
82 changes: 59 additions & 23 deletions pkg/compiler/lib/src/js_backend/backend.dart
Expand Up @@ -1154,42 +1154,29 @@ class JavaScriptBackend {

jsAst.Expression rewriteAsync(
CommonElements commonElements,
ElementEnvironment elementEnvironment,
FunctionEntity element,
jsAst.Expression code,
SourceInformation bodySourceInformation,
SourceInformation exitSourceInformation) {
bool startAsyncSynchronously = compiler.options.startAsyncSynchronously;
if (element.asyncMarker == AsyncMarker.SYNC) return code;

AsyncRewriterBase rewriter = null;
jsAst.Name name = namer.methodPropertyName(element);

switch (element.asyncMarker) {
case AsyncMarker.ASYNC:
var startFunction = startAsyncSynchronously
? commonElements.asyncHelperStartSync
: commonElements.asyncHelperStart;
var completerConstructor = startAsyncSynchronously
? commonElements.asyncAwaitCompleterConstructor
: commonElements.syncCompleterConstructor;
rewriter = new AsyncRewriter(reporter, element,
asyncStart: emitter.staticFunctionAccess(startFunction),
asyncAwait:
emitter.staticFunctionAccess(commonElements.asyncHelperAwait),
asyncReturn:
emitter.staticFunctionAccess(commonElements.asyncHelperReturn),
asyncRethrow:
emitter.staticFunctionAccess(commonElements.asyncHelperRethrow),
wrapBody: emitter.staticFunctionAccess(commonElements.wrapBody),
completerFactory:
emitter.staticFunctionAccess(completerConstructor),
safeVariableName: namer.safeVariablePrefixForAsyncRewrite,
bodyName: namer.deriveAsyncBodyName(name));
rewriter = _makeAsyncRewriter(
commonElements, elementEnvironment, element, code, name);
break;
case AsyncMarker.SYNC_STAR:
rewriter = new SyncStarRewriter(reporter, element,
endOfIteration:
emitter.staticFunctionAccess(commonElements.endOfIteration),
iterableFactory: emitter.staticFunctionAccess(
commonElements.syncStarIterableConstructor),
iterableFactoryTypeArgument:
_fetchItemType(element, elementEnvironment),
yieldStarExpression:
emitter.staticFunctionAccess(commonElements.yieldStar),
uncaughtErrorExpression: emitter
Expand All @@ -1206,20 +1193,69 @@ class JavaScriptBackend {
wrapBody: emitter.staticFunctionAccess(commonElements.wrapBody),
newController: emitter.staticFunctionAccess(
commonElements.asyncStarControllerConstructor),
newControllerTypeArgument:
_fetchItemType(element, elementEnvironment),
safeVariableName: namer.safeVariablePrefixForAsyncRewrite,
yieldExpression:
emitter.staticFunctionAccess(commonElements.yieldSingle),
yieldStarExpression:
emitter.staticFunctionAccess(commonElements.yieldStar),
bodyName: namer.deriveAsyncBodyName(name));
break;
default:
assert(element.asyncMarker == AsyncMarker.SYNC);
return code;
}
return rewriter.rewrite(code, bodySourceInformation, exitSourceInformation);
}

/// Returns an expression that evaluates the type argument to the
/// Future/Stream/Iterable.
jsAst.Expression _fetchItemType(
FunctionEntity element, ElementEnvironment elementEnvironment) {
DartType type =
elementEnvironment.getFunctionAsyncOrSyncStarElementType(element);

if (!type.containsFreeTypeVariables) {
return rtiEncoder.getTypeRepresentation(emitter.emitter, type, null);
}

// TODO(sra): Handle types that have type variables.
return js('null');
}

AsyncRewriter _makeAsyncRewriter(
CommonElements commonElements,
ElementEnvironment elementEnvironment,
FunctionEntity element,
jsAst.Expression code,
jsAst.Name name) {
bool startAsyncSynchronously = compiler.options.startAsyncSynchronously;

var startFunction = startAsyncSynchronously
? commonElements.asyncHelperStartSync
: commonElements.asyncHelperStart;
var completerConstructor = startAsyncSynchronously
? commonElements.asyncAwaitCompleterConstructor
: commonElements.syncCompleterConstructor;

jsAst.Expression itemTypeExpression =
_fetchItemType(element, elementEnvironment);

var rewriter = new AsyncRewriter(reporter, element,
asyncStart: emitter.staticFunctionAccess(startFunction),
asyncAwait:
emitter.staticFunctionAccess(commonElements.asyncHelperAwait),
asyncReturn:
emitter.staticFunctionAccess(commonElements.asyncHelperReturn),
asyncRethrow:
emitter.staticFunctionAccess(commonElements.asyncHelperRethrow),
wrapBody: emitter.staticFunctionAccess(commonElements.wrapBody),
completerFactory: emitter.staticFunctionAccess(completerConstructor),
completerFactoryTypeArgument: itemTypeExpression,
safeVariableName: namer.safeVariablePrefixForAsyncRewrite,
bodyName: namer.deriveAsyncBodyName(name));

return rewriter;
}

/// Creates an impact strategy to use for compilation.
ImpactStrategy createImpactStrategy(
{bool supportDeferredLoad: true, bool supportDumpInfo: true}) {
Expand Down
33 changes: 33 additions & 0 deletions pkg/compiler/lib/src/kernel/element_map_impl.dart
Expand Up @@ -1408,6 +1408,39 @@ class KernelElementEnvironment extends ElementEnvironment {
return elementMap._getFunctionTypeVariables(function);
}

@override
DartType getFunctionAsyncOrSyncStarElementType(FunctionEntity function) {
DartType returnType = getFunctionType(function).returnType;
switch (function.asyncMarker) {
case AsyncMarker.SYNC:
return returnType;
case AsyncMarker.SYNC_STAR:
if (returnType is InterfaceType) {
if (returnType.element == elementMap.commonElements.iterableClass) {
return returnType.typeArguments.first;
}
}
return dynamicType;
case AsyncMarker.ASYNC:
if (returnType is FutureOrType) return returnType.typeArgument;
if (returnType is InterfaceType) {
if (returnType.element == elementMap.commonElements.futureClass) {
return returnType.typeArguments.first;
}
}
return dynamicType;
case AsyncMarker.ASYNC_STAR:
if (returnType is InterfaceType) {
if (returnType.element == elementMap.commonElements.streamClass) {
return returnType.typeArguments.first;
}
}
return dynamicType;
}
assert(false, 'Unexpected marker ${function.asyncMarker}');
return null;
}

@override
DartType getFieldType(FieldEntity field) {
return elementMap._getFieldType(field);
Expand Down

0 comments on commit 81d779c

Please sign in to comment.