1
0
mirror of https://github.com/dart-lang/sdk synced 2024-07-08 12:06:26 +00:00

Remove unused closure conversion

Change-Id: I0edbbd29a4cc603e7479023bc0e8869c78ca7bcc
Reviewed-on: https://dart-review.googlesource.com/54225
Commit-Queue: Peter von der Ahé <ahe@google.com>
Reviewed-by: Samir Jindel <sjindel@google.com>
This commit is contained in:
Peter von der Ahé 2018-05-14 14:58:17 +00:00 committed by commit-bot@chromium.org
parent bc86dc1dd6
commit 02cd63eefd
77 changed files with 0 additions and 3936 deletions

View File

@ -12,7 +12,6 @@ import 'package:kernel/core_types.dart';
import 'package:kernel/kernel.dart';
import 'package:kernel/src/tool/batch_util.dart';
import 'package:kernel/target/targets.dart';
import 'package:kernel/transformations/closure_conversion.dart' as closures;
import 'package:kernel/transformations/constants.dart' as constants;
import 'package:kernel/transformations/continuation.dart' as cont;
import 'package:kernel/transformations/empty.dart' as empty;
@ -94,9 +93,6 @@ Future<CompilerOutcome> runTransformation(List<String> arguments) async {
mix.transformLibraries(
new NoneTarget(null), coreTypes, hierarchy, component.libraries);
break;
case 'closures':
component = closures.transformComponent(coreTypes, component);
break;
case 'coq':
component = coq.transformComponent(coreTypes, component);
break;

View File

@ -9,7 +9,6 @@ import '../core_types.dart';
import '../transformations/treeshaker.dart' show ProgramRoot;
import 'flutter.dart' show FlutterTarget;
import 'vm.dart' show VmTarget;
import 'vmcc.dart' show VmClosureConvertedTarget;
final List<String> targetNames = targets.keys.toList();
@ -35,7 +34,6 @@ typedef Target _TargetBuilder(TargetFlags flags);
final Map<String, _TargetBuilder> targets = <String, _TargetBuilder>{
'none': (TargetFlags flags) => new NoneTarget(flags),
'vm': (TargetFlags flags) => new VmTarget(flags),
'vmcc': (TargetFlags flags) => new VmClosureConvertedTarget(flags),
'flutter': (TargetFlags flags) => new FlutterTarget(flags),
};

View File

@ -1,61 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library kernel.target.vmcc;
import '../ast.dart' show Component, Library;
import '../core_types.dart' show CoreTypes;
import '../class_hierarchy.dart';
import '../transformations/continuation.dart' as cont;
import '../transformations/mixin_full_resolution.dart' as mix;
import '../transformations/sanitize_for_vm.dart';
import '../transformations/treeshaker.dart';
import '../transformations/closure_conversion.dart' as cc
show transformComponent;
import 'targets.dart' show TargetFlags;
import 'vm.dart' as vm_target;
// VmClosureConvertedTarget used legacy VmTarget which was superseded by
// VmFastaTarget. Legacy transformations pipeline was pulled from VmTarget
// into this class when VmTarget was merged with new VmFastaTarget.
// TODO(alexmarkov): Figure out if this target is still used, and either remove
// it or unify its transformation pipeline with new VmTarget.
class VmClosureConvertedTarget extends vm_target.VmTarget {
VmClosureConvertedTarget(TargetFlags flags) : super(flags);
@override
String get name => "vmcc";
ClassHierarchy _hierarchy;
@override
void performModularTransformationsOnLibraries(
CoreTypes coreTypes, ClassHierarchy hierarchy, List<Library> libraries,
{void logger(String msg)}) {
var mixins = new mix.MixinFullResolution(this, coreTypes, hierarchy)
..transform(libraries);
_hierarchy = mixins.hierarchy;
}
@override
void performGlobalTransformations(CoreTypes coreTypes, Component component,
{void logger(String msg)}) {
if (flags.treeShake) {
performTreeShaking(coreTypes, component);
}
cont.transformComponent(coreTypes, component, flags.syncAsync);
new SanitizeForVM().transform(component);
cc.transformComponent(coreTypes, component);
}
void performTreeShaking(CoreTypes coreTypes, Component component) {
new TreeShaker(coreTypes, _hierarchy, component,
strongMode: strongMode, programRoots: flags.programRoots)
.transform(component);
_hierarchy = null; // Hierarchy must be recomputed.
}
}

View File

@ -1,7 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library kernel.transformations.closure.converter;
export '../../clone.dart' show CloneWithoutBody;

View File

@ -1,252 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library kernel.transformations.closure.context;
import '../../ast.dart'
show
Expression,
FunctionNode,
NullLiteral,
StringLiteral,
Throw,
TreeNode,
VariableDeclaration,
VariableGet,
VariableSet,
VectorCreation,
VectorGet,
VectorSet,
VectorCopy;
import 'converter.dart' show ClosureConverter;
import 'variable_accessor.dart' show VariableAccessor;
abstract class Context {
/// Returns a new expression for accessing this context.
Expression get expression;
/// Returns an accessor (or null) for accessing this context.
VariableAccessor get accessor;
/// Extend the context to include [variable] initialized to [value]. For
/// example, this replaces the [VariableDeclaration] node of a captured local
/// variable.
///
/// This may create a new context and update the `context` field of the
/// current [ClosureConverter].
// TODO(ahe): Return context instead?
void extend(VariableDeclaration variable, Expression value);
/// Update the initializer [value] of [variable] which was previously added
/// with [extend]. This is used when [value] isn't available when the context
/// was extended.
void update(VariableDeclaration variable, Expression value) {
throw "not supported $runtimeType";
}
/// Returns a new expression for reading the value of [variable] from this
/// context. For example, for replacing a [VariableGet] of a captured local
/// variable.
Expression lookup(VariableDeclaration variable);
/// Returns a new expression which stores [value] in [variable] in this
/// context. For example, for replacing a [VariableSet] of a captured local
/// variable.
Expression assign(VariableDeclaration variable, Expression value,
{bool voidContext: false});
/// Returns a new context whose parent is this context. The optional argument
/// [accessor] controls how the nested context access this context. This is
/// used, for example, when hoisting a local function. In this case, access
/// to this context can't be accessed directly via [expression]. In other
/// cases, for example, a for-loop, this context is still in scope and can be
/// accessed directly (with [accessor]).
Context toNestedContext([VariableAccessor accessor]);
/// Returns a new expression which will copy this context and store the copy
/// in the local variable currently holding this context.
Expression clone() {
return new Throw(
new StringLiteral("Context clone not implemented for ${runtimeType}"));
}
}
class NoContext extends Context {
final ClosureConverter converter;
NoContext(this.converter);
Expression get expression => new NullLiteral();
VariableAccessor get accessor => null;
void extend(VariableDeclaration variable, Expression value) {
converter.context = new LocalContext(converter, this)
..extend(variable, value);
}
Expression lookup(VariableDeclaration variable) {
throw 'Unbound NoContext.lookup($variable)';
}
Expression assign(VariableDeclaration variable, Expression value,
{bool voidContext: false}) {
throw 'Unbound NoContext.assign($variable, ...)';
}
Context toNestedContext([VariableAccessor accessor]) {
return new NestedContext(
converter, accessor, <List<VariableDeclaration>>[]);
}
}
class LocalContext extends Context {
final ClosureConverter converter;
final Context parent;
final VariableDeclaration self;
final VectorCreation vectorCreation;
final List<VariableDeclaration> variables = <VariableDeclaration>[];
final Map<VariableDeclaration, VectorSet> initializers =
<VariableDeclaration, VectorSet>{};
LocalContext._internal(
this.converter, this.parent, this.self, this.vectorCreation);
factory LocalContext(ClosureConverter converter, Context parent) {
converter.rewriter.insertContextDeclaration(parent.expression);
return new LocalContext._internal(
converter,
parent,
converter.rewriter.contextDeclaration,
converter.rewriter.vectorCreation);
}
Expression get expression => accessor.buildSimpleRead();
VariableAccessor get accessor =>
new VariableAccessor(self, null, TreeNode.noOffset);
void extend(VariableDeclaration variable, Expression value) {
// Increase index by 2, because the type arguments vector occupies position
// 0, the parent occupies position 1, and all other variables are therefore
// shifted by 2.
VectorSet initializer =
new VectorSet(expression, variables.length + 2, value);
value.parent = initializer;
converter.rewriter.insertExtendContext(initializer);
if (variable.parent is FunctionNode) {
converter.rewriter.insertZeroOutParameter(variable);
}
++vectorCreation.length;
variables.add(variable);
initializers[variable] = initializer;
}
void update(VariableDeclaration variable, Expression value) {
VectorSet initializer = initializers[variable];
initializer.value = value;
value.parent = initializer;
}
Expression lookup(VariableDeclaration variable) {
var index = variables.indexOf(variable);
// Increase index by 2 in case of success, because the type arguments vector
// occupies position 0, the parent occupies position 1, and all other
// variables are therefore shifted by 2.
return index == -1
? parent.lookup(variable)
: new VectorGet(expression, index + 2);
}
Expression assign(VariableDeclaration variable, Expression value,
{bool voidContext: false}) {
var index = variables.indexOf(variable);
// Increase index by 2 in case of success, because the type arguments vector
// occupies position 0, the parent occupies position 1, and all other
// variables are therefore shifted by 2.
return index == -1
? parent.assign(variable, value, voidContext: voidContext)
: new VectorSet(expression, index + 2, value);
}
Context toNestedContext([VariableAccessor accessor]) {
accessor ??= this.accessor;
List<List<VariableDeclaration>> variabless = <List<VariableDeclaration>>[];
var current = this;
while (current != null && current is! NoContext) {
if (current is LocalContext) {
variabless.add(current.variables);
current = current.parent;
} else if (current is NestedContext) {
variabless.addAll((current as NestedContext).variabless);
current = null;
}
}
return new NestedContext(converter, accessor, variabless);
}
Expression clone() {
self.isFinal = false;
return new VariableSet(self, new VectorCopy(new VariableGet(self)));
}
}
class NestedContext extends Context {
final ClosureConverter converter;
final VariableAccessor accessor;
final List<List<VariableDeclaration>> variabless;
NestedContext(this.converter, this.accessor, this.variabless);
Expression get expression {
return accessor?.buildSimpleRead() ?? new NullLiteral();
}
void extend(VariableDeclaration variable, Expression value) {
converter.context = new LocalContext(converter, this)
..extend(variable, value);
}
Expression lookup(VariableDeclaration variable) {
Expression context = expression;
for (var variables in variabless) {
var index = variables.indexOf(variable);
if (index != -1) {
// Increase index by 2 in case of success, because the type arguments
// vector occupies position 0, the parent occupies item 1, and all other
// variables are therefore shifted by 2.
return new VectorGet(context, index + 2);
}
// Item 1 of a context always points to its parent.
context = new VectorGet(context, 1);
}
throw 'Unbound NestedContext.lookup($variable)';
}
Expression assign(VariableDeclaration variable, Expression value,
{bool voidContext: false}) {
Expression context = expression;
for (List<VariableDeclaration> variables in variabless) {
var index = variables.indexOf(variable);
if (index != -1) {
// Increase index by 2 in case of success, because the type arguments
// vector occupies position 0, the parent occupies item 1, and all other
// variables are therefore shifted by 2.
return new VectorSet(context, index + 2, value);
}
// Item 1 of a context always points to its parent.
context = new VectorGet(context, 1);
}
throw 'Unbound NestedContext.lookup($variable)';
}
Context toNestedContext([VariableAccessor accessor]) {
return new NestedContext(converter, accessor ?? this.accessor, variabless);
}
}

View File

@ -1,848 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library kernel.transformations.closure.converter;
import '../../ast.dart'
show
AsyncMarker,
Arguments,
Block,
Catch,
Class,
ClosureCreation,
Constructor,
DartType,
DoStatement,
DynamicType,
EmptyStatement,
Expression,
ExpressionStatement,
Field,
ForInStatement,
ForStatement,
FunctionDeclaration,
FunctionExpression,
FunctionNode,
FunctionType,
Initializer,
InterfaceType,
InvalidExpression,
InvocationExpression,
Library,
LocalInitializer,
RedirectingInitializer,
Member,
MethodInvocation,
Name,
NamedExpression,
NamedType,
NullLiteral,
Procedure,
ProcedureKind,
PropertyGet,
ReturnStatement,
Statement,
StaticInvocation,
ThisExpression,
Transformer,
TreeNode,
TypeParameter,
TypeParameterType,
VariableDeclaration,
VariableGet,
VariableSet,
VectorCreation,
WhileStatement,
transformList;
import '../../clone.dart' show CloneVisitor;
import '../../core_types.dart' show CoreTypes;
import '../../type_algebra.dart' show substitute;
import 'clone_without_body.dart' show CloneWithoutBody;
import 'context.dart' show Context, NoContext, LocalContext;
import 'info.dart' show ClosureInfo;
import 'rewriter.dart' show AstRewriter, BlockRewriter, InitializerListRewriter;
import 'variable_accessor.dart' show VariableAccessor;
bool isLoop(TreeNode node) {
return node is WhileStatement ||
node is DoStatement ||
node is ForStatement ||
node is ForInStatement;
}
class ClosureConverter extends Transformer {
final CoreTypes coreTypes;
final Set<VariableDeclaration> capturedVariables;
// This map pairs variables that are captured with flags indicating whether
// they are used inside or outside an initializer. See
// [ClosureInfo.parameterUses].
final Map<VariableDeclaration, int> parameterUses;
final Map<FunctionNode, Set<TypeParameter>> capturedTypeVariables;
final Map<FunctionNode, VariableDeclaration> thisAccess;
final Map<FunctionNode, String> localNames;
/// Records place-holders for cloning contexts. See [visitForStatement].
final Set<InvalidExpression> contextClonePlaceHolders =
new Set<InvalidExpression>();
final CloneVisitor cloner = new CloneWithoutBody();
/// New members to add to [currentLibrary] after it has been
/// transformed. These members will not be transformed themselves.
final List<TreeNode> newLibraryMembers = <TreeNode>[];
/// New members to add to [currentClass] after it has been transformed. These
/// members will not be transformed themselves.
final List<Member> newClassMembers = <Member>[];
Library currentLibrary;
Class currentClass;
Member currentMember;
FunctionNode currentMemberFunction;
FunctionNode currentFunction;
Context context;
AstRewriter rewriter;
/// TODO(29181): update this comment when the type variables are restored.
/// Maps original type variable (aka type parameter) to a hoisted type
/// variable type.
///
/// For example, consider:
///
/// class C<T> {
/// f() => (x) => x is T;
/// }
///
/// This is currently converted to:
///
/// class C<T> {
/// f() => new Closure#0<T>();
/// }
/// class Closure#0<T_> implements Function {
/// call(x) => x is T_;
/// }
///
/// In this example, `typeSubstitution[T].parameter == T_` when transforming
/// the closure in `f`.
Map<TypeParameter, DartType> typeSubstitution =
const <TypeParameter, DartType>{};
ClosureConverter(this.coreTypes, ClosureInfo info)
: this.capturedVariables = info.variables,
this.parameterUses = info.parameterUses,
this.capturedTypeVariables = info.typeVariables,
this.thisAccess = info.thisAccess,
this.localNames = info.localNames;
bool get isOuterMostContext {
return currentFunction == null || currentMemberFunction == currentFunction;
}
Uri get currentFileUri {
if (currentMember is Constructor) return currentClass.fileUri;
if (currentMember is Field) return (currentMember as Field).fileUri;
if (currentMember is Procedure) return (currentMember as Procedure).fileUri;
throw "No file uri for ${currentMember.runtimeType}";
}
TreeNode saveContext(TreeNode f()) {
AstRewriter old = rewriter;
Context savedContext = context;
try {
return f();
} finally {
rewriter = old;
context = savedContext;
}
}
TreeNode visitLibrary(Library node) {
assert(newLibraryMembers.isEmpty);
currentLibrary = node;
node = super.visitLibrary(node);
for (TreeNode member in newLibraryMembers) {
if (member is Class) {
node.addClass(member);
} else {
node.addMember(member);
}
}
newLibraryMembers.clear();
currentLibrary = null;
return node;
}
TreeNode visitClass(Class node) {
assert(newClassMembers.isEmpty);
currentClass = node;
node = super.visitClass(node);
newClassMembers.forEach(node.addMember);
newClassMembers.clear();
currentClass = null;
return node;
}
extendContextConditionally({bool inInitializer}) {
return (VariableDeclaration parameter) {
if (!capturedVariables.contains(parameter)) return 0;
int flags = parameterUses[parameter];
if (flags == null) {
context.extend(parameter, new VariableGet(parameter));
return 0;
}
// When moving variables into the context while scanning initializers,
// we need to add the variable if it's captured in an initializer,
// whether or not it's used/captured in the body. However, in the body,
// we only need to add the variable into the context if it's *not*
// captured in an initializer.
if (inInitializer
? (flags & ClosureInfo.INSIDE_INITIALIZER) > 0
: flags == ClosureInfo.OUTSIDE_INITIALIZER) {
context.extend(parameter, new VariableGet(parameter));
}
return flags;
};
}
TreeNode visitConstructor(Constructor node) {
assert(isEmptyContext);
currentMember = node;
// If we created a context for the initializers, we need to re-use that
// context in the body of the function. Unfortunately, the context is
// declared in a local initializer and local initializers aren't visible
// in the body of the constructor. To work around this issue, we move the
// body into a new constructor and make this constructor redirect to that
// one, passing the context as an argument to the new constructor.
var movingCtor = false;
// Transform initializers.
if (node.initializers.length > 0) {
var initRewriter = new InitializerListRewriter(node);
rewriter = initRewriter;
context = new NoContext(this);
final int capturedBoth =
ClosureInfo.OUTSIDE_INITIALIZER | ClosureInfo.INSIDE_INITIALIZER;
// TODO(karlklose): add a fine-grained analysis of captured parameters.
handleParam(decl) {
if (extendContextConditionally(inInitializer: true)(decl) ==
capturedBoth) {
movingCtor = true;
}
}
node.function.positionalParameters.forEach(handleParam);
node.function.namedParameters.forEach(handleParam);
transformList(node.initializers, this, node);
node.initializers.insertAll(0, initRewriter.prefix);
rewriter = null;
}
// Transform constructor body.
FunctionNode function = node.function;
if (function.body != null && function.body is! EmptyStatement) {
setupRewriterForFunctionBody(function);
if (!movingCtor) context = new NoContext(this);
VariableDeclaration self = thisAccess[currentMemberFunction];
if (self != null) {
context.extend(self, new ThisExpression());
}
node.function.accept(this);
if (movingCtor) {
var contextDecl = (context as LocalContext).self;
var newCtorName = new Name("${node.name.name}#redir");
var newCtor = new Constructor(node.function, name: newCtorName);
newClassMembers.add(newCtor);
LocalInitializer contextDeclInit = null;
for (var init in node.initializers) {
if (init is LocalInitializer && init.variable == contextDecl) {
contextDeclInit = init;
} else {
newCtor.initializers.add(init);
}
}
node.initializers = <Initializer>[contextDeclInit];
var cv = new CloneVisitor();
var oldCtorParams = function.positionalParameters
.map(cv.visitVariableDeclaration)
.toList();
var oldCtorNamedParams =
function.namedParameters.map(cv.visitVariableDeclaration).toList();
function.positionalParameters.addAll(function.namedParameters);
function.namedParameters = [];
var args = <Expression>[];
args.addAll(oldCtorParams.map((decl) => new VariableGet(decl)));
args.addAll(oldCtorNamedParams.map((decl) => new VariableGet(decl)));
node.function = new FunctionNode(new EmptyStatement(),
typeParameters: [],
positionalParameters: oldCtorParams,
namedParameters: oldCtorNamedParams,
requiredParameterCount: function.requiredParameterCount,
returnType: function.returnType,
asyncMarker: function.asyncMarker,
dartAsyncMarker: function.dartAsyncMarker);
node.function.parent = node;
var oldCtorDecl = cv.visitVariableDeclaration(contextDecl);
contextDecl.initializer = null;
function.positionalParameters.add(contextDecl);
function.requiredParameterCount++;
contextDeclInit.variable = oldCtorDecl;
oldCtorDecl.parent = contextDeclInit;
args.add(new VariableGet(oldCtorDecl));
var redirInit =
new RedirectingInitializer(newCtor, new Arguments(args));
node.initializers.add(redirInit);
}
}
resetContext();
return node;
}
AstRewriter makeRewriterForBody(FunctionNode function) {
Statement body = function.body;
if (body is! Block) {
body = new Block(<Statement>[body]);
function.body = function.body.parent = body;
}
return new BlockRewriter(body);
}
bool isObject(DartType type) {
return type is InterfaceType && type.classNode.supertype == null;
}
TreeNode visitField(Field node) {
currentMember = node;
context = new NoContext(this);
node = super.visitField(node);
context = null;
currentMember = null;
return node;
}
Expression handleLocalFunction(FunctionNode function) {
if (function.asyncMarker == AsyncMarker.SyncYielding) {
function.transformChildren(this);
return new FunctionExpression(function);
}
FunctionNode enclosingFunction = currentFunction;
Map<TypeParameter, DartType> enclosingTypeSubstitution = typeSubstitution;
currentFunction = function;
Statement body = function.body;
assert(body != null);
rewriter = makeRewriterForBody(function);
VariableDeclaration contextVariable =
new VariableDeclaration("#contextParameter", type: const DynamicType());
Context parent = context;
context = context.toNestedContext(
new VariableAccessor(contextVariable, null, TreeNode.noOffset));
Set<TypeParameter> captured =
capturedTypeVariables[currentFunction] ?? new Set<TypeParameter>();
typeSubstitution = copyTypeVariables(captured);
function.transformChildren(this);
Expression result = addClosure(function, contextVariable, parent.expression,
typeSubstitution, enclosingTypeSubstitution);
currentFunction = enclosingFunction;
typeSubstitution = enclosingTypeSubstitution;
return result;
}
TreeNode visitFunctionDeclaration(FunctionDeclaration node) {
/// Is this closure itself captured by a closure?
bool isCaptured = capturedVariables.contains(node.variable);
if (isCaptured) {
context.extend(node.variable, new InvalidExpression(null));
}
Context parent = context;
return saveContext(() {
Expression expression = handleLocalFunction(node.function);
if (isCaptured) {
parent.update(node.variable, expression);
return null;
} else {
node.variable.initializer = expression;
expression.parent = node.variable;
return node.variable;
}
});
}
TreeNode visitFunctionExpression(FunctionExpression node) {
return saveContext(() => handleLocalFunction(node.function));
}
/// Add a new procedure to the current library that looks like this:
///
/// static method closure#0(Vector #c, /* Parameters of [function]. */)
/// dynamic {
///
/// /* Context is represented by #c. */
///
/// /* Body of [function]. */
///
/// }
///
/// Returns an invocation of the closure creation primitive that binds the
/// above top-level function to a context represented as Vector.
Expression addClosure(
FunctionNode function,
VariableDeclaration contextVariable,
Expression accessContext,
Map<TypeParameter, DartType> substitution,
Map<TypeParameter, DartType> enclosingTypeSubstitution) {
var fnTypeParams = <TypeParameter>[];
var fnTypeArgs = <TypeParameterType>[];
for (TypeParameter t in substitution.keys) {
var fnTypeParam = (substitution[t] as TypeParameterType).parameter;
fnTypeParams.add(fnTypeParam);
fnTypeArgs
.add(substitute(new TypeParameterType(t), enclosingTypeSubstitution));
}
function.typeParameters.insertAll(0, fnTypeParams);
function.positionalParameters.insert(0, contextVariable);
++function.requiredParameterCount;
Procedure closedTopLevelFunction = new Procedure(
new Name(createNameForClosedTopLevelFunction(function)),
ProcedureKind.Method,
function,
isStatic: true,
fileUri: currentFileUri);
newLibraryMembers.add(closedTopLevelFunction);
// We need to again make new type parameters for the function's function
// type, and substitute them into the function type's arguments' types.
var closureTypeParams = <TypeParameter>[];
var closureTypeSubstitutionMap = copyTypeVariables(function.typeParameters);
for (DartType d in closureTypeSubstitutionMap.values)
closureTypeParams.add((d as TypeParameterType).parameter);
FunctionType closureType = new FunctionType(
function.positionalParameters
.skip(1)
.map((VariableDeclaration decl) =>
substitute(decl.type, closureTypeSubstitutionMap))
.toList(),
substitute(function.returnType, closureTypeSubstitutionMap),
namedParameters: function.namedParameters
.map((VariableDeclaration decl) => new NamedType(
decl.name, substitute(decl.type, closureTypeSubstitutionMap)))
.toList(),
typeParameters: closureTypeParams,
requiredParameterCount: function.requiredParameterCount - 1);
// If we capture type parameters but not regular variables, we still need to
// make a context.
if (capturedTypeVariables[function] != null &&
accessContext is NullLiteral) {
accessContext = new VectorCreation(1);
}
return new ClosureCreation(
closedTopLevelFunction, accessContext, closureType, fnTypeArgs);
}
TreeNode visitProcedure(Procedure node) {
assert(isEmptyContext);
currentMember = node;
FunctionNode function = node.function;
if (function.body != null) {
bool hadSingleStatementBody = function.body is! Block;
setupRewriterForFunctionBody(function);
// Start with no context. This happens after setting up _currentBlock
// so statements can be emitted into _currentBlock if necessary.
context = new NoContext(this);
VariableDeclaration self = thisAccess[currentMemberFunction];
if (self != null) {
context.extend(self, new ThisExpression());
}
node.transformChildren(this);
resetContext();
// Here a special case is handled: the body of the procedure was a single
// statement and after the transformation it is a block with a single
// statement inside. In this case we make this statement the body of the
// procedure again. It is required to follow the conventions imposed by
// [addClass] in [DillLibraryBuilder].
// See [dill_library_builder.dart]
// (../../../../front_end/lib/src/fasta/dill/dill_library_builder.dart)
// for details.
if (hadSingleStatementBody && function.body is Block) {
Block body = function.body;
if (body.statements.length == 1) {
function.body = body.statements[0];
function.body.parent = function;
}
}
}
return node;
}
void setupRewriterForFunctionBody(FunctionNode function) {
Statement body = function.body;
assert(body != null);
currentMemberFunction = function;
// Ensure that the body is a block which becomes the current block.
rewriter = makeRewriterForBody(function);
}
void resetContext() {
rewriter = null;
context = null;
currentMemberFunction = null;
currentMember = null;
}
bool get isEmptyContext {
return rewriter == null && context == null;
}
TreeNode visitLocalInitializer(LocalInitializer node) {
assert(!capturedVariables.contains(node.variable));
node.transformChildren(this);
return node;
}
TreeNode visitFunctionNode(FunctionNode node) {
transformList(node.typeParameters, this, node);
// Initializers for optional parameters must be compile-time constants,
// which excludes closures. Therefore, we can avoid looking for closures in
// initializers of the parameters.
node.positionalParameters
.forEach(extendContextConditionally(inInitializer: false));
node.namedParameters
.forEach(extendContextConditionally(inInitializer: false));
assert(node.body != null);
node.body = node.body.accept(this);
node.body.parent = node;
return node;
}
TreeNode visitBlock(Block node) {
return saveContext(() {
BlockRewriter blockRewriter = rewriter = rewriter.forNestedBlock(node);
if (node.parent is Statement &&
isLoop(node.parent) &&
context is! NoContext) {
context = context.toNestedContext();
}
blockRewriter.transformStatements(this);
return node;
});
}
TreeNode visitVariableDeclaration(VariableDeclaration node) {
node.transformChildren(this);
if (!capturedVariables.contains(node)) return node;
if (node.initializer == null && node.parent is FunctionNode) {
// If the variable is a function parameter and doesn't have an
// initializer, just use this variable name to put it into the context.
context.extend(node, new VariableGet(node));
} else {
context.extend(node, node.initializer ?? new NullLiteral());
}
if (node.parent == currentFunction) {
return node;
} else {
assert(node.parent is Block);
// When returning null, the parent block will remove
// this node from its list of statements.
return null;
}
}
TreeNode visitVariableGet(VariableGet node) {
return capturedVariables.contains(node.variable)
? context.lookup(node.variable)
: node;
}
TreeNode visitVariableSet(VariableSet node) {
node.transformChildren(this);
return capturedVariables.contains(node.variable)
? context.assign(node.variable, node.value,
voidContext: isInVoidContext(node))
: node;
}
bool isInVoidContext(Expression node) {
TreeNode parent = node.parent;
return parent is ExpressionStatement ||
parent is ForStatement && parent.condition != node;
}
DartType visitDartType(DartType node) {
return substitute(node, typeSubstitution);
}
VariableDeclaration getReplacementLoopVariable(VariableDeclaration variable) {
VariableDeclaration newVariable = new VariableDeclaration(variable.name,
initializer: variable.initializer, type: variable.type)
..flags = variable.flags;
variable.initializer = new VariableGet(newVariable);
variable.initializer.parent = variable;
return newVariable;
}
Expression cloneContext() {
InvalidExpression placeHolder = new InvalidExpression(null);
contextClonePlaceHolders.add(placeHolder);
return placeHolder;
}
TreeNode visitInvalidExpression(InvalidExpression node) {
return contextClonePlaceHolders.remove(node) ? context.clone() : node;
}
TreeNode visitForStatement(ForStatement node) {
if (node.variables.any(capturedVariables.contains)) {
// In Dart, loop variables are new variables on each iteration of the
// loop. This is only observable when a loop variable is captured by a
// closure, which is the situation we're in here. So we transform the
// loop.
//
// Consider the following example, where `x` is `node.variables.first`,
// and `#t1` is a temporary variable:
//
// for (var x = 0; x < 10; x++) body;
//
// This is transformed to:
//
// {
// var x = 0;
// for (; x < 10; clone-context, x++) body;
// }
//
// `clone-context` is a place-holder that will later be replaced by an
// expression that clones the current closure context (see
// [visitInvalidExpression]).
return saveContext(() {
context = context.toNestedContext();
List<Statement> statements = <Statement>[];
statements.addAll(node.variables);
statements.add(node);
node.variables.clear();
node.updates.insert(0, cloneContext());
Block block = new Block(statements);
rewriter = new BlockRewriter(block);
return block.accept(this);
});
}
return super.visitForStatement(node);
}
TreeNode visitForInStatement(ForInStatement node) {
if (capturedVariables.contains(node.variable)) {
// In Dart, loop variables are new variables on each iteration of the
// loop. This is only observable when the loop variable is captured by a
// closure, so we need to transform the for-in loop when `node.variable`
// is captured.
//
// Consider the following example, where `x` is `node.variable`, and
// `#t1` is a temporary variable:
//
// for (var x in expr) body;
//
// Notice that we can assume that `x` doesn't have an initializer based
// on invariants in the Kernel AST. This is transformed to:
//
// for (var #t1 in expr) { var x = #t1; body; }
//
// After this, we call super to apply the normal closure conversion to
// the transformed for-in loop.
VariableDeclaration variable = node.variable;
VariableDeclaration newVariable = getReplacementLoopVariable(variable);
node.variable = newVariable;
newVariable.parent = node;
node.body = new Block(<Statement>[variable, node.body]);
node.body.parent = node;
}
return super.visitForInStatement(node);
}
TreeNode visitThisExpression(ThisExpression node) {
return isOuterMostContext
? node
: context.lookup(thisAccess[currentMemberFunction]);
}
TreeNode visitCatch(Catch node) {
VariableDeclaration exception = node.exception;
VariableDeclaration stackTrace = node.stackTrace;
if (stackTrace != null && capturedVariables.contains(stackTrace)) {
Block block = node.body = ensureBlock(node.body);
block.parent = node;
node.stackTrace = new VariableDeclaration(null);
node.stackTrace.parent = node;
stackTrace.initializer = new VariableGet(node.stackTrace);
block.statements.insert(0, stackTrace);
stackTrace.parent = block;
}
if (exception != null && capturedVariables.contains(exception)) {
Block block = node.body = ensureBlock(node.body);
block.parent = node;
node.exception = new VariableDeclaration(null);
node.exception.parent = node;
exception.initializer = new VariableGet(node.exception);
block.statements.insert(0, exception);
exception.parent = block;
}
return super.visitCatch(node);
}
Block ensureBlock(Statement statement) {
return statement is Block ? statement : new Block(<Statement>[statement]);
}
/// Creates a function that has the same signature as `procedure.function`
/// and which forwards all arguments to `procedure`.
FunctionNode forwardFunction(
Procedure procedure,
VariableDeclaration receiver,
VariableDeclaration contextVariable,
Map<TypeParameter, DartType> substitution) {
CloneVisitor cloner = substitution.isEmpty
? this.cloner
: new CloneWithoutBody(typeSubstitution: substitution);
FunctionNode function = procedure.function;
List<TypeParameter> typeParameters =
function.typeParameters.map(cloner.clone).toList();
List<VariableDeclaration> positionalParameters =
function.positionalParameters.map(cloner.clone).toList();
if (contextVariable != null) {
positionalParameters.insert(0, contextVariable);
}
List<VariableDeclaration> namedParameters =
function.namedParameters.map(cloner.clone).toList();
List<DartType> types = typeParameters
.map((TypeParameter parameter) => new TypeParameterType(parameter))
.toList();
List<Expression> positional = positionalParameters
.map((VariableDeclaration parameter) => new VariableGet(parameter))
.toList();
if (contextVariable != null) {
positional.removeAt(0);
}
List<NamedExpression> named =
namedParameters.map((VariableDeclaration parameter) {
return new NamedExpression(parameter.name, new VariableGet(parameter));
}).toList();
Arguments arguments = new Arguments(positional, types: types, named: named);
InvocationExpression invocation = procedure.isInstanceMember
? new MethodInvocation(
context.lookup(receiver), procedure.name, arguments, procedure)
: new StaticInvocation(procedure, arguments);
int requiredParameterCount = function.requiredParameterCount;
if (contextVariable != null) {
++requiredParameterCount;
}
return new FunctionNode(new ReturnStatement(invocation),
typeParameters: typeParameters,
positionalParameters: positionalParameters,
namedParameters: namedParameters,
requiredParameterCount: requiredParameterCount,
returnType: substitute(function.returnType, cloner.typeSubstitution));
}
/// Creates copies of the type variables in [original] and returns a
/// substitution that can be passed to [substitute] to substitute all uses of
/// [original] with their copies.
///
Map<TypeParameter, DartType> copyTypeVariables(
Iterable<TypeParameter> original) {
if (original.isEmpty) return const <TypeParameter, DartType>{};
Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{};
for (TypeParameter t in original) {
substitution[t] = new TypeParameterType(new TypeParameter(t.name));
}
substitution.forEach((TypeParameter t, DartType copy) {
if (copy is TypeParameterType) {
copy.parameter.bound = substitute(t.bound, substitution);
}
});
return substitution;
}
String createNameForClosedTopLevelFunction(FunctionNode function) {
return 'closure#${localNames[function]}';
}
Statement forwardToThisProperty(Member node) {
assert(node is Field || (node is Procedure && node.isGetter));
return new ReturnStatement(
new PropertyGet(new ThisExpression(), node.name, node));
}
void addFieldForwarder(Name name, Field field) {
newClassMembers.add(new Procedure(name, ProcedureKind.Getter,
new FunctionNode(forwardToThisProperty(field)),
fileUri: currentFileUri));
}
Procedure copyWithBody(Procedure procedure, Statement body) {
Procedure copy = cloner.clone(procedure);
copy.function.body = body;
copy.function.body.parent = copy.function;
return copy;
}
void addGetterForwarder(Name name, Procedure getter) {
assert(getter.isGetter);
newClassMembers
.add(copyWithBody(getter, forwardToThisProperty(getter))..name = name);
}
}

View File

@ -1,260 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library kernel.transformations.closure.info;
import '../../ast.dart'
show
Class,
Constructor,
Field,
FunctionDeclaration,
FunctionNode,
Member,
Procedure,
ThisExpression,
TypeParameter,
TypeParameterType,
VariableDeclaration,
VariableGet,
VariableSet,
visitList;
import '../../visitor.dart' show RecursiveVisitor;
class ClosureInfo extends RecursiveVisitor {
FunctionNode currentFunction;
final Set<VariableDeclaration> variables = new Set<VariableDeclaration>();
// For captured constructor parameters, we need to distinquish the following
// states:
//
// - only used inside initializers (INSIDE_INITIALIZER)
// - only used in body (OUTSIDE_INITIALIZER)
// - used in body and initializers (OUTSIDE_INITIALIZER | INSIDE_INITIALIZER)
static const int OUTSIDE_INITIALIZER = 1;
static const int INSIDE_INITIALIZER = 2;
int captureFlags = OUTSIDE_INITIALIZER;
final Map<VariableDeclaration, int> parameterUses =
<VariableDeclaration, int>{};
final Map<VariableDeclaration, FunctionNode> function =
<VariableDeclaration, FunctionNode>{};
/// Map from functions to set of type variables captured within them.
final Map<FunctionNode, Set<TypeParameter>> typeVariables =
<FunctionNode, Set<TypeParameter>>{};
/// Map from members to synthetic variables for accessing `this` in a local
/// function.
final Map<FunctionNode, VariableDeclaration> thisAccess =
<FunctionNode, VariableDeclaration>{};
final Set<String> currentMemberLocalNames = new Set<String>();
final Map<FunctionNode, String> localNames = <FunctionNode, String>{};
Class currentClass;
Member currentMember;
FunctionNode currentMemberFunction;
bool get isOuterMostContext {
return currentFunction == null || currentMemberFunction == currentFunction;
}
void beginMember(Member member, [FunctionNode function]) {
currentMemberLocalNames.clear();
if (function != null) {
localNames[function] = computeUniqueLocalName(member.name.name);
}
currentMember = member;
currentMemberFunction = function;
}
void endMember() {
currentMember = null;
currentMemberFunction = null;
}
visitClass(Class node) {
currentClass = node;
super.visitClass(node);
currentClass = null;
}
visitConstructor(Constructor node) {
/// [currentFunction] should be set to [currentMemberFunction] before
/// visiting the [FunctionNode] of the constructor, because initializers may
/// use constructor parameters and it shouldn't be treated as capturing
/// them. Consider the following code:
///
/// class A {
/// int x;
/// A(int x) /* [x] is visible in initializers and body. */
/// : this.x = x { /* Initializer. */
/// /* Constructor body. */
/// }
/// }
///
/// Here the parameter shouldn't be captured into a context in the
/// initializer. However, [currentFunction] is `null` if not set, and
/// `function[node.variable]` in this case points to the [FunctionNode] of
/// the constructor (which is not `null`). It leads to `x` being treated as
/// captured, because it's seen as used outside of the function where it is
/// declared. In turn, it leads to unnecessary context creation and usage.
///
/// Another consideration is the order of visiting children of the
/// constructor: [node.function] should be visited before
/// [node.initializers], because [node.function] contains declarations of
/// the parameters that may be used in the initializers. If the nodes are
/// visited in another order, the encountered parameters in initializers
/// are treated as captured, because they are not yet associated with the
/// function.
beginMember(node, node.function);
saveCurrentFunction(() {
currentFunction = currentMemberFunction;
visitList(node.annotations, this);
node.name?.accept(this);
visitList(node.function.typeParameters, this);
visitList(node.function.positionalParameters, this);
visitList(node.function.namedParameters, this);
assert(captureFlags == OUTSIDE_INITIALIZER);
captureFlags = INSIDE_INITIALIZER;
visitList(node.initializers, this);
captureFlags = OUTSIDE_INITIALIZER;
for (var decl in node.function.positionalParameters) {
var use = parameterUses[decl];
if (use == 0) parameterUses.remove(decl);
}
for (var decl in node.function.namedParameters) {
var use = parameterUses[decl];
if (use == 0) parameterUses.remove(decl);
}
node.function.accept(this);
});
endMember();
}
visitProcedure(Procedure node) {
beginMember(node, node.function);
super.visitProcedure(node);
endMember();
}
visitField(Field node) {
beginMember(node);
super.visitField(node);
endMember();
}
String computeUniqueLocalName([String name]) {
if (name == null || name.isEmpty) {
name = "function";
}
if (currentFunction == null) {
if (currentMember != null) {
name = "${currentMember.name.name}#$name";
}
if (currentClass != null) {
name = "${currentClass.name}#$name";
}
} else {
name = "${localNames[currentFunction]}#$name";
}
int count = 1;
String candidate = name;
while (currentMemberLocalNames.contains(candidate)) {
candidate = "$name#${count++}";
}
currentMemberLocalNames.add(candidate);
return candidate;
}
visitFunctionDeclaration(FunctionDeclaration node) {
assert(!localNames.containsKey(node));
localNames[node.function] = computeUniqueLocalName(node.variable.name);
return super.visitFunctionDeclaration(node);
}
visitFunctionNode(FunctionNode node) {
localNames.putIfAbsent(node, computeUniqueLocalName);
saveCurrentFunction(() {
currentFunction = node;
node.visitChildren(this);
});
Set<TypeParameter> capturedTypeVariables = typeVariables[node];
if (capturedTypeVariables != null && !isOuterMostContext) {
// Propagate captured type variables to enclosing function.
typeVariables
.putIfAbsent(currentFunction, () => new Set<TypeParameter>())
.addAll(
// 't.parent == currentFunction' will be true if the type variable
// is defined by one of our type parameters.
capturedTypeVariables.where((t) => t.parent != currentFunction));
}
}
visitVariableDeclaration(VariableDeclaration node) {
function[node] = currentFunction;
node.visitChildren(this);
}
visitVariableGet(VariableGet node) {
if (function[node.variable] != currentFunction) {
variables.add(node.variable);
}
if (node.variable.parent.parent is Constructor) {
parameterUses.putIfAbsent(node.variable, () => 0);
parameterUses[node.variable] |= captureFlags;
}
node.visitChildren(this);
}
visitVariableSet(VariableSet node) {
if (function[node.variable] != currentFunction) {
variables.add(node.variable);
}
if (node.variable.parent.parent is Constructor) {
parameterUses.putIfAbsent(node.variable, () => 0);
parameterUses[node.variable] |= captureFlags;
}
node.visitChildren(this);
}
visitTypeParameterType(TypeParameterType node) {
if (!isOuterMostContext &&
node.parameter.parent != currentFunction &&
!node.parameter.isFunctionTypeTypeParameter) {
typeVariables
.putIfAbsent(currentFunction, () => new Set<TypeParameter>())
.add(node.parameter);
}
}
visitThisExpression(ThisExpression node) {
if (!isOuterMostContext) {
thisAccess.putIfAbsent(
currentMemberFunction, () => new VariableDeclaration("#self"));
}
}
saveCurrentFunction(void f()) {
var saved = currentFunction;
try {
f();
} finally {
currentFunction = saved;
}
}
}

View File

@ -1,27 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library kernel.transformations.closure.invalidate;
import '../../ast.dart';
class InvalidateClosures extends Transformer {
FunctionDeclaration visitFunctionDeclaration(FunctionDeclaration node) {
invalidate(node.function);
return node;
}
FunctionExpression visitFunctionExpression(FunctionExpression node) {
invalidate(node.function);
return node;
}
void invalidate(FunctionNode function) {
if (function.asyncMarker != AsyncMarker.Sync) return;
var position = function.location;
function.body = new ExpressionStatement(new Throw(
new StringLiteral("Calling unconverted closure at $position")))
..parent = function;
}
}

View File

@ -1,132 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library kernel.transformations.closure.rewriter;
import '../../ast.dart';
import 'converter.dart' show ClosureConverter;
/// Used by the [Context] to initialize and update the context variable
/// used to capture the variables closed over by functions.
abstract class AstRewriter {
/// The declared variable that holds the context.
VariableDeclaration contextDeclaration;
/// Expression that is used to initialize the vector representing the context.
/// It's [length] field is modified by the [extend] operation
VectorCreation vectorCreation;
/// Creates a new [AstRewriter] for a (nested) [Block].
BlockRewriter forNestedBlock(Block block);
/// Inserts an allocation of a context and initializes [contextDeclaration]
/// and [vectorCreation].
void insertContextDeclaration(Expression accessParent);
/// Inserts an expression or statement that extends the context.
void insertExtendContext(VectorSet extender);
/// Inserts an expression that sets a parameter to NULL, so we don't have
/// unnecessary references to it.
void insertZeroOutParameter(VariableDeclaration parameter);
void _createDeclaration() {
assert(contextDeclaration == null && vectorCreation == null);
// Context size is set to 2 initially, because the 0-th element of it holds
// the vector of type arguments that the VM creates, and the 1-st element
// works as a link to the parent context.
vectorCreation = new VectorCreation(2);
contextDeclaration = new VariableDeclaration.forValue(vectorCreation,
type: const DynamicType());
contextDeclaration.name = "#context";
}
}
/// Adds a local variable for the context and adds update [Statement]s to the
/// current block.
class BlockRewriter extends AstRewriter {
Block _currentBlock;
int _insertionIndex;
BlockRewriter(this._currentBlock) : _insertionIndex = 0;
BlockRewriter forNestedBlock(Block block) {
return _currentBlock != block ? new BlockRewriter(block) : this;
}
void transformStatements(ClosureConverter converter) {
while (_insertionIndex < _currentBlock.statements.length) {
var original = _currentBlock.statements[_insertionIndex];
var transformed = original.accept(converter);
assert(_currentBlock.statements[_insertionIndex] == original);
if (transformed == null) {
_currentBlock.statements.removeAt(_insertionIndex);
} else {
_currentBlock.statements[_insertionIndex++] = transformed;
transformed.parent = _currentBlock;
}
}
}
void _insertStatement(Statement statement) {
_currentBlock.statements.insert(_insertionIndex++, statement);
statement.parent = _currentBlock;
}
void insertContextDeclaration(Expression accessParent) {
_createDeclaration();
_insertStatement(contextDeclaration);
if (accessParent is! NullLiteral) {
// Index 1 of a context always points to the parent.
_insertStatement(new ExpressionStatement(
new VectorSet(new VariableGet(contextDeclaration), 1, accessParent)));
}
}
void insertExtendContext(VectorSet extender) {
_insertStatement(new ExpressionStatement(extender));
}
void insertZeroOutParameter(VariableDeclaration parameter) {
_insertStatement(
new ExpressionStatement(new VariableSet(parameter, new NullLiteral())));
}
}
class InitializerListRewriter extends AstRewriter {
final Constructor parentConstructor;
final List<Initializer> prefix = [];
InitializerListRewriter(this.parentConstructor);
@override
BlockRewriter forNestedBlock(Block block) {
return new BlockRewriter(block);
}
@override
void insertContextDeclaration(Expression accessParent) {
_createDeclaration();
var init = new LocalInitializer(contextDeclaration);
init.parent = parentConstructor;
prefix.add(init);
}
@override
void insertExtendContext(VectorSet extender) {
var init = new LocalInitializer(
new VariableDeclaration(null, initializer: extender));
init.parent = parentConstructor;
prefix.add(init);
}
@override
void insertZeroOutParameter(VariableDeclaration parameter) {
var init = new LocalInitializer(new VariableDeclaration(null,
initializer: new VariableSet(parameter, new NullLiteral())));
init.parent = parentConstructor;
prefix.add(init);
}
}

View File

@ -1,167 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// A library to help transform compounds and null-aware accessors into
/// let expressions.
library kernel.closure.variable_accessor;
import '../../ast.dart';
/// An [Accessor] represents a subexpression for which we can't yet build a
/// kernel [Expression] because we don't yet know the context in which it is
/// used.
///
/// Once the context is known, an [Accessor] can be converted into an
/// [Expression] by calling a "build" method.
///
/// For example, when building a kernel representation for `a[x] = b`, after
/// parsing `a[x]` but before parsing `= b`, we don't yet know whether to
/// generate an invocation of `operator[]` or `operator[]=`, so we generate an
/// [Accessor] object. Later, after `= b` is parsed, [buildAssignment] will be
/// called.
class VariableAccessor {
final int offset;
VariableDeclaration variable;
DartType promotedType;
VariableAccessor(this.variable, this.promotedType, this.offset);
// [builtBinary] and [builtGetter] capture the inner nodes. Used by
// dart2js+rasta for determining how subexpressions map to legacy dart2js Ast
// nodes. This will be removed once dart2js type analysis (aka inference) is
// reimplemented on kernel.
Expression builtBinary;
Expression builtGetter;
/// Builds an [Expression] representing a read from the accessor.
Expression buildSimpleRead() {
return _finish(_makeSimpleRead());
}
/// Builds an [Expression] representing an assignment with the accessor on
/// the LHS and [value] on the RHS.
///
/// The returned expression evaluates to the assigned value, unless
/// [voidContext] is true, in which case it may evaluate to anything.
Expression buildAssignment(Expression value, {bool voidContext: false}) {
return _finish(_makeSimpleWrite(value, voidContext));
}
/// Returns an [Expression] representing a null-aware assignment (`??=`) with
/// the accessor on the LHS and [value] on the RHS.
///
/// The returned expression evaluates to the assigned value, unless
/// [voidContext] is true, in which case it may evaluate to anything.
///
/// [type] is the static type of the RHS.
Expression buildNullAwareAssignment(Expression value, DartType type,
{bool voidContext: false}) {
if (voidContext) {
return _finish(new ConditionalExpression(_buildIsNull(_makeRead()),
_makeWrite(value, false), new NullLiteral(), type));
}
var tmp = new VariableDeclaration.forValue(_makeRead());
return _finish(_makeLet(
tmp,
new ConditionalExpression(_buildIsNull(new VariableGet(tmp)),
_makeWrite(value, false), new VariableGet(tmp), type)));
}
/// Returns an [Expression] representing a compound assignment (e.g. `+=`)
/// with the accessor on the LHS and [value] on the RHS.
Expression buildCompoundAssignment(Name binaryOperator, Expression value,
{int offset: TreeNode.noOffset,
bool voidContext: false,
Procedure interfaceTarget}) {
return _finish(_makeWrite(
builtBinary = _makeBinary(
_makeRead(), binaryOperator, interfaceTarget, value,
offset: offset),
voidContext));
}
/// Returns an [Expression] representing a pre-increment or pre-decrement
/// of the accessor.
Expression buildPrefixIncrement(Name binaryOperator,
{int offset: TreeNode.noOffset,
bool voidContext: false,
Procedure interfaceTarget}) {
return buildCompoundAssignment(binaryOperator, new IntLiteral(1),
offset: offset,
voidContext: voidContext,
interfaceTarget: interfaceTarget);
}
/// Returns an [Expression] representing a post-increment or post-decrement
/// of the accessor.
Expression buildPostfixIncrement(Name binaryOperator,
{int offset: TreeNode.noOffset,
bool voidContext: false,
Procedure interfaceTarget}) {
if (voidContext) {
return buildPrefixIncrement(binaryOperator,
offset: offset, voidContext: true, interfaceTarget: interfaceTarget);
}
var value = new VariableDeclaration.forValue(_makeRead());
valueAccess() => new VariableGet(value);
var dummy = new VariableDeclaration.forValue(_makeWrite(
builtBinary = _makeBinary(
valueAccess(), binaryOperator, interfaceTarget, new IntLiteral(1),
offset: offset),
true));
return _finish(_makeLet(value, _makeLet(dummy, valueAccess())));
}
Expression _makeSimpleRead() => _makeRead();
Expression _makeSimpleWrite(Expression value, bool voidContext) {
return _makeWrite(value, voidContext);
}
Expression _finish(Expression body) => body;
/// Returns an [Expression] representing a compile-time error.
makeInvalidRead() => new InvalidExpression(null);
/// Returns an [Expression] representing a compile-time error wrapping
/// [value].
///
/// The expression will be a compile-time error but will contain [value] as a
/// subexpression before the compile-time error.
makeInvalidWrite(Expression value) => _wrapInvalid(value);
_makeRead() => new VariableGet(variable, promotedType)..fileOffset = offset;
_makeWrite(Expression value, bool voidContext) {
return variable.isFinal || variable.isConst
? makeInvalidWrite(value)
: new VariableSet(variable, value)
..fileOffset = offset;
}
}
Expression _makeLet(VariableDeclaration variable, Expression body) {
if (variable == null) return body;
return new Let(variable, body);
}
Expression _makeBinary(
Expression left, Name operator, Procedure interfaceTarget, Expression right,
{int offset: TreeNode.noOffset}) {
return new MethodInvocation(
left, operator, new Arguments(<Expression>[right]), interfaceTarget)
..fileOffset = offset;
}
final Name _equalOperator = new Name('==');
Expression _buildIsNull(Expression value, {int offset: TreeNode.noOffset}) {
return _makeBinary(value, _equalOperator, null, new NullLiteral(),
offset: offset);
}
Expression _wrapInvalid(Expression e) {
return new Let(
new VariableDeclaration.forValue(e), new InvalidExpression(null));
}

View File

@ -1,40 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library kernel.transformations.closure_conversion;
import '../ast.dart' show Component, Library;
import '../core_types.dart' show CoreTypes;
import 'closure/converter.dart' show ClosureConverter;
import 'closure/info.dart' show ClosureInfo;
import 'closure/invalidate_closures.dart';
Component transformComponent(CoreTypes coreTypes, Component component) {
var info = new ClosureInfo();
info.visitComponent(component);
var convert = new ClosureConverter(coreTypes, info);
component = convert.visitComponent(component);
return new InvalidateClosures().visitComponent(component);
}
void transformLibraries(CoreTypes coreTypes, List<Library> libraries) {
var info = new ClosureInfo();
for (var library in libraries) {
info.visitLibrary(library);
}
var convert = new ClosureConverter(coreTypes, info);
for (int i = 0; i < libraries.length; i++) {
libraries[i] = convert.visitLibrary(libraries[i]);
}
var invalidator = new InvalidateClosures();
for (int i = 0; i < libraries.length; i++) {
invalidator.visitLibrary(libraries[i]);
}
}

View File

@ -1,3 +0,0 @@
# Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE.md file.

View File

@ -1,117 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
library test.kernel.closures.suite;
import 'dart:io' show File, Platform;
import 'dart:async' show Future;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:testing/testing.dart'
show Chain, ChainContext, Result, Step, runMe, StdioProcess;
import 'package:kernel/ast.dart' show Component, Library;
import 'package:kernel/target/targets.dart' show Target;
import 'package:front_end/src/fasta/testing/kernel_chain.dart'
show
Print,
MatchExpectation,
WriteDill,
ReadDill,
Verify,
Compile,
CompileContext;
import 'package:kernel/transformations/closure_conversion.dart'
as closure_conversion;
const String STRONG_MODE = " strong mode ";
class ClosureConversionContext extends ChainContext implements CompileContext {
final bool strongMode;
Target get target => null;
final List<Step> steps;
Component platform;
ClosureConversionContext(this.strongMode, bool updateExpectations)
: steps = <Step>[
const Compile(),
const Print(),
const Verify(true),
const ClosureConversion(),
const Print(),
const Verify(true),
new MatchExpectation(".expect",
updateExpectations: updateExpectations),
const WriteDill(),
const ReadDill(),
const Run(),
];
static Future<ClosureConversionContext> create(
Chain suite, Map<String, String> environment, bool strongMode) async {
bool updateExpectations = environment["updateExpectations"] == "true";
return new ClosureConversionContext(strongMode, updateExpectations);
}
}
Future<ClosureConversionContext> createContext(
Chain suite, Map<String, String> environment) async {
bool strongMode = environment.containsKey(STRONG_MODE);
environment["updateExpectations"] =
const String.fromEnvironment("updateExpectations");
return ClosureConversionContext.create(suite, environment, strongMode);
}
class ClosureConversion
extends Step<Component, Component, ClosureConversionContext> {
const ClosureConversion();
String get name => "closure conversion";
Future<Result<Component>> run(
Component component, ClosureConversionContext testContext) async {
try {
CoreTypes coreTypes = new CoreTypes(component);
Library library = component.libraries
.firstWhere((Library library) => library.importUri.scheme != "dart");
closure_conversion.transformLibraries(coreTypes, <Library>[library]);
return pass(component);
} catch (e, s) {
return crash(e, s);
}
}
}
class Run extends Step<Uri, int, ClosureConversionContext> {
const Run();
String get name => "run";
Future<Result<int>> run(Uri uri, ClosureConversionContext context) async {
final File generated = new File.fromUri(uri);
try {
Uri vm = Uri.base.resolveUri(new Uri.file(Platform.resolvedExecutable));
final StdioProcess process = await StdioProcess.run(vm.toFilePath(), [
"--reify",
"--reify_generic_functions",
"-c",
generated.path,
"Hello, World!"
]);
print(process.output);
return process.toResult();
} finally {
generated.parent.delete(recursive: true);
}
}
}
main(List<String> arguments) => runMe(arguments, createContext, "testing.json");

View File

@ -1,28 +0,0 @@
{
"":"Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file",
"":"for details. All rights reserved. Use of this source code is governed by a",
"":"BSD-style license that can be found in the LICENSE.md file.",
"packages": "../../../../.packages",
"suites": [
{
"name": "closures",
"kind": "Chain",
"source": "suite.dart",
"path": "../../testcases/closures/",
"status": "closures.status",
"pattern": [
"\\.dart$"
],
"exclude": [
"/test/closures/suite\\.dart$"
]
}
],
"analyze": {
"uris": [
"suite.dart"
],
"exclude": [
]
}
}

View File

@ -1,3 +0,0 @@
# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE.md file.

View File

@ -1,116 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
library test.kernel.closures.suite;
import 'dart:async' show Future;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:testing/testing.dart'
show Chain, ChainContext, Result, Step, runMe;
import 'package:kernel/ast.dart' show Component, Library;
import 'package:kernel/transformations/argument_extraction.dart'
as argument_extraction;
import 'package:kernel/target/targets.dart' show Target;
import 'package:kernel/transformations/closure_conversion.dart'
as closure_conversion;
import 'package:front_end/src/fasta/testing/kernel_chain.dart'
show
Compile,
CompileContext,
Print,
MatchExpectation,
WriteDill,
ReadDill,
Verify;
const String STRONG_MODE = " strong mode ";
class ClosureConversionContext extends ChainContext implements CompileContext {
final bool strongMode;
Target get target => null;
final List<Step> steps;
ClosureConversionContext(this.strongMode, bool updateExpectations)
: steps = <Step>[
const Compile(),
const Print(),
const Verify(true),
const ArgumentExtraction(),
const Print(),
const Verify(true),
const ClosureConversion(),
const Print(),
const Verify(true),
new MatchExpectation(".expect",
updateExpectations: updateExpectations),
const WriteDill(),
const ReadDill(),
// TODO(29143): add `Run` step when Vectors are added to VM.
];
static Future<ClosureConversionContext> create(
Chain suite, Map<String, String> environment) async {
bool strongMode = environment.containsKey(STRONG_MODE);
bool updateExpectations = environment["updateExpectations"] == "true";
return new ClosureConversionContext(strongMode, updateExpectations);
}
}
Future<ClosureConversionContext> createContext(
Chain suite, Map<String, String> environment) async {
environment["updateExpectations"] =
const String.fromEnvironment("updateExpectations");
return ClosureConversionContext.create(suite, environment);
}
class ArgumentExtraction
extends Step<Component, Component, ClosureConversionContext> {
const ArgumentExtraction();
String get name => "argument extraction";
Future<Result<Component>> run(
Component component, ClosureConversionContext context) async {
try {
CoreTypes coreTypes = new CoreTypes(component);
Library library = component.libraries
.firstWhere((Library library) => library.importUri.scheme != "dart");
argument_extraction.transformLibraries(coreTypes, <Library>[library]);
return pass(component);
} catch (e, s) {
return crash(e, s);
}
}
}
class ClosureConversion
extends Step<Component, Component, ClosureConversionContext> {
const ClosureConversion();
String get name => "closure conversion";
Future<Result<Component>> run(
Component component, ClosureConversionContext testContext) async {
try {
CoreTypes coreTypes = new CoreTypes(component);
Library library = component.libraries
.firstWhere((Library library) => library.importUri.scheme != "dart");
closure_conversion.transformLibraries(coreTypes, <Library>[library]);
return pass(component);
} catch (e, s) {
return crash(e, s);
}
}
}
main(List<String> arguments) => runMe(arguments, createContext, "testing.json");

View File

@ -1,28 +0,0 @@
{
"":"Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file",
"":"for details. All rights reserved. Use of this source code is governed by a",
"":"BSD-style license that can be found in the LICENSE.md file.",
"packages": "../../../../.packages",
"suites": [
{
"name": "closures_initializers",
"kind": "Chain",
"source": "suite.dart",
"path": "../../testcases/closures_initializers/",
"status": "closures_initializers.status",
"pattern": [
"\\.dart$"
],
"exclude": [
"/test/closures_initializers/suite\\.dart$"
]
}
],
"analyze": {
"uris": [
"suite.dart"
],
"exclude": [
]
}
}

View File

@ -1,15 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
library test.kernel.closures_test;
import 'package:test/test.dart' show Timeout, test;
import 'package:testing/testing.dart' show run;
main() {
test("closures",
() => run([], ["closures"], "pkg/kernel/test/closures/testing.json"),
timeout: new Timeout(new Duration(minutes: 5)));
}

View File

@ -1,3 +0,0 @@
# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE.md file.

View File

@ -1,19 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
library test.kernel.closures_type_vars.suite;
import 'dart:async' show Future;
import 'package:testing/testing.dart' show Chain, runMe;
import '../closures/suite.dart' show ClosureConversionContext;
Future<ClosureConversionContext> createContext(
Chain suite, Map<String, String> environment) async {
environment["updateExpectations"] =
const String.fromEnvironment("updateExpectations");
return ClosureConversionContext.create(
suite, environment, true /*strongMode*/);
}
main(List<String> arguments) => runMe(arguments, createContext, "testing.json");

View File

@ -1,28 +0,0 @@
{
"":"Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file",
"":"for details. All rights reserved. Use of this source code is governed by a",
"":"BSD-style license that can be found in the LICENSE.md file.",
"packages": "../../../../.packages",
"suites": [
{
"name": "closures_type_vars",
"kind": "Chain",
"source": "suite.dart",
"path": "../../testcases/closures_type_vars/",
"status": "closures_type_vars.status",
"pattern": [
"\\.dart$"
],
"exclude": [
"/test/closures_type_vars/suite\\.dart$"
]
}
],
"analyze": {
"uris": [
"suite.dart"
],
"exclude": [
]
}
}

View File

@ -1,9 +0,0 @@
<!--
Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
for details. All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
-->
# Running tests
export DART_AOT_SDK=.../xcodebuild/DerivedSources/DebugX64/patched_sdk
dart -c --packages=.packages package:testing/src/run_tests.dart test/closures/testing.json

View File

@ -1,28 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// Test that closures check their argument count.
//
main() {
var closures = [
(x, y, [z]) {},
(x, y, z) {},
(x, y, {z}) {},
(x, y, z, w, v) {}
];
for (var c in closures) {
bool ok = false;
try {
c(1, 2, 3, 4);
} on NoSuchMethodError catch (_) {
ok = true;
}
if (!ok) {
throw new Exception("Expected an error!");
}
}
(x, y, [z]) {}(1, 2);
(x, y, [z]) {}(1, 2, 3);
}

View File

@ -1,27 +0,0 @@
library;
import self as self;
import "dart:core" as core;
static method main() → dynamic {
dynamic closures = <dynamic>[MakeClosure<(dynamic, dynamic, [dynamic]) → dynamic>(self::closure#main#function, null), MakeClosure<(dynamic, dynamic, dynamic) → dynamic>(self::closure#main#function#1, null), MakeClosure<(dynamic, dynamic, {z: dynamic}) → dynamic>(self::closure#main#function#2, null), MakeClosure<(dynamic, dynamic, dynamic, dynamic, dynamic) → dynamic>(self::closure#main#function#3, null)];
for (dynamic c in closures) {
core::bool ok = false;
try {
c.call(1, 2, 3, 4);
}
on core::NoSuchMethodError catch(final core::NoSuchMethodError _) {
ok = true;
}
if(!ok) {
throw core::Exception::•("Expected an error!");
}
}
(MakeClosure<(dynamic, dynamic, [dynamic]) → dynamic>(self::closure#main#function#4, null)).call(1, 2);
(MakeClosure<(dynamic, dynamic, [dynamic]) → dynamic>(self::closure#main#function#5, null)).call(1, 2, 3);
}
static method closure#main#function(dynamic #contextParameter, dynamic x, dynamic y, [dynamic z]) → dynamic {}
static method closure#main#function#1(dynamic #contextParameter, dynamic x, dynamic y, dynamic z) → dynamic {}
static method closure#main#function#2(dynamic #contextParameter, dynamic x, dynamic y, {dynamic z}) → dynamic {}
static method closure#main#function#3(dynamic #contextParameter, dynamic x, dynamic y, dynamic z, dynamic w, dynamic v) → dynamic {}
static method closure#main#function#4(dynamic #contextParameter, dynamic x, dynamic y, [dynamic z]) → dynamic {}
static method closure#main#function#5(dynamic #contextParameter, dynamic x, dynamic y, [dynamic z]) → dynamic {}

View File

@ -1,52 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// This test checks that we don't create duplicate local contexts in the same
// function. It's modeled after the 'startIsolateMock' function which was broken
// in the standard library.
class X {}
typedef dynamic fn(dynamic x);
typedef dynamic fn2(dynamic x, dynamic y);
void startIsolateMock(
dynamic parentPort,
dynamic entryPoint,
dynamic args,
dynamic message,
dynamic isSpawnUri,
dynamic controlPort,
List<dynamic> capabilities) {
if (controlPort != null) {
controlPort.handler = (dynamic _) {};
}
if (parentPort != null) {
dynamic readyMessage = new List<dynamic>(2);
readyMessage[0] = controlPort.sendPort;
readyMessage[1] = capabilities;
capabilities = null;
parentPort.send(readyMessage);
}
assert(capabilities == null);
dynamic port = "abc";
port.handler = (dynamic _) {
port.close();
if (isSpawnUri) {
if (entryPoint is fn2) {
entryPoint.call(args, message);
} else if (entryPoint is fn) {
entryPoint.call(args);
} else {
entryPoint.call();
}
} else {
entryPoint.call(message);
}
};
port.sendPort.send(null);
}
main() {
// No code here -- we just check that duplicate contexts aren't created above.
}

View File

@ -1,56 +0,0 @@
library;
import self as self;
import "dart:core" as core;
typedef fn = (dynamic) → dynamic;
typedef fn2 = (dynamic, dynamic) → dynamic;
class X extends core::Object {
synthetic constructor •() → void
: super core::Object::•()
;
}
static method startIsolateMock(dynamic parentPort, dynamic entryPoint, dynamic args, dynamic message, dynamic isSpawnUri, dynamic controlPort, core::List<dynamic> capabilities) → void {
final dynamic #context = MakeVector(7);
#context[2] = entryPoint;
entryPoint = null;
#context[3] = args;
args = null;
#context[4] = message;
message = null;
#context[5] = isSpawnUri;
isSpawnUri = null;
if(!controlPort.==(null)) {
controlPort.handler = MakeClosure<(dynamic) → dynamic>(self::closure#startIsolateMock#function, #context);
}
if(!parentPort.==(null)) {
dynamic readyMessage = core::List::_internal<dynamic>(2);
readyMessage.[]=(0, controlPort.sendPort);
readyMessage.[]=(1, capabilities);
capabilities = null;
parentPort.send(readyMessage);
}
assert(capabilities.==(null));
#context[6] = "abc";
(#context[6]).handler = MakeClosure<(dynamic) → dynamic>(self::closure#startIsolateMock#function#1, #context);
(#context[6]).sendPort.send(null);
}
static method main() → dynamic {}
static method closure#startIsolateMock#function(dynamic #contextParameter, dynamic _) → dynamic {}
static method closure#startIsolateMock#function#1(dynamic #contextParameter, dynamic _) → dynamic {
(#contextParameter[6]).close();
if(#contextParameter[5]) {
if((#contextParameter[2]) is (dynamic, dynamic) → dynamic) {
(#contextParameter[2]).call(#contextParameter[3], #contextParameter[4]);
}
else
if((#contextParameter[2]) is (dynamic) → dynamic) {
(#contextParameter[2]).call(#contextParameter[3]);
}
else {
(#contextParameter[2]).call();
}
}
else {
(#contextParameter[2]).call(#contextParameter[4]);
}
}

View File

@ -1,9 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
main(arguments) {
f() => null;
g() => f();
g();
}

View File

@ -1,15 +0,0 @@
library;
import self as self;
static method main(dynamic arguments) → dynamic {
final dynamic #context = MakeVector(3);
#context[2] = MakeClosure<() → dynamic>(self::closure#main#f, #context);
final () → dynamic g = MakeClosure<() → dynamic>(self::closure#main#g, #context);
g.call();
}
static method closure#main#f(dynamic #contextParameter) → dynamic {
return null;
}
static method closure#main#g(dynamic #contextParameter) → dynamic {
return (#contextParameter[2]).call();
}

View File

@ -1,15 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
main(List<String> arguments) {
foo(x) {
bar() {
print(x);
}
return bar;
}
foo(arguments[0])();
}

View File

@ -1,19 +0,0 @@
library;
import self as self;
import "dart:core" as core;
static method main(core::List<core::String> arguments) → dynamic {
final (dynamic) → dynamic foo = MakeClosure<(dynamic) → dynamic>(self::closure#main#foo, null);
foo.call(arguments.[](0)).call();
}
static method closure#main#foo#bar(dynamic #contextParameter) → dynamic {
core::print(#contextParameter[2]);
}
static method closure#main#foo(dynamic #contextParameter, dynamic x) → dynamic {
final dynamic #context = MakeVector(3);
#context[1] = #contextParameter;
#context[2] = x;
x = null;
final () → dynamic bar = MakeClosure<() → dynamic>(self::closure#main#foo#bar, #context);
return bar;
}

View File

@ -1,18 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
class C {
var x;
m() => (v) => x = v;
f() => () => () => x;
}
main() {
C c = new C();
c.x = 41;
c.m()(42);
if (42 != c.x) throw "Unexpected value in c.x: ${c.x}";
var result = c.f()()();
if (42 != result) throw "Unexpected value from c.f()()(): $result";
}

View File

@ -1,39 +0,0 @@
library;
import self as self;
import "dart:core" as core;
class C extends core::Object {
field dynamic x = null;
synthetic constructor •() → void
: super core::Object::•()
;
method m() → dynamic {
final dynamic #context = MakeVector(3);
#context[2] = this;
return MakeClosure<(dynamic) → dynamic>(self::closure#C#m#function, #context);
}
method f() → dynamic {
final dynamic #context = MakeVector(3);
#context[2] = this;
return MakeClosure<() → dynamic>(self::closure#C#f#function, #context);
}
}
static method main() → dynamic {
self::C c = new self::C::•();
c.x = 41;
c.m().call(42);
if(!42.==(c.x))
throw "Unexpected value in c.x: ${c.x}";
dynamic result = c.f().call().call();
if(!42.==(result))
throw "Unexpected value from c.f()()(): ${result}";
}
static method closure#C#m#function(dynamic #contextParameter, dynamic v) → dynamic {
return (#contextParameter[2]).x = v;
}
static method closure#C#f#function#function(dynamic #contextParameter) → dynamic {
return (#contextParameter[2]).x;
}
static method closure#C#f#function(dynamic #contextParameter) → dynamic {
return MakeClosure<() → dynamic>(self::closure#C#f#function#function, #contextParameter);
}

View File

@ -1,16 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
class Isgen<B> {
getfn() {
return (x) => x is B;
}
}
main() {
int x = 3;
var isgen = new Isgen<String>();
var iser = isgen.getfn();
assert(!iser(x));
}

View File

@ -1,21 +0,0 @@
library;
import self as self;
import "dart:core" as core;
class Isgen<B extends core::Object> extends core::Object {
synthetic constructor •() → void
: super core::Object::•()
;
method getfn() → dynamic {
return MakeClosure<<B extends core::Object>(dynamic) → dynamic, self::Isgen::B>(self::closure#Isgen#getfn#function, MakeVector(1));
}
}
static method main() → dynamic {
core::int x = 3;
dynamic isgen = new self::Isgen::•<core::String>();
dynamic iser = isgen.getfn();
assert(!iser.call(x));
}
static method closure#Isgen#getfn#function<B extends core::Object>(dynamic #contextParameter, dynamic x) → dynamic {
return x is self::closure#Isgen#getfn#function::B;
}

View File

@ -1,17 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
main() {
var c;
try {
throw "Fisk";
} on String catch (e, s) {
c = () {
print(e);
if (s != null) print(s);
};
}
c();
print("TEST PASSED");
}

View File

@ -1,23 +0,0 @@
library;
import self as self;
import "dart:core" as core;
static method main() → dynamic {
dynamic c;
try {
throw "Fisk";
}
on core::String catch(dynamic #t1, dynamic #t2) {
final dynamic #context = MakeVector(4);
#context[2] = #t1;
#context[3] = #t2;
c = MakeClosure<() → dynamic>(self::closure#main#function, #context);
}
c.call();
core::print("TEST PASSED");
}
static method closure#main#function(dynamic #contextParameter) → dynamic {
core::print(#contextParameter[2]);
if(!(#contextParameter[3]).==(null))
core::print(#contextParameter[3]);
}

View File

@ -1,20 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
class C1 {
var x;
C1(y) : x = (() => print('Hello $y'));
}
class C2 {
var x;
C2(y) {
x = () => print('Hello $y');
}
}
main() {
new C1('hest').x();
new C2('naebdyr').x();
}

View File

@ -1,30 +0,0 @@
library;
import self as self;
import "dart:core" as core;
class C1 extends core::Object {
field dynamic x;
constructor •(dynamic y) → void
: final dynamic #context = MakeVector(3), dynamic #t1 = #context[2] = y, dynamic #t2 = y = null, self::C1::x = MakeClosure<() → dynamic>(self::closure#C1#function#function, #context), super core::Object::•()
;
}
class C2 extends core::Object {
field dynamic x = null;
constructor •(dynamic y) → void
: super core::Object::•() {
final dynamic #context = MakeVector(3);
#context[2] = y;
y = null;
this.x = MakeClosure<() → dynamic>(self::closure#C2#function#function, #context);
}
}
static method main() → dynamic {
new self::C1::•("hest").x();
new self::C2::•("naebdyr").x();
}
static method closure#C1#function#function(dynamic #contextParameter) → dynamic {
return core::print("Hello ${#contextParameter[2]}");
}
static method closure#C2#function#function(dynamic #contextParameter) → dynamic {
return core::print("Hello ${#contextParameter[2]}");
}

View File

@ -1,19 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
class C {
var t;
C.foo(f, x) : t = (() => f(x)) {
x = 1;
print(x);
}
}
main() {
print(0);
var c = new C.foo((x) => print('hest${x}'), 0);
print(2);
c.t();
print(3);
}

View File

@ -1,28 +0,0 @@
library;
import self as self;
import "dart:core" as core;
class C extends core::Object {
field dynamic t;
constructor foo(dynamic f, dynamic x) → void
: final dynamic #context = MakeVector(4), this self::C::foo#redir(f, x, #context)
;
constructor foo#redir(dynamic f, dynamic x, final dynamic #context) → void
: dynamic #t1 = #context[2] = f, dynamic #t2 = f = null, dynamic #t3 = #context[3] = x, dynamic #t4 = x = null, self::C::t = MakeClosure<() → dynamic>(self::closure#C#foo#function, #context), super core::Object::•() {
#context[3] = 1;
core::print(#context[3]);
}
}
static method main() → dynamic {
core::print(0);
dynamic c = new self::C::foo(MakeClosure<(dynamic) → dynamic>(self::closure#main#function, null), 0);
core::print(2);
c.t();
core::print(3);
}
static method closure#C#foo#function(dynamic #contextParameter) → dynamic {
return (#contextParameter[2]).call(#contextParameter[3]);
}
static method closure#main#function(dynamic #contextParameter, dynamic x) → dynamic {
return core::print("hest${x}");
}

View File

@ -1,26 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
class C {
var t;
C.foo(f)
: t = (() {
var prefix;
var g = (x) {
f("$prefix$x");
};
prefix = 'hest';
return g;
}) {
print(1);
}
}
main() {
print(0);
var c = new C.foo((x) => print(x));
print(2);
c.t()('fisk');
print(3);
}

View File

@ -1,32 +0,0 @@
library;
import self as self;
import "dart:core" as core;
class C extends core::Object {
field dynamic t;
constructor foo(dynamic f) → void
: final dynamic #context = MakeVector(3), dynamic #t1 = #context[2] = f, dynamic #t2 = f = null, self::C::t = MakeClosure<() → dynamic>(self::closure#C#foo#function, #context), super core::Object::•() {
core::print(1);
}
}
static method main() → dynamic {
core::print(0);
dynamic c = new self::C::foo(MakeClosure<(dynamic) → dynamic>(self::closure#main#function, null));
core::print(2);
c.t().call("fisk");
core::print(3);
}
static method closure#C#foo#function#function(dynamic #contextParameter, dynamic x) → dynamic {
(#contextParameter[1][2]).call("${#contextParameter[2]}${x}");
}
static method closure#C#foo#function(dynamic #contextParameter) → dynamic {
final dynamic #context = MakeVector(3);
#context[1] = #contextParameter;
#context[2] = null;
dynamic g = MakeClosure<(dynamic) → dynamic>(self::closure#C#foo#function#function, #context);
#context[2] = "hest";
return g;
}
static method closure#main#function(dynamic #contextParameter, dynamic x) → dynamic {
return core::print(x);
}

View File

@ -1,55 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
//
// This tests checks that the runtime types of converted closures are asessed
// correctly in is-tests.
class C<T> {
void getf() {
T fn(T x) {
return x;
}
;
return fn;
}
}
typedef void ct(int x);
void test_c() {
var x = new C<int>().getf();
assert(x is ct);
var y = new C<String>().getf();
assert(y is! ct);
}
class D<T> {
void getf<S>() {
T fn(S y) {
return null;
}
return fn;
}
}
typedef String dt(int x);
void test_d() {
var x = new D<String>().getf<int>();
assert(x is dt);
var y = new D<int>().getf<int>();
assert(y is! dt);
var z = new D<int>().getf<String>();
assert(z is! dt);
}
main() {
test_c();
test_d();
}

View File

@ -1,49 +0,0 @@
library;
import self as self;
import "dart:core" as core;
typedef ct = (core::int) → void;
typedef dt = (core::int) → core::String;
class C<T extends core::Object> extends core::Object {
synthetic constructor •() → void
: super core::Object::•()
;
method getf() → void {
final (self::C::T) → self::C::T fn = MakeClosure<<T extends core::Object>(T) → T, self::C::T>(self::closure#C#getf#fn, MakeVector(1));
;
return fn;
}
}
class D<T extends core::Object> extends core::Object {
synthetic constructor •() → void
: super core::Object::•()
;
method getf() → void {
final (dynamic) → self::D::T fn = MakeClosure<<T extends core::Object>(dynamic) → T, self::D::T>(self::closure#D#getf#fn, MakeVector(1));
return fn;
}
}
static method test_c() → void {
dynamic x = new self::C::•<core::int>().getf();
assert(x is (core::int) → void);
dynamic y = new self::C::•<core::String>().getf();
assert(!(y is (core::int) → void));
}
static method test_d() → void {
dynamic x = new self::D::•<core::String>().getf();
assert(x is (core::int) → core::String);
dynamic y = new self::D::•<core::int>().getf();
assert(!(y is (core::int) → core::String));
dynamic z = new self::D::•<core::int>().getf();
assert(!(z is (core::int) → core::String));
}
static method main() → dynamic {
self::test_c();
self::test_d();
}
static method closure#C#getf#fn<T extends core::Object>(dynamic #contextParameter, self::closure#C#getf#fn::T x) → self::closure#C#getf#fn::T {
return x;
}
static method closure#D#getf#fn<T extends core::Object>(dynamic #contextParameter, dynamic y) → self::closure#D#getf#fn::T {
return null;
}

View File

@ -1,14 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
var f;
foo() {
print(f(0));
}
main(arguments) {
f = (x) => arguments[x];
foo();
}

View File

@ -1,18 +0,0 @@
library;
import self as self;
import "dart:core" as core;
static field dynamic f;
static method foo() → dynamic {
core::print(self::f.call(0));
}
static method main(dynamic arguments) → dynamic {
final dynamic #context = MakeVector(3);
#context[2] = arguments;
arguments = null;
self::f = MakeClosure<(dynamic) → dynamic>(self::closure#main#function, #context);
self::foo();
}
static method closure#main#function(dynamic #contextParameter, dynamic x) → dynamic {
return (#contextParameter[2]).[](x);
}

View File

@ -1,31 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// The purpose of this test is to detect that no unnecessary contexts are
// created when a constructor parameter is used in its field initializers. No
// contexts should be created either in the initializer or in the constructor
// body.
class X {}
class A {
X x;
A(this.x) {}
}
class B {
X x;
B(X x) : x = x {
fn() {
print(x);
}
fn();
}
}
main() {
A a = new A(new X());
B b = new B(new X());
}

View File

@ -1,32 +0,0 @@
library;
import self as self;
import "dart:core" as core;
class X extends core::Object {
synthetic constructor •() → void
: super core::Object::•()
;
}
class A extends core::Object {
field self::X x;
constructor •(self::X x) → void
: self::A::x = x, super core::Object::•() {}
}
class B extends core::Object {
field self::X x;
constructor •(self::X x) → void
: final dynamic #context = MakeVector(3), this self::B::#redir(x, #context)
;
constructor #redir(self::X x, final dynamic #context) → void
: dynamic #t1 = #context[2] = x, dynamic #t2 = x = null, self::B::x = #context[2], super core::Object::•() {
final () → dynamic fn = MakeClosure<() → dynamic>(self::closure#B#function#fn, #context);
fn.call();
}
}
static method main() → dynamic {
self::A a = new self::A::•(new self::X::•());
self::B b = new self::B::•(new self::X::•());
}
static method closure#B#function#fn(dynamic #contextParameter) → dynamic {
core::print(#contextParameter[2]);
}

View File

@ -1,26 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// The purpose of this test is to detect that no unnecessary contexts are
// created when a constructor parameter is used in its super initializer. No
// contexts should be created either in the initializer list or in the
// constructor body.
class X {}
class Y {}
class A {
X x;
Y y;
A(this.x, this.y);
}
class B extends A {
B(X x, Y y) : super(x, y) {}
}
main() {
B b = new B(new X(), new Y());
}

View File

@ -1,28 +0,0 @@
library;
import self as self;
import "dart:core" as core;
class X extends core::Object {
synthetic constructor •() → void
: super core::Object::•()
;
}
class Y extends core::Object {
synthetic constructor •() → void
: super core::Object::•()
;
}
class A extends core::Object {
field self::X x;
field self::Y y;
constructor •(self::X x, self::Y y) → void
: self::A::x = x, self::A::y = y, super core::Object::•()
;
}
class B extends self::A {
constructor •(self::X x, self::Y y) → void
: super self::A::•(x, y) {}
}
static method main() → dynamic {
self::B b = new self::B::•(new self::X::•(), new self::Y::•());
}

View File

@ -1,25 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
var x = () => "x";
class C<T> {
var v = (x) => x is T;
final y = () => "y";
static final z = () => "z";
}
main() {
if (!new C<String>().v("")) throw "C<String>.v false on String";
if (new C<String>().v(0)) throw "C<String>.v true on int";
if (new C<String>().v(null)) throw "C<String>.v true on null";
if (new C<int>().v("")) throw "C<int>.v true on String";
if (!new C<int>().v(0)) throw "C<int>.v false on int";
if (new C<int>().v(null)) throw "C<int>.v true on null";
if ("x" != x()) throw "x";
if ("y" != new C<String>().y()) throw "y";
if ("z" != C.z()) throw "z";
}

View File

@ -1,45 +0,0 @@
library;
import self as self;
import "dart:core" as core;
class C<T extends core::Object> extends core::Object {
field dynamic v = MakeClosure<<T extends core::Object>(dynamic) → dynamic, self::C::T>(self::closure#C#v#function, MakeVector(1));
final field dynamic y = MakeClosure<() → dynamic>(self::closure#C#y#function, null);
static final field dynamic z = MakeClosure<() → dynamic>(self::closure#C#z#function, null);
synthetic constructor •() → void
: super core::Object::•()
;
}
static field dynamic x = MakeClosure<() → dynamic>(self::closure#x#function, null);
static method main() → dynamic {
if(!new self::C::•<core::String>().v(""))
throw "C<String>.v false on String";
if(new self::C::•<core::String>().v(0))
throw "C<String>.v true on int";
if(new self::C::•<core::String>().v(null))
throw "C<String>.v true on null";
if(new self::C::•<core::int>().v(""))
throw "C<int>.v true on String";
if(!new self::C::•<core::int>().v(0))
throw "C<int>.v false on int";
if(new self::C::•<core::int>().v(null))
throw "C<int>.v true on null";
if(!"x".==(self::x.call()))
throw "x";
if(!"y".==(new self::C::•<core::String>().y()))
throw "y";
if(!"z".==(self::C::z.call()))
throw "z";
}
static method closure#C#v#function<T extends core::Object>(dynamic #contextParameter, dynamic x) → dynamic {
return x is self::closure#C#v#function::T;
}
static method closure#C#y#function(dynamic #contextParameter) → dynamic {
return "y";
}
static method closure#C#z#function(dynamic #contextParameter) → dynamic {
return "z";
}
static method closure#x#function(dynamic #contextParameter) → dynamic {
return "x";
}

View File

@ -1,22 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
const numbers = const <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
main() {
var closures = [];
var captured_outside = 0;
for (int i in numbers) {
closures.add(() => i + captured_outside);
}
int sum = 0;
for (Function f in closures) {
sum += f();
}
// This formula is credited to Gauss. Search for "Gauss adding 1 to 100".
int expectedSum = (numbers.length - 1) * numbers.length ~/ 2;
if (expectedSum != sum) {
throw new Exception("Unexpected sum = $sum != $expectedSum");
}
}

View File

@ -1,29 +0,0 @@
library;
import self as self;
import "dart:core" as core;
static const field dynamic numbers = const <core::int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
static method main() → dynamic {
dynamic closures = <dynamic>[];
final dynamic #context = MakeVector(3);
#context[2] = 0;
for (core::int i in self::numbers) {
final dynamic #context = MakeVector(3);
#context[1] = #context;
#context[2] = i;
{
closures.add(MakeClosure<() → dynamic>(self::closure#main#function, #context));
}
}
core::int sum = 0;
for (core::Function f in closures) {
sum = sum.+(f.call());
}
core::int expectedSum = self::numbers.length.-(1).*(self::numbers.length).~/(2);
if(!expectedSum.==(sum)) {
throw core::Exception::•("Unexpected sum = ${sum} != ${expectedSum}");
}
}
static method closure#main#function(dynamic #contextParameter) → dynamic {
return (#contextParameter[2]).+(#contextParameter[1][2]);
}

View File

@ -1,29 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
const int max = 100;
main() {
var closures = [];
var closures2 = [];
var last;
for (int i = 0; i < max; i++) {
closures.add(() => last = i);
closures2.add(() {
if (last != max - 1) throw "last: $last != ${max - 1}";
});
}
int sum = 0;
for (Function f in closures) {
sum += f();
}
for (Function f in closures2) {
f();
}
// This formula is credited to Gauss. Search for "Gauss adding 1 to 100".
int expectedSum = (max - 1) * max ~/ 2;
if (expectedSum != sum) {
throw new Exception("Unexpected sum = $sum != $expectedSum");
}
}

View File

@ -1,38 +0,0 @@
library;
import self as self;
import "dart:core" as core;
static const field core::int max = 100;
static method main() → dynamic {
dynamic closures = <dynamic>[];
dynamic closures2 = <dynamic>[];
final dynamic #context = MakeVector(3);
#context[2] = null;
{
dynamic #context = MakeVector(3);
#context[1] = #context;
#context[2] = 0;
for (; (#context[2]).<(self::max); #context = CopyVector(#context), #context[2] = (#context[2]).+(1)) {
closures.add(MakeClosure<() → dynamic>(self::closure#main#function, #context));
closures2.add(MakeClosure<() → dynamic>(self::closure#main#function#1, #context));
}
}
core::int sum = 0;
for (core::Function f in closures) {
sum = sum.+(f.call());
}
for (core::Function f in closures2) {
f.call();
}
core::int expectedSum = self::max.-(1).*(self::max).~/(2);
if(!expectedSum.==(sum)) {
throw core::Exception::•("Unexpected sum = ${sum} != ${expectedSum}");
}
}
static method closure#main#function(dynamic #contextParameter) → dynamic {
return #contextParameter[1][2] = #contextParameter[2];
}
static method closure#main#function#1(dynamic #contextParameter) → dynamic {
if(!(#contextParameter[1][2]).==(self::max.-(1)))
throw "last: ${#contextParameter[1][2]} != ${self::max.-(1)}";
}

View File

@ -1,15 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
main() {
var closure;
for (var i = 0, fn = () => i; i < 3; i++) {
i += 1;
closure = fn;
}
var x = closure();
if (x != 1) {
throw "Expected 1, but got $x.";
}
}

View File

@ -1,22 +0,0 @@
library;
import self as self;
static method main() → dynamic {
dynamic closure;
{
dynamic #context = MakeVector(3);
#context[2] = 0;
dynamic fn = MakeClosure<() → dynamic>(self::closure#main#function, #context);
for (; (#context[2]).<(3); #context = CopyVector(#context), #context[2] = (#context[2]).+(1)) {
#context[2] = (#context[2]).+(1);
closure = fn;
}
}
dynamic x = closure.call();
if(!x.==(1)) {
throw "Expected 1, but got ${x}.";
}
}
static method closure#main#function(dynamic #contextParameter) → dynamic {
return #contextParameter[2];
}

View File

@ -1,65 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
class C {
var f = () => "f";
get g => (x) => "g($x)";
a() => "a";
b(x) => x;
c(x, [y = 2]) => x + y;
d(x, {y: 2}) => x + y;
}
/// This class doesn't use its type variable.
class D<T> {
var f = () => "f";
get g => (x) => "g($x)";
a() => "a";
b(x) => x;
c(x, [y = 2]) => x + y;
d(x, {y: 2}) => x + y;
}
/// This class uses its type variable.
class E<T> {
var f = () => "f";
get g => (T x) => "g($x)";
a() => "a";
b(T x) => x;
c(T x, [T y = 2]) => x + y;
d(T x, {T y: 2}) => x + y;
}
expect(expected, actual) {
print("Expecting '$expected' and got '$actual'");
if (expected != actual) {
print("Expected '$expected' but got '$actual'");
throw "Expected '$expected' but got '$actual'";
}
}
test(o) {
expect("f", o.f());
expect("f", (o.f)());
expect("g(42)", o.g(42));
expect("g(42)", (o.g)(42));
expect("a", o.a());
expect("a", (o.a)());
expect(42, o.b(42));
expect(42, (o.b)(42));
expect(42, o.c(40));
expect(42, (o.c)(40));
expect(87, o.c(80, 7));
expect(87, (o.c)(80, 7));
expect(42, o.d(40));
expect(42, (o.d)(40));
expect(87, o.d(80, y: 7));
expect(87, (o.d)(80, y: 7));
}
main(arguments) {
test(new C());
test(new D<int>());
test(new E<int>());
}

View File

@ -1,100 +0,0 @@
library;
import self as self;
import "dart:core" as core;
class C extends core::Object {
field dynamic f = MakeClosure<() → dynamic>(self::closure#C#f#function, null);
synthetic constructor •() → void
: super core::Object::•()
;
get g() → dynamic
return MakeClosure<(dynamic) → dynamic>(self::closure#C#g#function, null);
method a() → dynamic
return "a";
method b(dynamic x) → dynamic
return x;
method c(dynamic x, [dynamic y = 2]) → dynamic
return x.+(y);
method d(dynamic x, {dynamic y = 2}) → dynamic
return x.+(y);
}
class D<T extends core::Object> extends core::Object {
field dynamic f = MakeClosure<() → dynamic>(self::closure#D#f#function, null);
synthetic constructor •() → void
: super core::Object::•()
;
get g() → dynamic
return MakeClosure<(dynamic) → dynamic>(self::closure#D#g#function, null);
method a() → dynamic
return "a";
method b(dynamic x) → dynamic
return x;
method c(dynamic x, [dynamic y = 2]) → dynamic
return x.+(y);
method d(dynamic x, {dynamic y = 2}) → dynamic
return x.+(y);
}
class E<T extends core::Object> extends core::Object {
field dynamic f = MakeClosure<() → dynamic>(self::closure#E#f#function, null);
synthetic constructor •() → void
: super core::Object::•()
;
get g() → dynamic
return MakeClosure<<T extends core::Object>(T) → dynamic, self::E::T>(self::closure#E#g#function, MakeVector(1));
method a() → dynamic
return "a";
method b(self::E::T x) → dynamic
return x;
method c(self::E::T x, [self::E::T y = 2]) → dynamic
return x.+(y);
method d(self::E::T x, {self::E::T y = 2}) → dynamic
return x.+(y);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
core::print("Expecting '${expected}' and got '${actual}'");
if(!expected.==(actual)) {
core::print("Expected '${expected}' but got '${actual}'");
throw "Expected '${expected}' but got '${actual}'";
}
}
static method test(dynamic o) → dynamic {
self::expect("f", o.f());
self::expect("f", o.f.call());
self::expect("g(42)", o.g(42));
self::expect("g(42)", o.g.call(42));
self::expect("a", o.a());
self::expect("a", o.a.call());
self::expect(42, o.b(42));
self::expect(42, o.b.call(42));
self::expect(42, o.c(40));
self::expect(42, o.c.call(40));
self::expect(87, o.c(80, 7));
self::expect(87, o.c.call(80, 7));
self::expect(42, o.d(40));
self::expect(42, o.d.call(40));
self::expect(87, o.d(80, y: 7));
self::expect(87, o.d.call(80, y: 7));
}
static method main(dynamic arguments) → dynamic {
self::test(new self::C::•());
self::test(new self::D::•<core::int>());
self::test(new self::E::•<core::int>());
}
static method closure#C#g#function(dynamic #contextParameter, dynamic x) → dynamic {
return "g(${x})";
}
static method closure#C#f#function(dynamic #contextParameter) → dynamic {
return "f";
}
static method closure#D#g#function(dynamic #contextParameter, dynamic x) → dynamic {
return "g(${x})";
}
static method closure#D#f#function(dynamic #contextParameter) → dynamic {
return "f";
}
static method closure#E#g#function<T extends core::Object>(dynamic #contextParameter, self::closure#E#g#function::T x) → dynamic {
return "g(${x})";
}
static method closure#E#f#function(dynamic #contextParameter) → dynamic {
return "f";
}

View File

@ -1,30 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// Check that a variable declared and captured inside a loop is given a separate
// context for each iteration of the loop, so changes to the variable in
// subsequent iterations are not visible to closures capturing it in prior
// iterations.
void doit(int x) {
final int max = 10;
final double expectedSum = ((max - 1) * max) / 2;
int counter = 0;
var calls = [];
while (counter < max) {
int pos = counter;
calls.add(() => pos + x);
counter++;
}
double sum = 0.0;
for (var c in calls) sum += c();
if (sum != expectedSum)
throw new Exception("Unexpected sum = $sum != $expectedSum");
}
void main() {
doit(0);
}

View File

@ -1,31 +0,0 @@
library;
import self as self;
import "dart:core" as core;
static method doit(core::int x) → void {
final dynamic #context = MakeVector(3);
#context[2] = x;
x = null;
final core::int max = 10;
final core::double expectedSum = max.-(1).*(max)./(2);
core::int counter = 0;
dynamic calls = <dynamic>[];
while (counter.<(max)) {
final dynamic #context = MakeVector(3);
#context[1] = #context;
#context[2] = counter;
calls.add(MakeClosure<() → dynamic>(self::closure#doit#function, #context));
counter = counter.+(1);
}
core::double sum = 0.0;
for (dynamic c in calls)
sum = sum.+(c.call());
if(!sum.==(expectedSum))
throw core::Exception::•("Unexpected sum = ${sum} != ${expectedSum}");
}
static method main() → void {
self::doit(0);
}
static method closure#doit#function(dynamic #contextParameter) → dynamic {
return (#contextParameter[2]).+(#contextParameter[1][2]);
}

View File

@ -1,15 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
var f;
foo() {
print(f(0));
}
main(arguments) {
g(x) => arguments[x];
f = g;
foo();
}

View File

@ -1,19 +0,0 @@
library;
import self as self;
import "dart:core" as core;
static field dynamic f;
static method foo() → dynamic {
core::print(self::f.call(0));
}
static method main(dynamic arguments) → dynamic {
final dynamic #context = MakeVector(3);
#context[2] = arguments;
arguments = null;
final (dynamic) → dynamic g = MakeClosure<(dynamic) → dynamic>(self::closure#main#g, #context);
self::f = g;
self::foo();
}
static method closure#main#g(dynamic #contextParameter, dynamic x) → dynamic {
return (#contextParameter[2]).[](x);
}

View File

@ -1,28 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
var v;
main(arguments) {
var w;
((x) => v = w = x)(87);
if (v != 87) {
throw "Unexpected value in v: $v";
}
if (w != 87) {
throw "Unexpected value in w: $w";
}
v = true;
(() {
for (; w = v;) {
v = false;
}
})();
if (v != false) {
throw "Unexpected value in v: $v";
}
if (w != false) {
throw "Unexpected value in w: $w";
}
}

View File

@ -1,31 +0,0 @@
library;
import self as self;
static field dynamic v;
static method main(dynamic arguments) → dynamic {
final dynamic #context = MakeVector(3);
#context[2] = null;
(MakeClosure<(dynamic) → dynamic>(self::closure#main#function, #context)).call(87);
if(!self::v.==(87)) {
throw "Unexpected value in v: ${self::v}";
}
if(!(#context[2]).==(87)) {
throw "Unexpected value in w: ${#context[2]}";
}
self::v = true;
(MakeClosure<() → dynamic>(self::closure#main#function#1, #context)).call();
if(!self::v.==(false)) {
throw "Unexpected value in v: ${self::v}";
}
if(!(#context[2]).==(false)) {
throw "Unexpected value in w: ${#context[2]}";
}
}
static method closure#main#function(dynamic #contextParameter, dynamic x) → dynamic {
return self::v = #contextParameter[2] = x;
}
static method closure#main#function#1(dynamic #contextParameter) → dynamic {
for (; #contextParameter[2] = self::v; ) {
self::v = false;
}
}

View File

@ -1,48 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
f_1_1_no_default(a, [b]) => a + b;
f_1_1_default(a, [b = 2]) => a + b;
f_1_b_no_default(a, {b}) => a + b;
f_1_b_default(a, {b: 2}) => a + b;
test_1_1(Function f, bool hasDefault) {
var result = f(40, 2);
if (42 != result) throw "Unexpected result: $result";
test_1(f, hasDefault);
}
test_1_b(Function f, bool hasDefault) {
var result = f(40, b: 2);
if (42 != result) throw "Unexpected result: $result";
test_1(f, hasDefault);
}
test_1(Function f, bool hasDefault) {
var result = 0;
bool threw = true;
try {
result = f(40);
threw = false;
} catch (_) {
// Ignored.
}
if (hasDefault) {
if (threw) throw "Unexpected exception.";
if (42 != result) throw "Unexpected result: $result.";
} else {
if (!threw) throw "Expected exception missing.";
if (0 != result) throw "Unexpected result: $result.";
}
}
main(arguments) {
test_1_1(f_1_1_no_default, false);
test_1_1(f_1_1_default, true);
test_1_b(f_1_b_no_default, false);
test_1_b(f_1_b_default, true);
}

View File

@ -1,52 +0,0 @@
library;
import self as self;
import "dart:core" as core;
static method f_1_1_no_default(dynamic a, [dynamic b = null]) → dynamic
return a.+(b);
static method f_1_1_default(dynamic a, [dynamic b = 2]) → dynamic
return a.+(b);
static method f_1_b_no_default(dynamic a, {dynamic b = null}) → dynamic
return a.+(b);
static method f_1_b_default(dynamic a, {dynamic b = 2}) → dynamic
return a.+(b);
static method test_1_1(core::Function f, core::bool hasDefault) → dynamic {
dynamic result = f.call(40, 2);
if(!42.==(result))
throw "Unexpected result: ${result}";
self::test_1(f, hasDefault);
}
static method test_1_b(core::Function f, core::bool hasDefault) → dynamic {
dynamic result = f.call(40, b: 2);
if(!42.==(result))
throw "Unexpected result: ${result}";
self::test_1(f, hasDefault);
}
static method test_1(core::Function f, core::bool hasDefault) → dynamic {
dynamic result = 0;
core::bool threw = true;
try {
result = f.call(40);
threw = false;
}
on dynamic catch(final dynamic _) {
}
if(hasDefault) {
if(threw)
throw "Unexpected exception.";
if(!42.==(result))
throw "Unexpected result: ${result}.";
}
else {
if(!threw)
throw "Expected exception missing.";
if(!0.==(result))
throw "Unexpected result: ${result}.";
}
}
static method main(dynamic arguments) → dynamic {
self::test_1_1(self::f_1_1_no_default, false);
self::test_1_1(self::f_1_1_default, true);
self::test_1_b(self::f_1_b_no_default, false);
self::test_1_b(self::f_1_b_default, true);
}

View File

@ -1,24 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// This tests that the wrapper function around converted closures in the VM
// doesn't break when the context parameter is captured (since async
// transformations introduces an additional closure here).
range(int high) {
iter(int low) sync* {
while (high-- > low) yield high;
}
return iter;
}
main() {
var sum = 0;
for (var x in range(10)(2)) sum += x;
if (sum != 44) {
throw new Exception("Incorrect output.");
}
}

View File

@ -1,37 +0,0 @@
library;
import self as self;
import "dart:core" as core;
static method range(core::int high) → dynamic {
final dynamic #context = MakeVector(3);
#context[2] = high;
high = null;
final (core::int) → dynamic iter = MakeClosure<(core::int) → dynamic>(self::closure#range#iter, #context);
return iter;
}
static method main() → dynamic {
dynamic sum = 0;
for (dynamic x in self::range(10).call(2))
sum = sum.+(x);
if(!sum.==(44)) {
throw core::Exception::•("Incorrect output.");
}
}
static method closure#range#iter(dynamic #contextParameter, core::int low) → dynamic /* originally sync* */ {
final dynamic #context = MakeVector(3);
#context[1] = #contextParameter;
#context[2] = low;
low = null;
dynamic :await_jump_var = 0;
dynamic :await_ctx_var;
dynamic :sync_op = (core::Iterator<dynamic> :iterator) → core::bool yielding {
{
while ((let final dynamic #t1 = #contextParameter[2] in let final dynamic #t2 = #contextParameter[2] = #t1.-(1) in #t1).>(#context[2])) {
:iterator._current = #context[1][2];
[yield] true;
}
}
return false;
};
return new core::_SyncIterable::•(:sync_op);
}

View File

@ -1,22 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
const numbers = const <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
main() {
var closures = [];
for (int i in numbers) {
int j = i;
closures.add(() => j);
}
int sum = 0;
for (Function f in closures) {
sum += f();
}
// This formula is credited to Gauss. Search for "Gauss adding 1 to 100".
int expectedSum = (numbers.length - 1) * numbers.length ~/ 2;
if (expectedSum != sum) {
throw new Exception("Unexpected sum = $sum != $expectedSum");
}
}

View File

@ -1,24 +0,0 @@
library;
import self as self;
import "dart:core" as core;
static const field dynamic numbers = const <core::int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
static method main() → dynamic {
dynamic closures = <dynamic>[];
for (core::int i in self::numbers) {
final dynamic #context = MakeVector(3);
#context[2] = i;
closures.add(MakeClosure<() → dynamic>(self::closure#main#function, #context));
}
core::int sum = 0;
for (core::Function f in closures) {
sum = sum.+(f.call());
}
core::int expectedSum = self::numbers.length.-(1).*(self::numbers.length).~/(2);
if(!expectedSum.==(sum)) {
throw core::Exception::•("Unexpected sum = ${sum} != ${expectedSum}");
}
}
static method closure#main#function(dynamic #contextParameter) → dynamic {
return #contextParameter[2];
}

View File

@ -1,52 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// The purpose of this test is to detect that closures in [LocalInitializer]s
// and [FieldInitializer]s are properly converted. This test assumes that
// [ArgumentExtractionForTesting] transformer was run before closure conversion.
// It should introduce one [LocalInitializer] for each argument passed to a
// field initializer for a field ending in "_li". If such argument contains a
// closure, it would appear in a [LocalInitializer]. The [FieldInitializer]
// example requires no such elaboration.
class X {}
// Closure in field initializer.
//
class A {
X foo;
A(X i) : foo = ((() => i)());
}
// Closure in super initializer.
//
class S extends A {
S(X i) : super((() => i)());
}
// Closure in local initializer.
//
class S2 {
X foo_li;
S2(X foo) : foo_li = (() => foo)();
}
// Closure in redirecting initializer.
//
class B {
X foo;
B.named(X foo) {}
B(X foo) : this.named((() => foo)());
}
main() {
A a = new A(new X());
a.foo; // To prevent dartanalyzer from marking [a] as unused.
B b = new B(new X());
b.foo;
S s = new S(new X());
s.foo;
S2 s2 = new S2(new X());
s2.foo_li;
}

View File

@ -1,56 +0,0 @@
library;
import self as self;
import "dart:core" as core;
class X extends core::Object {
constructor •() → void
: super core::Object::•()
;
}
class A extends core::Object {
field self::X foo;
constructor •(self::X i) → void
: final Vector #context = MakeVector(2), dynamic #t1 = #context[1] = i, self::A::foo = (MakeClosure<() → dynamic>(self::closure#A#function#function, #context)).call(), super core::Object::•()
;
}
class S extends self::A {
constructor •(self::X i) → void
: final Vector #context = MakeVector(2), dynamic #t2 = #context[1] = i, super self::A::•((MakeClosure<() → dynamic>(self::closure#S#function#function, #context)).call())
;
}
class S2 extends core::Object {
field self::X foo_li;
constructor •(self::X foo) → void
: final Vector #context = MakeVector(2), dynamic #t3 = #context[1] = foo, dynamic #li_0 = (MakeClosure<() → dynamic>(self::closure#S2#function#function, #context)).call(), self::S2::foo_li = #li_0, super core::Object::•()
;
}
class B extends core::Object {
field self::X foo = null;
constructor named(self::X foo) → void
: super core::Object::•() {}
constructor •(self::X foo) → void
: final Vector #context = MakeVector(2), dynamic #t4 = #context[1] = foo, this self::B::named((MakeClosure<() → dynamic>(self::closure#B#function#function, #context)).call())
;
}
static method main() → dynamic {
self::A a = new self::A::•(new self::X::•());
a.foo;
self::B b = new self::B::•(new self::X::•());
b.foo;
self::S s = new self::S::•(new self::X::•());
s.foo;
self::S2 s2 = new self::S2::•(new self::X::•());
s2.foo_li;
}
static method closure#A#function#function(Vector #contextParameter) → dynamic {
return #contextParameter[1];
}
static method closure#S#function#function(Vector #contextParameter) → dynamic {
return #contextParameter[1];
}
static method closure#S2#function#function(Vector #contextParameter) → dynamic {
return #contextParameter[1];
}
static method closure#B#function#function(Vector #contextParameter) → dynamic {
return #contextParameter[1];
}

View File

@ -1,35 +0,0 @@
library;
import self as self;
import "dart:core" as core;
class X extends core::Object {
constructor •() → void
: super core::Object::•()
;
}
class A extends core::Object {
field self::X foo;
constructor •(self::X i) → void
: self::A::foo = let final Vector #context = MakeVector(2) in let dynamic #t1 = #context[1] = i in (MakeClosure<() → dynamic>(self::closure#A#function#function, #context)).call(), super core::Object::•()
;
}
class B extends core::Object {
field self::X foo = null;
constructor named(self::X foo) → void
: super core::Object::•() {}
constructor •(self::X foo) → void
: dynamic extracted#0 = let final Vector #context = MakeVector(2) in let dynamic #t2 = #context[1] = foo in (MakeClosure<() → dynamic>(self::closure#B#function#function, #context)).call(), this self::B::named(extracted#0)
;
}
static method main() → dynamic {
self::A a = new self::A::•(new self::X::•());
a.foo;
self::B b = new self::B::•(new self::X::•());
b.foo;
}
static method closure#A#function#function(Vector #contextParameter) → dynamic {
return #contextParameter[1];
}
static method closure#B#function#function(Vector #contextParameter) → dynamic {
return #contextParameter[1];
}

View File

@ -1,50 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
class C<T, S> {
foo(S s) => (T x) {
T y = x;
Object z = y;
C<T, S> self = this;
return z as T;
};
bar() {
C<T, S> self = this;
}
baz() {
return () => () => new C<T, S>();
}
factory C() {
local() {
C<T, S> self = new C<T, S>.internal();
return self;
}
return local();
}
C.internal();
}
fn<A>(A x) {
var fn2 = (A x2) {
var l = <A>[];
l.add(x2);
return l;
};
return fn2(x);
}
main(arguments) {
print(new C<String, String>().foo(null)(arguments.first));
dynamic c = new C<int, int>().baz()()();
if (c is! C<int, int>) throw "$c fails type test 'is C<int, int>'";
if (c is C<String, String>) {
throw "$c passes type test 'is C<String, String>'";
}
print(c);
print(fn<int>(3));
}

View File

@ -1,60 +0,0 @@
library;
import self as self;
import "dart:core" as core;
class C<T extends core::Object, S extends core::Object> extends core::Object {
constructor internal() → void
: super core::Object::•()
;
method foo(self::C::S s) → dynamic {
final Vector #context = MakeVector(3);
#context[2] = this;
return MakeClosure<<T extends core::Object, S extends core::Object>(T) → T, self::C::T, self::C::S>(self::closure#C#foo#function, #context);
}
method bar() → dynamic {
self::C<self::C::T, self::C::S> self = this;
}
method baz() → dynamic {
return MakeClosure<<T extends core::Object, S extends core::Object>() → () → self::C<T, S>, self::C::T, self::C::S>(self::closure#C#baz#function, MakeVector(1));
}
static factory •<T extends core::Object, S extends core::Object>() → self::C<self::C::•::T, self::C::•::S> {
final <T extends core::Object, S extends core::Object>() → self::C<self::C::•::T, self::C::•::S> local = MakeClosure<<T extends core::Object, S extends core::Object>() → self::C<T, S>, self::C::•::T, self::C::•::S>(self::closure#C#function#local, MakeVector(1));
return local.call();
}
}
static method fn<A extends core::Object>(self::fn::A x) → dynamic {
<A extends core::Object>(self::fn::A) → core::List<self::fn::A> fn2 = MakeClosure<<A extends core::Object>(A) → core::List<A>, self::fn::A>(self::closure#fn#function, MakeVector(1));
return fn2.call(x);
}
static method main(dynamic arguments) → dynamic {
core::print(self::C::•<core::String, core::String>().{self::C::foo}(null).call(arguments.first));
dynamic c = self::C::•<core::int, core::int>().{self::C::baz}().call().call();
if(!(c is self::C<core::int, core::int>))
throw "${c} fails type test 'is C<int, int>'";
if(c is self::C<core::String, core::String>) {
throw "${c{self::C<core::String, core::String>}} passes type test 'is C<String, String>'";
}
core::print(c);
core::print(self::fn<core::int>(3));
}
static method closure#C#foo#function<T extends core::Object, S extends core::Object>(Vector #contextParameter, self::closure#C#foo#function::T x) → self::closure#C#foo#function::T {
self::closure#C#foo#function::T y = x;
core::Object z = y;
self::C<self::closure#C#foo#function::T, self::closure#C#foo#function::S> self = #contextParameter[2];
return z as self::closure#C#foo#function::T;
}
static method closure#C#baz#function#function<T extends core::Object, S extends core::Object>(Vector #contextParameter) → self::C<self::closure#C#baz#function#function::T, self::closure#C#baz#function#function::S> {
return self::C::•<self::closure#C#baz#function#function::T, self::closure#C#baz#function#function::S>();
}
static method closure#C#baz#function<T extends core::Object, S extends core::Object>(Vector #contextParameter) → () → self::C<self::closure#C#baz#function::T, self::closure#C#baz#function::S> {
return MakeClosure<<T extends core::Object, S extends core::Object>() → self::C<T, S>, self::closure#C#baz#function::T, self::closure#C#baz#function::S>(self::closure#C#baz#function#function, #contextParameter);
}
static method closure#C#function#local<T extends core::Object, S extends core::Object>(Vector #contextParameter) → self::C<self::closure#C#function#local::T, self::closure#C#function#local::S> {
self::C<self::closure#C#function#local::T, self::closure#C#function#local::S> self = new self::C::internal<self::closure#C#function#local::T, self::closure#C#function#local::S>();
return self;
}
static method closure#fn#function<A extends core::Object>(Vector #contextParameter, self::closure#fn#function::A x2) → core::List<self::closure#fn#function::A> {
core::List<self::closure#fn#function::A> l = <self::closure#fn#function::A>[];
l.{core::List::add}(x2);
return l;
}