Skip to content

Commit

Permalink
[CFE] Add LocalFunction as super-interface for FunctionExpression and…
Browse files Browse the repository at this point in the history
… FunctionDeclaration

+ use it in dart2js to simplify and clarify handle of local function nodes

Change-Id: I35da2dd8bd3baba6eff6ad631ebe63d572bae4d6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105423
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
  • Loading branch information
johnniwinther authored and commit-bot@chromium.org committed Jun 12, 2019
1 parent 2be92b0 commit cbe4855
Show file tree
Hide file tree
Showing 13 changed files with 96 additions and 185 deletions.
2 changes: 1 addition & 1 deletion pkg/compiler/lib/src/closure.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ abstract class ClosureData {
/// used inside the scope of [node].
ScopeInfo getScopeInfo(MemberEntity member);

ClosureRepresentationInfo getClosureInfo(ir.Node localFunction);
ClosureRepresentationInfo getClosureInfo(ir.LocalFunction localFunction);

/// Look up information about a loop, in case any variables it declares need
/// to be boxed/snapshotted.
Expand Down
12 changes: 3 additions & 9 deletions pkg/compiler/lib/src/inferrer/inferrer_engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -725,13 +725,8 @@ class InferrerEngineImpl extends InferrerEngine {
}
break;
case MemberKind.closureCall:
ir.TreeNode node = definition.node;
if (node is ir.FunctionDeclaration) {
return node.function;
} else if (node is ir.FunctionExpression) {
return node.function;
}
break;
ir.LocalFunction node = definition.node;
return node.function;
case MemberKind.closureField:
case MemberKind.signature:
case MemberKind.generatorBody:
Expand Down Expand Up @@ -1361,8 +1356,7 @@ class KernelTypeSystemStrategy implements TypeSystemStrategy {
bool isClosure = false;
if (functionNode.parent is ir.Member) {
member = _closedWorld.elementMap.getMember(functionNode.parent);
} else if (functionNode.parent is ir.FunctionExpression ||
functionNode.parent is ir.FunctionDeclaration) {
} else if (functionNode.parent is ir.LocalFunction) {
ClosureRepresentationInfo info =
_closedWorld.closureDataLookup.getClosureInfo(functionNode.parent);
member = info.callMethod;
Expand Down
51 changes: 13 additions & 38 deletions pkg/compiler/lib/src/io/kernel_source_information.dart
Original file line number Diff line number Diff line change
Expand Up @@ -137,32 +137,24 @@ class KernelSourceInformationBuilder implements SourceInformationBuilder {
SourceInformation _buildFunctionEnd(MemberEntity member, [ir.TreeNode base]) {
MemberDefinition definition = _elementMap.getMemberDefinition(member);
String name = computeKernelElementNameForSourceMaps(_elementMap, member);
ir.Node node = definition.node;
switch (definition.kind) {
case MemberKind.regular:
ir.Member node = definition.node;
if (node is ir.Procedure) {
return _buildFunction(name, base ?? node, node.function);
}
break;
case MemberKind.constructor:
case MemberKind.constructorBody:
if (node is ir.Procedure) {
return _buildFunction(name, base ?? node, node.function);
} else if (node is ir.Constructor) {
return _buildFunction(name, base ?? node, node.function);
}
break;
ir.Member node = definition.node;
return _buildFunction(name, base ?? node, node.function);
case MemberKind.closureCall:
if (node is ir.FunctionDeclaration) {
return _buildFunction(name, base ?? node, node.function);
} else if (node is ir.FunctionExpression) {
return _buildFunction(name, base ?? node, node.function);
}
break;
ir.LocalFunction node = definition.node;
return _buildFunction(name, base ?? node, node.function);
// TODO(sra): generatorBody
default:
}
return _buildTreeNode(base ?? node, name: name);
return _buildTreeNode(base ?? definition.node, name: name);
}

/// Creates the source information for exiting a function definition defined
Expand Down Expand Up @@ -220,18 +212,11 @@ class KernelSourceInformationBuilder implements SourceInformationBuilder {
}
break;
case MemberKind.closureCall:
ir.Node node = definition.node;
if (node is ir.FunctionDeclaration) {
return _buildBody(node, node.function.body);
} else if (node is ir.FunctionExpression) {
return _buildBody(node, node.function.body);
}
break;
ir.LocalFunction node = definition.node;
return _buildBody(node, node.function.body);
case MemberKind.generatorBody:
ir.Node node = definition.node;
if (node is ir.FunctionDeclaration) {
return _buildBody(node, node.function.body);
} else if (node is ir.FunctionExpression) {
if (node is ir.LocalFunction) {
return _buildBody(node, node.function.body);
} else if (node is ir.Member && node.function != null) {
return _buildBody(node, node.function.body);
Expand All @@ -254,21 +239,11 @@ class KernelSourceInformationBuilder implements SourceInformationBuilder {
break;
case MemberKind.constructor:
case MemberKind.constructorBody:
ir.Node node = definition.node;
if (node is ir.Procedure) {
return _buildFunctionExit(node, node.function);
} else if (node is ir.Constructor) {
return _buildFunctionExit(node, node.function);
}
break;
ir.Member node = definition.node;
return _buildFunctionExit(node, node.function);
case MemberKind.closureCall:
ir.Node node = definition.node;
if (node is ir.FunctionDeclaration) {
return _buildFunctionExit(node, node.function);
} else if (node is ir.FunctionExpression) {
return _buildFunctionExit(node, node.function);
}
break;
ir.LocalFunction node = definition.node;
return _buildFunctionExit(node, node.function);
default:
}
return _buildTreeNode(definition.node);
Expand Down
26 changes: 7 additions & 19 deletions pkg/compiler/lib/src/ir/closure.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class ClosureScopeModel {
<ir.Node, KernelCapturedScope>{};

/// Collected [ScopeInfo] data for nodes.
Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate =
<ir.TreeNode, KernelScopeInfo>{};
Map<ir.LocalFunction, KernelScopeInfo> closuresToGenerate =
<ir.LocalFunction, KernelScopeInfo>{};

@override
String toString() {
Expand Down Expand Up @@ -227,8 +227,7 @@ enum VariableUseKind {
class VariableUse {
final VariableUseKind kind;
final ir.Member member;
final ir.TreeNode /*ir.FunctionDeclaration|ir.FunctionExpression*/
localFunction;
final ir.LocalFunction localFunction;
final ir.MethodInvocation invocation;
final ir.Instantiation instantiation;

Expand All @@ -248,10 +247,7 @@ class VariableUse {
: this.kind = VariableUseKind.localParameter,
this.member = null,
this.invocation = null,
this.instantiation = null {
assert(localFunction is ir.FunctionDeclaration ||
localFunction is ir.FunctionExpression);
}
this.instantiation = null;

VariableUse.memberReturnType(this.member)
: this.kind = VariableUseKind.memberReturnType,
Expand All @@ -263,10 +259,7 @@ class VariableUse {
: this.kind = VariableUseKind.localReturnType,
this.member = null,
this.invocation = null,
this.instantiation = null {
assert(localFunction is ir.FunctionDeclaration ||
localFunction is ir.FunctionExpression);
}
this.instantiation = null;

VariableUse.constructorTypeArgument(this.member)
: this.kind = VariableUseKind.constructorTypeArgument,
Expand All @@ -289,10 +282,7 @@ class VariableUse {
VariableUse.localTypeArgument(this.localFunction, this.invocation)
: this.kind = VariableUseKind.localTypeArgument,
this.member = null,
this.instantiation = null {
assert(localFunction is ir.FunctionDeclaration ||
localFunction is ir.FunctionExpression);
}
this.instantiation = null;

VariableUse.instantiationTypeArgument(this.instantiation)
: this.kind = VariableUseKind.instantiationTypeArgument,
Expand Down Expand Up @@ -388,9 +378,7 @@ class TypeVariableTypeWithContext implements ir.Node {
} else {
// We have a generic local function type variable, like `T` in
// `m() { local<T>() { ... } ... }`.
assert(
typeDeclaration.parent is ir.FunctionExpression ||
typeDeclaration.parent is ir.FunctionDeclaration,
assert(typeDeclaration.parent is ir.LocalFunction,
"Unexpected type declaration: $typeDeclaration");
kind = TypeVariableKind.local;
typeDeclaration = typeDeclaration.parent;
Expand Down
7 changes: 2 additions & 5 deletions pkg/compiler/lib/src/ir/scope_visitor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -484,9 +484,7 @@ class ScopeModelBuilder extends ir.Visitor<InitializerComplexity>
}

void visitInvokable(ir.TreeNode node, void f()) {
assert(node is ir.Member ||
node is ir.FunctionExpression ||
node is ir.FunctionDeclaration);
assert(node is ir.Member || node is ir.LocalFunction);
bool oldIsInsideClosure = _isInsideClosure;
ir.TreeNode oldExecutableContext = _executableContext;
KernelScopeInfo oldScopeInfo = _currentScopeInfo;
Expand Down Expand Up @@ -866,8 +864,7 @@ class ScopeModelBuilder extends ir.Visitor<InitializerComplexity>
if (node.arguments.types.isNotEmpty) {
VariableUse usage;
if (receiver is ir.VariableGet &&
(receiver.variable.parent is ir.FunctionDeclaration ||
receiver.variable.parent is ir.FunctionExpression)) {
(receiver.variable.parent is ir.LocalFunction)) {
usage =
new VariableUse.localTypeArgument(receiver.variable.parent, node);
} else {
Expand Down
35 changes: 12 additions & 23 deletions pkg/compiler/lib/src/js_model/closure.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ class ClosureDataImpl implements ClosureData {
// Signature function.
final Map<MemberEntity, CapturedScope> _capturedScopeForSignatureMap;

// The key is either a [ir.FunctionDeclaration] or [ir.FunctionExpression].
final Map<ir.TreeNode, ClosureRepresentationInfo>
final Map<ir.LocalFunction, ClosureRepresentationInfo>
_localClosureRepresentationMap;

ClosureDataImpl(this._elementMap, this._scopeMap, this._capturedScopesMap,
Expand All @@ -56,8 +55,8 @@ class ClosureDataImpl implements ClosureData {
.readTreeNodeMap(() => new CapturedScope.readFromDataSource(source));
Map<MemberEntity, CapturedScope> capturedScopeForSignatureMap = source
.readMemberMap(() => new CapturedScope.readFromDataSource(source));
Map<ir.TreeNode, ClosureRepresentationInfo> localClosureRepresentationMap =
source.readTreeNodeMap(
Map<ir.LocalFunction, ClosureRepresentationInfo>
localClosureRepresentationMap = source.readTreeNodeMap(
() => new ClosureRepresentationInfo.readFromDataSource(source));
source.end(tag);
return new ClosureDataImpl(elementMap, scopeMap, capturedScopesMap,
Expand Down Expand Up @@ -123,8 +122,7 @@ class ClosureDataImpl implements ClosureData {
_capturedScopesMap[loopNode] ?? const CapturedLoopScope();

@override
ClosureRepresentationInfo getClosureInfo(ir.Node node) {
assert(node is ir.FunctionExpression || node is ir.FunctionDeclaration);
ClosureRepresentationInfo getClosureInfo(ir.LocalFunction node) {
var closure = _localClosureRepresentationMap[node];
assert(
closure != null,
Expand Down Expand Up @@ -159,9 +157,8 @@ class ClosureDataBuilder {
// Signature function.
Map<MemberEntity, CapturedScope> _capturedScopeForSignatureMap = {};

// The key is either a [ir.FunctionDeclaration] or [ir.FunctionExpression].
Map<ir.TreeNode, ClosureRepresentationInfo> _localClosureRepresentationMap =
{};
Map<ir.LocalFunction, ClosureRepresentationInfo>
_localClosureRepresentationMap = {};

ClosureDataBuilder(this._elementMap, this._globalLocalsMap, this._options);

Expand Down Expand Up @@ -323,17 +320,10 @@ class ClosureDataBuilder {
allBoxedVariables.addAll(boxedVariables);
});

Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate =
Map<ir.LocalFunction, KernelScopeInfo> closuresToGenerate =
model.closuresToGenerate;
for (ir.TreeNode node in closuresToGenerate.keys) {
ir.FunctionNode functionNode;
if (node is ir.FunctionDeclaration) {
functionNode = node.function;
} else if (node is ir.FunctionExpression) {
functionNode = node.function;
} else {
failedAt(member, "Unexpected closure node ${node}");
}
for (ir.LocalFunction node in closuresToGenerate.keys) {
ir.FunctionNode functionNode = node.function;
KernelClosureClassInfo closureClassInfo = _produceSyntheticElements(
closedWorldBuilder,
member,
Expand Down Expand Up @@ -402,8 +392,7 @@ class ClosureDataBuilder {
if (node.parent is ir.Member) {
assert(_elementMap.getMember(node.parent) == member);
} else {
assert(node.parent is ir.FunctionExpression ||
node.parent is ir.FunctionDeclaration);
assert(node.parent is ir.LocalFunction);
_localClosureRepresentationMap[node.parent] = closureClassInfo;
}
return closureClassInfo;
Expand Down Expand Up @@ -1281,9 +1270,9 @@ abstract class ClosureRtiNeed {

bool methodNeedsSignature(MemberEntity method);

bool localFunctionNeedsTypeArguments(ir.Node node);
bool localFunctionNeedsTypeArguments(ir.LocalFunction node);

bool localFunctionNeedsSignature(ir.Node node);
bool localFunctionNeedsSignature(ir.LocalFunction node);

bool selectorNeedsTypeArguments(Selector selector);

Expand Down
68 changes: 27 additions & 41 deletions pkg/compiler/lib/src/js_model/element_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -273,28 +273,15 @@ ir.FunctionNode getFunctionNode(
MemberDefinition definition = elementMap.getMemberDefinition(member);
switch (definition.kind) {
case MemberKind.regular:
ir.Node node = definition.node;
if (node is ir.Procedure) {
return node.function;
}
break;
ir.Member node = definition.node;
return node.function;
case MemberKind.constructor:
case MemberKind.constructorBody:
ir.Node node = definition.node;
if (node is ir.Procedure) {
return node.function;
} else if (node is ir.Constructor) {
return node.function;
}
break;
ir.Member node = definition.node;
return node.function;
case MemberKind.closureCall:
ir.Node node = definition.node;
if (node is ir.FunctionDeclaration) {
return node.function;
} else if (node is ir.FunctionExpression) {
return node.function;
}
break;
ir.LocalFunction node = definition.node;
return node.function;
default:
}
return null;
Expand All @@ -303,23 +290,29 @@ ir.FunctionNode getFunctionNode(
// TODO(johnniwinther,efortuna): Add more when needed.
// TODO(johnniwinther): Should we split regular into method, field, etc.?
enum MemberKind {
// A regular member defined by an [ir.Node].
/// A regular member defined by an [ir.Node].
regular,
// A constructor whose initializer is defined by an [ir.Constructor] node.

/// A constructor whose initializer is defined by an [ir.Constructor] node.
constructor,
// A constructor whose body is defined by an [ir.Constructor] node.

/// A constructor whose body is defined by an [ir.Constructor] node.
constructorBody,
// A closure class `call` method whose body is defined by an
// [ir.FunctionExpression] or [ir.FunctionDeclaration].

/// A closure class `call` method whose body is defined by an
/// [ir.LocalFunction].
closureCall,
// A field corresponding to a captured variable in the closure. It does not
// have a corresponding ir.Node.

/// A field corresponding to a captured variable in the closure. It does not
/// have a corresponding ir.Node.
closureField,
// A method that describes the type of a function (in this case the type of
// the closure class. It does not have a corresponding ir.Node or a method
// body.

/// A method that describes the type of a function (in this case the type of
/// the closure class. It does not have a corresponding ir.Node or a method
/// body.
signature,
// A separated body of a generator (sync*/async/async*) function.

/// A separated body of a generator (sync*/async/async*) function.
generatorBody,
}

Expand Down Expand Up @@ -588,17 +581,10 @@ void forEachOrderedParameter(JsToElementMap elementMap, FunctionEntity function,
}
break;
case MemberKind.closureCall:
ir.Node node = definition.node;
if (node is ir.FunctionDeclaration) {
forEachOrderedParameterByFunctionNode(
node.function, parameterStructure, handleParameter);
return;
} else if (node is ir.FunctionExpression) {
forEachOrderedParameterByFunctionNode(
node.function, parameterStructure, handleParameter);
return;
}
break;
ir.LocalFunction node = definition.node;
forEachOrderedParameterByFunctionNode(
node.function, parameterStructure, handleParameter);
return;
default:
}
failedAt(function, "Unexpected function definition $definition.");
Expand Down
Loading

0 comments on commit cbe4855

Please sign in to comment.