mirror of
https://github.com/dart-lang/sdk
synced 2024-07-08 12:06:26 +00:00
Remove unused closure conversion
Change-Id: I0edbbd29a4cc603e7479023bc0e8869c78ca7bcc Reviewed-on: https://dart-review.googlesource.com/54225 Commit-Queue: Peter von der Ahé <ahe@google.com> Reviewed-by: Samir Jindel <sjindel@google.com>
This commit is contained in:
parent
bc86dc1dd6
commit
02cd63eefd
|
@ -12,7 +12,6 @@ import 'package:kernel/core_types.dart';
|
|||
import 'package:kernel/kernel.dart';
|
||||
import 'package:kernel/src/tool/batch_util.dart';
|
||||
import 'package:kernel/target/targets.dart';
|
||||
import 'package:kernel/transformations/closure_conversion.dart' as closures;
|
||||
import 'package:kernel/transformations/constants.dart' as constants;
|
||||
import 'package:kernel/transformations/continuation.dart' as cont;
|
||||
import 'package:kernel/transformations/empty.dart' as empty;
|
||||
|
@ -94,9 +93,6 @@ Future<CompilerOutcome> runTransformation(List<String> arguments) async {
|
|||
mix.transformLibraries(
|
||||
new NoneTarget(null), coreTypes, hierarchy, component.libraries);
|
||||
break;
|
||||
case 'closures':
|
||||
component = closures.transformComponent(coreTypes, component);
|
||||
break;
|
||||
case 'coq':
|
||||
component = coq.transformComponent(coreTypes, component);
|
||||
break;
|
||||
|
|
|
@ -9,7 +9,6 @@ import '../core_types.dart';
|
|||
import '../transformations/treeshaker.dart' show ProgramRoot;
|
||||
import 'flutter.dart' show FlutterTarget;
|
||||
import 'vm.dart' show VmTarget;
|
||||
import 'vmcc.dart' show VmClosureConvertedTarget;
|
||||
|
||||
final List<String> targetNames = targets.keys.toList();
|
||||
|
||||
|
@ -35,7 +34,6 @@ typedef Target _TargetBuilder(TargetFlags flags);
|
|||
final Map<String, _TargetBuilder> targets = <String, _TargetBuilder>{
|
||||
'none': (TargetFlags flags) => new NoneTarget(flags),
|
||||
'vm': (TargetFlags flags) => new VmTarget(flags),
|
||||
'vmcc': (TargetFlags flags) => new VmClosureConvertedTarget(flags),
|
||||
'flutter': (TargetFlags flags) => new FlutterTarget(flags),
|
||||
};
|
||||
|
||||
|
|
|
@ -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 New Issue
Block a user