From ff0c3936a108343b0c7b88d6c4e46356a7a37fdf Mon Sep 17 00:00:00 2001 From: Samir Jindel Date: Wed, 26 Jul 2017 13:22:41 +0200 Subject: [PATCH] Revert "Revert "Preserve type variables in closure conversion."" This reverts commit fd4a0c658feec81fa7dbc01a6d6abb81f5e6e623. --- pkg/kernel/binary.md | 1 + pkg/kernel/lib/ast.dart | 15 ++-- pkg/kernel/lib/binary/ast_from_binary.dart | 3 +- pkg/kernel/lib/binary/ast_to_binary.dart | 1 + pkg/kernel/lib/clone.dart | 3 +- pkg/kernel/lib/text/ast_to_text.dart | 2 + .../transformations/closure/converter.dart | 77 +++++++++---------- .../lib/transformations/closure/info.dart | 8 +- pkg/kernel/test/closures/closures.status | 15 ++++ pkg/kernel/test/closures/suite.dart | 6 +- .../closures_type_vars.status | 5 ++ pkg/kernel/test/closures_type_vars/suite.dart | 19 +++++ .../test/closures_type_vars/testing.json | 28 +++++++ .../testcases/closures/field.dart.expect | 6 +- .../closures/instance_tear_off.dart.expect | 4 +- .../closures/type_variables.dart.expect | 50 ------------ .../type_variables.dart | 10 +++ .../type_variables.dart.expect | 60 +++++++++++++++ runtime/vm/object.cc | 4 +- 19 files changed, 206 insertions(+), 111 deletions(-) create mode 100644 pkg/kernel/test/closures_type_vars/closures_type_vars.status create mode 100644 pkg/kernel/test/closures_type_vars/suite.dart create mode 100644 pkg/kernel/test/closures_type_vars/testing.json delete mode 100644 pkg/kernel/testcases/closures/type_variables.dart.expect rename pkg/kernel/testcases/{closures => closures_type_vars}/type_variables.dart (87%) create mode 100644 pkg/kernel/testcases/closures_type_vars/type_variables.dart.expect diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md index df216649eeb..840efa0ff7a 100644 --- a/pkg/kernel/binary.md +++ b/pkg/kernel/binary.md @@ -741,6 +741,7 @@ type ClosureCreation extends Expression { MemberReference topLevelFunctionReference; Expression contextVector; FunctionType functionType; + List typeArguments; } abstract type Statement extends Node {} diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart index 56c1f4ce16c..aa87ce43659 100644 --- a/pkg/kernel/lib/ast.dart +++ b/pkg/kernel/lib/ast.dart @@ -3080,14 +3080,15 @@ class ClosureCreation extends Expression { Reference topLevelFunctionReference; Expression contextVector; FunctionType functionType; + List typeArguments; ClosureCreation(Member topLevelFunction, Expression contextVector, - FunctionType functionType) - : this.byReference( - getMemberReference(topLevelFunction), contextVector, functionType); + FunctionType functionType, List typeArguments) + : this.byReference(getMemberReference(topLevelFunction), contextVector, + functionType, typeArguments); - ClosureCreation.byReference( - this.topLevelFunctionReference, this.contextVector, this.functionType) { + ClosureCreation.byReference(this.topLevelFunctionReference, + this.contextVector, this.functionType, this.typeArguments) { contextVector?.parent = this; } @@ -3102,6 +3103,8 @@ class ClosureCreation extends Expression { visitChildren(Visitor v) { contextVector?.accept(v); + functionType.accept(v); + visitList(typeArguments, v); } transformChildren(Transformer v) { @@ -3109,6 +3112,8 @@ class ClosureCreation extends Expression { contextVector = contextVector.accept(v); contextVector?.parent = this; } + functionType = v.visitDartType(functionType); + transformTypeList(typeArguments, v); } DartType getStaticType(TypeEnvironment types) { diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart index 8a602423bcc..47e398ae763 100644 --- a/pkg/kernel/lib/binary/ast_from_binary.dart +++ b/pkg/kernel/lib/binary/ast_from_binary.dart @@ -937,8 +937,9 @@ class BinaryBuilder { var topLevelFunctionReference = readMemberReference(); var contextVector = readExpression(); var functionType = readDartType(); + var typeArgs = readDartTypeList(); return new ClosureCreation.byReference( - topLevelFunctionReference, contextVector, functionType); + topLevelFunctionReference, contextVector, functionType, typeArgs); default: throw fail('Invalid expression tag: $tag'); } diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart index 28bb9fd936e..0462336e05b 100644 --- a/pkg/kernel/lib/binary/ast_to_binary.dart +++ b/pkg/kernel/lib/binary/ast_to_binary.dart @@ -872,6 +872,7 @@ class BinaryPrinter extends Visitor { writeReference(node.topLevelFunctionReference); writeNode(node.contextVector); writeNode(node.functionType); + writeNodeList(node.typeArguments); } writeStatementOrEmpty(Statement node) { diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart index 492c3ad84d2..4f1d6814865 100644 --- a/pkg/kernel/lib/clone.dart +++ b/pkg/kernel/lib/clone.dart @@ -235,7 +235,8 @@ class CloneVisitor extends TreeVisitor { return new ClosureCreation.byReference( node.topLevelFunctionReference, cloneOptional(node.contextVector), - visitOptionalType(node.functionType)); + visitOptionalType(node.functionType), + node.typeArguments.map(visitType).toList()); } visitVectorSet(VectorSet node) { diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart index 34376e91bb9..38edfc6bd41 100644 --- a/pkg/kernel/lib/text/ast_to_text.dart +++ b/pkg/kernel/lib/text/ast_to_text.dart @@ -1061,6 +1061,8 @@ class Printer extends Visitor { writeWord('MakeClosure'); writeSymbol('<'); writeNode(node.functionType); + if (node.typeArguments.length > 0) writeSymbol(', '); + writeList(node.typeArguments, writeType); writeSymbol('>'); writeSymbol('('); writeMemberReference(node.topLevelFunction); diff --git a/pkg/kernel/lib/transformations/closure/converter.dart b/pkg/kernel/lib/transformations/closure/converter.dart index 5ee224172f0..713ab38cdc6 100644 --- a/pkg/kernel/lib/transformations/closure/converter.dart +++ b/pkg/kernel/lib/transformations/closure/converter.dart @@ -13,7 +13,6 @@ import '../../ast.dart' ClosureCreation, Constructor, DartType, - DynamicType, EmptyStatement, Expression, ExpressionStatement, @@ -260,39 +259,12 @@ class ClosureConverter extends Transformer { context = context.toNestedContext( new VariableAccessor(contextVariable, null, TreeNode.noOffset)); - Set captured = capturedTypeVariables[currentFunction]; - if (captured != null) { - typeSubstitution = copyTypeVariables(captured); - } else { - typeSubstitution = const {}; - } + Set captured = + capturedTypeVariables[currentFunction] ?? new Set(); + typeSubstitution = copyTypeVariables(captured); - // TODO(29181): remove replacementTypeSubstitution variable and its usages. - // All the type variables used in this function body are replaced with - // either dynamic or their bounds. This is to temporarily remove the type - // variables from closure conversion. They should be returned after the VM - // changes are done to support vectors and closure creation. See #29181. - Map replacementTypeSubstitution = - {}; - for (TypeParameter parameter in typeSubstitution.keys) { - replacementTypeSubstitution[parameter] = const DynamicType(); - } - for (TypeParameter parameter in typeSubstitution.keys) { - if (!isObject(parameter.bound)) { - replacementTypeSubstitution[parameter] = - substitute(parameter.bound, replacementTypeSubstitution); - } - } - typeSubstitution = replacementTypeSubstitution; function.transformChildren(this); - // TODO(29181): don't replace typeSubstitution with an empty map. - // Information about captured type variables is deleted from the closure - // class, because the type variables in this function body are already - // replaced with either dynamic or their bounds. This change should be - // undone after the VM support for vectors and closure creation is - // implemented. See #29181. - typeSubstitution = {}; Expression result = addClosure(function, contextVariable, parent.expression, typeSubstitution, enclosingTypeSubstitution); currentFunction = enclosingFunction; @@ -322,9 +294,7 @@ class ClosureConverter extends Transformer { } TreeNode visitFunctionExpression(FunctionExpression node) { - return saveContext(() { - return handleLocalFunction(node.function); - }); + return saveContext(() => handleLocalFunction(node.function)); } /// Add a new procedure to the current library that looks like this: @@ -346,6 +316,16 @@ class ClosureConverter extends Transformer { Expression accessContext, Map substitution, Map enclosingTypeSubstitution) { + var fnTypeParams = []; + var fnTypeArgs = []; + 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( @@ -356,21 +336,29 @@ class ClosureConverter extends Transformer { 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 = []; + 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) => decl.type) - .toList(), - function.returnType, - namedParameters: function.namedParameters .map((VariableDeclaration decl) => - new NamedType(decl.name, decl.type)) + substitute(decl.type, closureTypeSubstitutionMap)) .toList(), - typeParameters: function.typeParameters, + 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); return new ClosureCreation( - closedTopLevelFunction, accessContext, closureType); + closedTopLevelFunction, accessContext, closureType, fnTypeArgs); } TreeNode visitProcedure(Procedure node) { @@ -664,14 +652,19 @@ class ClosureConverter extends Transformer { /// 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. + /// [original] with their copies. Additionally returns a list of new type + /// parameters to prefix to the enclosing function's type parameters and the + /// arguments to be passed for those parameters. + /// Map copyTypeVariables( Iterable original) { if (original.isEmpty) return const {}; + Map substitution = {}; 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); diff --git a/pkg/kernel/lib/transformations/closure/info.dart b/pkg/kernel/lib/transformations/closure/info.dart index 68b82c1dc5e..dd867f45f1d 100644 --- a/pkg/kernel/lib/transformations/closure/info.dart +++ b/pkg/kernel/lib/transformations/closure/info.dart @@ -30,6 +30,7 @@ class ClosureInfo extends RecursiveVisitor { final Set variables = new Set(); + /// Map from functions to set of type variables captured within them. final Map> typeVariables = >{}; @@ -166,7 +167,10 @@ class ClosureInfo extends RecursiveVisitor { // Propagate captured type variables to enclosing function. typeVariables .putIfAbsent(currentFunction, () => new Set()) - .addAll(capturedTypeVariables); + .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)); } } @@ -190,7 +194,7 @@ class ClosureInfo extends RecursiveVisitor { } visitTypeParameterType(TypeParameterType node) { - if (!isOuterMostContext) { + if (!isOuterMostContext && node.parameter.parent != currentFunction) { typeVariables .putIfAbsent(currentFunction, () => new Set()) .add(node.parameter); diff --git a/pkg/kernel/test/closures/closures.status b/pkg/kernel/test/closures/closures.status index 0d7343acb6a..938db582cf6 100644 --- a/pkg/kernel/test/closures/closures.status +++ b/pkg/kernel/test/closures/closures.status @@ -4,3 +4,18 @@ field: RuntimeError type_variables: RuntimeError +capture_closure: RuntimeError +capture_closure_parameter: RuntimeError +capture_this: RuntimeError +catch: RuntimeError +closure_in_constructor: RuntimeError +closure_in_initializer: RuntimeError +closure_in_initializer_closure: RuntimeError +closures: RuntimeError +for_in_closure: RuntimeError +for_loop: RuntimeError +for_variable_capture_test: RuntimeError +instance_tear_off: RuntimeError +named_closure: RuntimeError +non_void_context: RuntimeError +uncaptured_for_in_loop: RuntimeError diff --git a/pkg/kernel/test/closures/suite.dart b/pkg/kernel/test/closures/suite.dart index 10e9c7afe86..452eebbe6eb 100644 --- a/pkg/kernel/test/closures/suite.dart +++ b/pkg/kernel/test/closures/suite.dart @@ -59,8 +59,7 @@ class ClosureConversionContext extends ChainContext implements CompileContext { ]; static Future create( - Chain suite, Map environment) async { - bool strongMode = environment.containsKey(STRONG_MODE); + Chain suite, Map environment, bool strongMode) async { bool updateExpectations = environment["updateExpectations"] == "true"; return new ClosureConversionContext(strongMode, updateExpectations); } @@ -68,9 +67,10 @@ class ClosureConversionContext extends ChainContext implements CompileContext { Future createContext( Chain suite, Map environment) async { + bool strongMode = environment.containsKey(STRONG_MODE); environment["updateExpectations"] = const String.fromEnvironment("updateExpectations"); - return ClosureConversionContext.create(suite, environment); + return ClosureConversionContext.create(suite, environment, strongMode); } class ClosureConversion diff --git a/pkg/kernel/test/closures_type_vars/closures_type_vars.status b/pkg/kernel/test/closures_type_vars/closures_type_vars.status new file mode 100644 index 00000000000..99e87d160df --- /dev/null +++ b/pkg/kernel/test/closures_type_vars/closures_type_vars.status @@ -0,0 +1,5 @@ +# 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. + +type_variables: RuntimeError diff --git a/pkg/kernel/test/closures_type_vars/suite.dart b/pkg/kernel/test/closures_type_vars/suite.dart new file mode 100644 index 00000000000..866bf2c4041 --- /dev/null +++ b/pkg/kernel/test/closures_type_vars/suite.dart @@ -0,0 +1,19 @@ +// 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 createContext( + Chain suite, Map environment) async { + environment["updateExpectations"] = + const String.fromEnvironment("updateExpectations"); + return ClosureConversionContext.create( + suite, environment, true /*strongMode*/); +} + +main(List arguments) => runMe(arguments, createContext, "testing.json"); diff --git a/pkg/kernel/test/closures_type_vars/testing.json b/pkg/kernel/test/closures_type_vars/testing.json new file mode 100644 index 00000000000..f07231504fb --- /dev/null +++ b/pkg/kernel/test/closures_type_vars/testing.json @@ -0,0 +1,28 @@ +{ +"":"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": [ + ] + } +} diff --git a/pkg/kernel/testcases/closures/field.dart.expect b/pkg/kernel/testcases/closures/field.dart.expect index 9c5341006bd..2a519cf89c0 100644 --- a/pkg/kernel/testcases/closures/field.dart.expect +++ b/pkg/kernel/testcases/closures/field.dart.expect @@ -3,7 +3,7 @@ import self as self; import "dart:core" as core; class C extends core::Object { - field dynamic v = MakeClosure<(dynamic) → dynamic>(self::closure#C#v#function, null); + field dynamic v = MakeClosure<(dynamic) → dynamic, self::C::T>(self::closure#C#v#function, null); 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); default constructor •() → void @@ -31,8 +31,8 @@ static method main() → dynamic { if(!"z".==(self::C::z.call())) throw "z"; } -static method closure#C#v#function(Vector #contextParameter, dynamic x) → dynamic { - return x is dynamic; +static method closure#C#v#function(Vector #contextParameter, dynamic x) → dynamic { + return x is self::closure#C#v#function::T; } static method closure#C#y#function(Vector #contextParameter) → dynamic { return "y"; diff --git a/pkg/kernel/testcases/closures/instance_tear_off.dart.expect b/pkg/kernel/testcases/closures/instance_tear_off.dart.expect index 2d829774277..73609c79306 100644 --- a/pkg/kernel/testcases/closures/instance_tear_off.dart.expect +++ b/pkg/kernel/testcases/closures/instance_tear_off.dart.expect @@ -50,7 +50,7 @@ class E extends core::Object { : super core::Object::•() ; get g() → dynamic { - return MakeClosure<(dynamic) → dynamic>(self::closure#E#g#function, null); + return MakeClosure<(T) → dynamic, self::E::T>(self::closure#E#g#function, null); } method a() → dynamic { return "a"; @@ -107,7 +107,7 @@ static method closure#D#g#function(Vector #contextParameter, dynamic x) → dyna static method closure#D#f#function(Vector #contextParameter) → dynamic { return "f"; } -static method closure#E#g#function(Vector #contextParameter, dynamic x) → dynamic { +static method closure#E#g#function(Vector #contextParameter, self::closure#E#g#function::T x) → dynamic { return "g(${x})"; } static method closure#E#f#function(Vector #contextParameter) → dynamic { diff --git a/pkg/kernel/testcases/closures/type_variables.dart.expect b/pkg/kernel/testcases/closures/type_variables.dart.expect deleted file mode 100644 index 53170a283d2..00000000000 --- a/pkg/kernel/testcases/closures/type_variables.dart.expect +++ /dev/null @@ -1,50 +0,0 @@ -library; -import self as self; -import "dart:core" as core; - -class C extends core::Object { - constructor internal() → void - : super core::Object::•() - ; - method foo(self::C::S s) → dynamic { - final Vector #context = MakeVector(2); - #context[1] = this; - return MakeClosure<(dynamic) → dynamic>(self::closure#C#foo#function, #context); - } - method bar() → dynamic { - self::C self = this; - } - method baz() → dynamic { - return MakeClosure<() → dynamic>(self::closure#C#baz#function, null); - } - static factory •() → self::C { - final () → dynamic local = MakeClosure<() → dynamic>(self::closure#C#function#local, null); - return local.call(); - } -} -static method main(dynamic arguments) → dynamic { - core::print(self::C::•().foo(null).call(arguments.first)); - dynamic c = self::C::•().baz().call().call(); - if(!(c is self::C)) - throw "${c} fails type test 'is C'"; - if(c is self::C) { - throw "${c{self::C}} passes type test 'is C'"; - } - core::print(c); -} -static method closure#C#foo#function(Vector #contextParameter, dynamic x) → dynamic { - dynamic y = x; - core::Object z = y; - self::C self = #contextParameter[1]; - return z as dynamic; -} -static method closure#C#baz#function#function(Vector #contextParameter) → dynamic { - return self::C::•(); -} -static method closure#C#baz#function(Vector #contextParameter) → dynamic { - return MakeClosure<() → dynamic>(self::closure#C#baz#function#function, #contextParameter); -} -static method closure#C#function#local(Vector #contextParameter) → dynamic { - self::C self = new self::C::internal(); - return self; -} diff --git a/pkg/kernel/testcases/closures/type_variables.dart b/pkg/kernel/testcases/closures_type_vars/type_variables.dart similarity index 87% rename from pkg/kernel/testcases/closures/type_variables.dart rename to pkg/kernel/testcases/closures_type_vars/type_variables.dart index 5883e7372d6..2de2994f3f9 100644 --- a/pkg/kernel/testcases/closures/type_variables.dart +++ b/pkg/kernel/testcases/closures_type_vars/type_variables.dart @@ -29,6 +29,15 @@ class C { C.internal(); } +fn(A x) { + var fn2 = (A x2) { + var l = []; + l.add(x2); + return l; + }; + return fn2(x); +} + main(arguments) { print(new C().foo(null)(arguments.first)); dynamic c = new C().baz()()(); @@ -37,4 +46,5 @@ main(arguments) { throw "$c passes type test 'is C'"; } print(c); + print(fn(3)); } diff --git a/pkg/kernel/testcases/closures_type_vars/type_variables.dart.expect b/pkg/kernel/testcases/closures_type_vars/type_variables.dart.expect new file mode 100644 index 00000000000..7dcd6d9f762 --- /dev/null +++ b/pkg/kernel/testcases/closures_type_vars/type_variables.dart.expect @@ -0,0 +1,60 @@ +library; +import self as self; +import "dart:core" as core; + +class C extends core::Object { + constructor internal() → void + : super core::Object::•() + ; + method foo(self::C::S s) → dynamic { + final Vector #context = MakeVector(2); + #context[1] = this; + return MakeClosure<(T) → T, self::C::T, self::C::S>(self::closure#C#foo#function, #context); + } + method bar() → dynamic { + self::C self = this; + } + method baz() → dynamic { + return MakeClosure<() → () → self::C, self::C::T, self::C::S>(self::closure#C#baz#function, null); + } + static factory •() → self::C { + final () → self::C local = MakeClosure<() → self::C, self::C::•::T, self::C::•::S>(self::closure#C#function#local, null); + return local.call(); + } +} +static method fn(self::fn::A x) → dynamic { + (self::fn::A) → core::List fn2 = MakeClosure<(A) → core::List, self::fn::A>(self::closure#fn#function, null); + return fn2.call(x); +} +static method main(dynamic arguments) → dynamic { + core::print(self::C::•().{self::C::foo}(null).call(arguments.first)); + dynamic c = self::C::•().{self::C::baz}().call().call(); + if(!(c is self::C)) + throw "${c} fails type test 'is C'"; + if(c is self::C) { + throw "${c{self::C}} passes type test 'is C'"; + } + core::print(c); + core::print(self::fn(3)); +} +static method closure#C#foo#function(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 = #contextParameter[1]; + return z as self::closure#C#foo#function::T; +} +static method closure#C#baz#function#function(Vector #contextParameter) → self::C { + return self::C::•(); +} +static method closure#C#baz#function(Vector #contextParameter) → () → self::C { + return MakeClosure<() → self::C, 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(Vector #contextParameter) → self::C { + self::C self = new self::C::internal(); + return self; +} +static method closure#fn#function(Vector #contextParameter, self::closure#fn#function::A x2) → core::List { + core::List l = []; + l.{core::List::add}(x2); + return l; +} diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 1b53fdc204e..c5faed86ee9 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -6879,7 +6879,7 @@ void Function::DropUncompiledImplicitClosureFunction() const { // Converted closure functions are used in VM Closure instances that represent // the results of evaluation of [MakeClosure] primitive operations. // -// Internally, converted closure functins are represented with the same Closure +// Internally, converted closure functions are represented with the same Closure // class as implicit closure functions (that are used for dealing with // tear-offs). The Closure class instances have two fields, one for the // function, and one for the captured context. Implicit closure functions have @@ -6903,7 +6903,7 @@ void Function::DropUncompiledImplicitClosureFunction() const { // this way, is invoked, it should receive the [Vector] as the first argument, // and take the rest of the arguments from the invocation. // -// Converted cosure functions in VM follow same discipline as implicit closure +// Converted closure functions in VM follow same discipline as implicit closure // functions, because they are similar in many ways. For further deatils, please // refer to the following methods: // -> Function::ConvertedClosureFunction