mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +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:
parent
bc86dc1dd6
commit
02cd63eefd
|
@ -12,7 +12,6 @@ import 'package:kernel/core_types.dart';
|
||||||
import 'package:kernel/kernel.dart';
|
import 'package:kernel/kernel.dart';
|
||||||
import 'package:kernel/src/tool/batch_util.dart';
|
import 'package:kernel/src/tool/batch_util.dart';
|
||||||
import 'package:kernel/target/targets.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/constants.dart' as constants;
|
||||||
import 'package:kernel/transformations/continuation.dart' as cont;
|
import 'package:kernel/transformations/continuation.dart' as cont;
|
||||||
import 'package:kernel/transformations/empty.dart' as empty;
|
import 'package:kernel/transformations/empty.dart' as empty;
|
||||||
|
@ -94,9 +93,6 @@ Future<CompilerOutcome> runTransformation(List<String> arguments) async {
|
||||||
mix.transformLibraries(
|
mix.transformLibraries(
|
||||||
new NoneTarget(null), coreTypes, hierarchy, component.libraries);
|
new NoneTarget(null), coreTypes, hierarchy, component.libraries);
|
||||||
break;
|
break;
|
||||||
case 'closures':
|
|
||||||
component = closures.transformComponent(coreTypes, component);
|
|
||||||
break;
|
|
||||||
case 'coq':
|
case 'coq':
|
||||||
component = coq.transformComponent(coreTypes, component);
|
component = coq.transformComponent(coreTypes, component);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -9,7 +9,6 @@ import '../core_types.dart';
|
||||||
import '../transformations/treeshaker.dart' show ProgramRoot;
|
import '../transformations/treeshaker.dart' show ProgramRoot;
|
||||||
import 'flutter.dart' show FlutterTarget;
|
import 'flutter.dart' show FlutterTarget;
|
||||||
import 'vm.dart' show VmTarget;
|
import 'vm.dart' show VmTarget;
|
||||||
import 'vmcc.dart' show VmClosureConvertedTarget;
|
|
||||||
|
|
||||||
final List<String> targetNames = targets.keys.toList();
|
final List<String> targetNames = targets.keys.toList();
|
||||||
|
|
||||||
|
@ -35,7 +34,6 @@ typedef Target _TargetBuilder(TargetFlags flags);
|
||||||
final Map<String, _TargetBuilder> targets = <String, _TargetBuilder>{
|
final Map<String, _TargetBuilder> targets = <String, _TargetBuilder>{
|
||||||
'none': (TargetFlags flags) => new NoneTarget(flags),
|
'none': (TargetFlags flags) => new NoneTarget(flags),
|
||||||
'vm': (TargetFlags flags) => new VmTarget(flags),
|
'vm': (TargetFlags flags) => new VmTarget(flags),
|
||||||
'vmcc': (TargetFlags flags) => new VmClosureConvertedTarget(flags),
|
|
||||||
'flutter': (TargetFlags flags) => new FlutterTarget(flags),
|
'flutter': (TargetFlags flags) => new FlutterTarget(flags),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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.
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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));
|
|
||||||
}
|
|
|
@ -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]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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.
|
|
|
@ -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");
|
|
|
@ -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": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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.
|
|
|
@ -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");
|
|
|
@ -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": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)));
|
|
||||||
}
|
|
|
@ -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.
|
|
|
@ -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");
|
|
|
@ -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": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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 {}
|
|
|
@ -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.
|
|
||||||
}
|
|
|
@ -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]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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])();
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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";
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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));
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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");
|
|
||||||
}
|
|
|
@ -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]);
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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]}");
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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}");
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
|
@ -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]);
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
|
@ -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::•());
|
|
||||||
}
|
|
|
@ -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";
|
|
||||||
}
|
|
|
@ -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";
|
|
||||||
}
|
|
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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]);
|
|
||||||
}
|
|
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)}";
|
|
||||||
}
|
|
|
@ -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.";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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];
|
|
||||||
}
|
|
|
@ -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>());
|
|
||||||
}
|
|
|
@ -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";
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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]);
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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.");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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];
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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];
|
|
||||||
}
|
|
|
@ -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];
|
|
||||||
}
|
|
|
@ -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));
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
Loading…
Reference in a new issue