[vm/aot/tfa] Whole-program propagation of closure values
This change adds propagation of closure values to TFA.
For now, inferred closure values are used only when they are
constant (tear-off of a static method or a constructor).
Arbitrary closures can now be referenced from unrelated
members via closure-id metadata.
In addition, this change fixes an incorrect stack trace when
an implicit closure (tear-off) was propagated and its call was
inlined. Inlining interval was not recorded because of the missing
source position of a call to a target method within implicit closure.
TEST=pkg/vm/testcases/transformations/type_flow/transformer/closures.dart
Issue: https://github.com/dart-lang/sdk/issues/39692
Change-Id: I3590da91b6057e0b55a8614382dba1bbcc267b39
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/325447
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
diff --git a/pkg/dart2wasm/lib/target.dart b/pkg/dart2wasm/lib/target.dart
index b74e794..8757b9b 100644
--- a/pkg/dart2wasm/lib/target.dart
+++ b/pkg/dart2wasm/lib/target.dart
@@ -102,6 +102,7 @@
Class? _wasmImmutableSet;
Class? _oneByteString;
Class? _twoByteString;
+ Class? _closure;
Map<String, Class>? _nativeClasses;
@override
@@ -480,6 +481,11 @@
}
@override
+ Class concreteClosureClass(CoreTypes coreTypes) {
+ return _closure ??= coreTypes.index.getClass('dart:core', '_Closure');
+ }
+
+ @override
bool isSupportedPragma(String pragmaName) => pragmaName.startsWith("wasm:");
late final Map<RecordShape, Class> recordClasses;
diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart
index 1f1b3d2..c8a598f 100644
--- a/pkg/kernel/lib/target/targets.dart
+++ b/pkg/kernel/lib/target/targets.dart
@@ -515,6 +515,7 @@
Class? concreteConstMapLiteralClass(CoreTypes coreTypes) => null;
Class? concreteSetLiteralClass(CoreTypes coreTypes) => null;
Class? concreteConstSetLiteralClass(CoreTypes coreTypes) => null;
+ Class? concreteClosureClass(CoreTypes coreTypes) => null;
Class getRecordImplementationClass(CoreTypes coreTypes,
int numPositionalFields, List<String> namedFields) =>
throw UnsupportedError('Target.getRecordImplementationClass');
diff --git a/pkg/vm/bin/dump_kernel.dart b/pkg/vm/bin/dump_kernel.dart
index 7b131c8..9248413 100644
--- a/pkg/vm/bin/dump_kernel.dart
+++ b/pkg/vm/bin/dump_kernel.dart
@@ -8,6 +8,7 @@
import 'package:kernel/binary/ast_from_binary.dart'
show BinaryBuilderWithMetadata;
+import 'package:vm/metadata/closure_id.dart' show ClosureIdMetadataRepository;
import 'package:vm/metadata/direct_call.dart' show DirectCallMetadataRepository;
import 'package:vm/metadata/inferred_type.dart'
show InferredTypeMetadataRepository, InferredArgTypeMetadataRepository;
@@ -50,6 +51,7 @@
component.addMetadataRepository(new UnreachableNodeMetadataRepository());
component.addMetadataRepository(new CallSiteAttributesMetadataRepository());
component.addMetadataRepository(new LoadingUnitsMetadataRepository());
+ component.addMetadataRepository(new ClosureIdMetadataRepository());
final List<int> bytes = new File(input).readAsBytesSync();
new BinaryBuilderWithMetadata(bytes).readComponent(component);
diff --git a/pkg/vm/lib/metadata/closure_id.dart b/pkg/vm/lib/metadata/closure_id.dart
new file mode 100644
index 0000000..8e9f034
--- /dev/null
+++ b/pkg/vm/lib/metadata/closure_id.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2023, 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.
+
+import 'package:kernel/ast.dart';
+
+/// Repository for persistent closure IDs.
+class ClosureIdMetadataRepository extends MetadataRepository<int> {
+ static const String repositoryTag = 'vm.closure-id';
+
+ @override
+ String get tag => repositoryTag;
+
+ // For a LocalFunction: id within an enclosing Member,
+ // with 0 reserved for the tear-off of the Member.
+ //
+ // For a Member: number of nested closures.
+ @override
+ final Map<TreeNode, int> mapping = {};
+
+ @override
+ void writeToBinary(int metadata, Node node, BinarySink sink) {
+ sink.writeUInt30(metadata);
+ }
+
+ @override
+ int readFromBinary(Node node, BinarySource source) {
+ return source.readUInt30();
+ }
+
+ /// Return closure ID within the enclosing [Member].
+ ///
+ /// Closures should be indexed within enclosing [Member]
+ /// using [indexClosures].
+ int getClosureId(LocalFunction closure) => mapping[closure]!;
+
+ /// Assign IDs for all closures within [member].
+ void indexClosures(Member member) {
+ if (mapping.containsKey(member)) {
+ return;
+ }
+ _ClosureIndexer indexer = _ClosureIndexer(this, member);
+ member.accept(indexer);
+ mapping[member] = indexer.index - _ClosureIndexer.firstClosureIndex;
+ }
+}
+
+class _ClosureIndexer extends RecursiveVisitor<void> {
+ // Zero is reserved for tear-offs.
+ static int firstClosureIndex = 1;
+
+ final ClosureIdMetadataRepository _repository;
+ final Member member;
+ int index = firstClosureIndex;
+
+ _ClosureIndexer(this._repository, this.member);
+
+ @override
+ void visitFunctionDeclaration(FunctionDeclaration node) =>
+ _visitLocalFunction(node);
+
+ @override
+ void visitFunctionExpression(FunctionExpression node) =>
+ _visitLocalFunction(node);
+
+ void _visitLocalFunction(LocalFunction node) {
+ assert(index > 0);
+ _repository.mapping[node] = index++;
+ node.visitChildren(this);
+ }
+}
diff --git a/pkg/vm/lib/metadata/inferred_type.dart b/pkg/vm/lib/metadata/inferred_type.dart
index 5cb0003..9d7d382 100644
--- a/pkg/vm/lib/metadata/inferred_type.dart
+++ b/pkg/vm/lib/metadata/inferred_type.dart
@@ -11,6 +11,8 @@
class InferredType {
final Reference? _concreteClassReference;
final Constant? _constantValue;
+ final Reference? _closureMemberReference;
+ final int _closureId;
final int _flags;
static const int flagNullable = 1 << 0;
@@ -19,10 +21,14 @@
// For invocations: whether to use the unchecked entry-point.
static const int flagSkipCheck = 1 << 2;
+ // Contains inferred constant value.
static const int flagConstant = 1 << 3;
static const int flagReceiverNotInt = 1 << 4;
+ // Contains inferred closure value.
+ static const int flagClosure = 1 << 5;
+
// Entire list may be null if no type arguments were inferred.
// Will always be null if `concreteClass` is null.
//
@@ -33,31 +39,44 @@
// argument (in the runtime type) is always exactly a particular `DartType`.
final List<DartType?>? exactTypeArguments;
- InferredType(
- Class? concreteClass, bool nullable, bool isInt, Constant? constantValue,
+ InferredType(Class? concreteClass, bool nullable, bool isInt,
+ Constant? constantValue, Member? closureMember, int closureId,
{List<DartType?>? exactTypeArguments,
bool skipCheck = false,
bool receiverNotInt = false})
: this._byReference(
concreteClass?.reference,
constantValue,
+ closureMember?.reference,
+ closureId,
(nullable ? flagNullable : 0) |
(isInt ? flagInt : 0) |
(skipCheck ? flagSkipCheck : 0) |
(constantValue != null ? flagConstant : 0) |
- (receiverNotInt ? flagReceiverNotInt : 0),
+ (receiverNotInt ? flagReceiverNotInt : 0) |
+ (closureMember != null ? flagClosure : 0),
exactTypeArguments);
- InferredType._byReference(this._concreteClassReference, this._constantValue,
- this._flags, this.exactTypeArguments) {
+ InferredType._byReference(
+ this._concreteClassReference,
+ this._constantValue,
+ this._closureMemberReference,
+ this._closureId,
+ this._flags,
+ this.exactTypeArguments) {
assert(exactTypeArguments == null || _concreteClassReference != null);
assert(_constantValue == null || _concreteClassReference != null);
+ assert(_closureMemberReference == null || _concreteClassReference != null);
+ assert(_closureId >= 0);
}
Class? get concreteClass => _concreteClassReference?.asClass;
Constant? get constantValue => _constantValue;
+ Member? get closureMember => _closureMemberReference?.asMember;
+ int get closureId => _closureId;
+
bool get nullable => (_flags & flagNullable) != 0;
bool get isInt => (_flags & flagInt) != 0;
bool get skipCheck => (_flags & flagSkipCheck) != 0;
@@ -96,6 +115,10 @@
if (receiverNotInt) {
buf.write(' (receiver not int)');
}
+ if (closureMember != null) {
+ buf.write(
+ ' (closure ${closureId} in ${closureMember!.toText(astTextStrategyForTesting)})');
+ }
return buf.toString();
}
}
@@ -116,10 +139,16 @@
// them for optimizations.
sink.writeNullAllowedCanonicalNameReference(
metadata.concreteClass?.reference);
+ final flags = metadata._flags;
sink.writeByte(metadata._flags);
- if (metadata.constantValue != null) {
+ if ((flags & InferredType.flagConstant) != 0) {
sink.writeConstantReference(metadata.constantValue!);
}
+ if ((flags & InferredType.flagClosure) != 0) {
+ sink.writeNullAllowedCanonicalNameReference(
+ metadata.closureMember!.reference);
+ sink.writeUInt30(metadata.closureId);
+ }
}
@override
@@ -132,8 +161,13 @@
final constantValue = (flags & InferredType.flagConstant) != 0
? source.readConstantReference()
: null;
- return new InferredType._byReference(
- concreteClassReference, constantValue, flags, null);
+ final closureMemberReference = (flags & InferredType.flagClosure) != 0
+ ? source.readNullableCanonicalNameReference()!.reference
+ : null;
+ final closureId =
+ (flags & InferredType.flagClosure) != 0 ? source.readUInt30() : 0;
+ return new InferredType._byReference(concreteClassReference, constantValue,
+ closureMemberReference, closureId, flags, null);
}
}
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index 73e510f..59872c2 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -39,6 +39,7 @@
Class? _twoByteString;
Class? _smi;
Class? _double; // _Double, not double.
+ Class? _closure;
Class? _syncStarIterable;
VmTarget(this.flags);
@@ -491,6 +492,11 @@
}
@override
+ Class concreteClosureClass(CoreTypes coreTypes) {
+ return _closure ??= coreTypes.index.getClass('dart:core', '_Closure');
+ }
+
+ @override
Class? concreteAsyncResultClass(CoreTypes coreTypes) =>
coreTypes.futureImplClass;
diff --git a/pkg/vm/lib/transformations/call_site_annotator.dart b/pkg/vm/lib/transformations/call_site_annotator.dart
index e0267ca..9df15ca 100644
--- a/pkg/vm/lib/transformations/call_site_annotator.dart
+++ b/pkg/vm/lib/transformations/call_site_annotator.dart
@@ -84,19 +84,6 @@
}
@override
- visitFunctionInvocation(FunctionInvocation node) {
- super.visitFunctionInvocation(node);
-
- final DartType receiverType =
- node.receiver.getStaticType(_staticTypeContext!);
- if (receiverType is FunctionType &&
- node.kind == FunctionAccessKind.Function) {
- throw 'Node ${node.runtimeType}: $node at ${node.location} has receiver'
- ' static type $receiverType, but kind ${node.kind}';
- }
- }
-
- @override
visitEqualsCall(EqualsCall node) {
super.visitEqualsCall(node);
diff --git a/pkg/vm/lib/transformations/type_flow/analysis.dart b/pkg/vm/lib/transformations/type_flow/analysis.dart
index 360e9fb..341e161 100644
--- a/pkg/vm/lib/transformations/type_flow/analysis.dart
+++ b/pkg/vm/lib/transformations/type_flow/analysis.dart
@@ -315,9 +315,29 @@
if (selector.callKind == CallKind.PropertyGet) {
// Tear-off.
// TODO(alexmarkov): capture receiver type
- assert((member is Procedure) && !member.isGetter && !member.isSetter);
+ assert((member is Procedure) &&
+ !member.isGetter &&
+ !member.isSetter &&
+ !member.isFactory &&
+ !member.isAbstract);
typeFlowAnalysis.addRawCall(new DirectSelector(member));
typeFlowAnalysis._tearOffTaken.add(member);
+ final Class? concreteClass = typeFlowAnalysis.target
+ .concreteClosureClass(typeFlowAnalysis.coreTypes);
+ if (concreteClass != null) {
+ if (!member.isInstanceMember) {
+ return typeFlowAnalysis
+ .addAllocatedClass(concreteClass)
+ .cls
+ .constantConcreteType(
+ StaticTearOffConstant(member as Procedure));
+ } else {
+ return typeFlowAnalysis
+ .addAllocatedClass(concreteClass)
+ .cls
+ .closureConcreteType(member, null);
+ }
+ }
return nullableAnyType;
} else {
// Call via getter.
diff --git a/pkg/vm/lib/transformations/type_flow/signature_shaking.dart b/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
index 6957ff7..721ebc0 100644
--- a/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
+++ b/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
@@ -182,7 +182,7 @@
// constant value in every implementation. The constant value inferred does
// not have to be the same across implementations, as it is specialized in
// each implementation individually.
- if (!(type is ConcreteType && type.constant != null ||
+ if (!(type is ConcreteType && type.attributes?.constant != null ||
type is NullableType && type.baseType is EmptyType)) {
isConstant = false;
}
@@ -372,7 +372,7 @@
if (param.isConstant) {
Type type = shaker.typeFlowAnalysis.argumentType(member, variable)!;
if (type is ConcreteType) {
- value = type.constant!;
+ value = type.attributes!.constant!;
} else {
assert(type is NullableType && type.baseType is EmptyType);
value = NullConstant();
@@ -499,7 +499,8 @@
void visitVariableGet(VariableGet node) {
Constant? constantValue = eliminatedParams[node.variable];
if (constantValue != null) {
- node.replaceWith(ConstantExpression(constantValue));
+ node.replaceWith(ConstantExpression(
+ constantValue, constantValue.getType(typeContext)));
}
}
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index 4a36c2d..4f0aaeb 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -526,6 +526,7 @@
// Join which accumulates all return values.
Join? _returnValue;
+ Member? _enclosingMember;
Parameter? _receiver;
late ConstantAllocationCollector constantAllocationCollector;
late RuntimeTypeTranslatorImpl _translator;
@@ -559,6 +560,7 @@
"${member}${fieldSummaryType == FieldSummaryType.kFieldGuard ? " (guard)" : ""}";
debugPrint("===== $summaryName =====");
assert(!member.isAbstract);
+ _enclosingMember = member;
_protobufHandler?.beforeSummaryCreation(member);
@@ -769,6 +771,7 @@
member.enclosingClass?.annotations.forEach(_visit);
member.enclosingLibrary.annotations.forEach(_visit);
+ _enclosingMember = null;
_staticTypeContext = null;
debugPrint("------------ SUMMARY ------------");
@@ -1370,6 +1373,25 @@
_returnValue = savedReturn;
}
+ TypeExpr _closureType(LocalFunction node) {
+ final Class? concreteClass =
+ target.concreteClosureClass(_environment.coreTypes);
+ if (concreteClass != null) {
+ return _entryPointsListener
+ .addAllocatedClass(concreteClass)
+ .cls
+ .closureConcreteType(_enclosingMember!, node);
+ }
+ switch (node) {
+ case FunctionExpression():
+ return _staticType(node);
+ case FunctionDeclaration():
+ return _typesBuilder.fromStaticType(node.variable.type, true);
+ default:
+ throw 'Unexpected ${node.runtimeType} $node';
+ }
+ }
+
// Tests subtypes ignoring any nullabilities.
bool _isSubtype(DartType subtype, DartType supertype) => _environment
.isSubtypeOf(subtype, supertype, SubtypeCheckMode.ignoringNullabilities);
@@ -1626,9 +1648,7 @@
@override
TypeExpr visitFunctionExpression(FunctionExpression node) {
_handleNestedFunctionNode(node.function);
- // TODO(alexmarkov): support function types.
- // return _concreteType(node.function.functionType);
- return _staticType(node);
+ return _closureType(node);
}
@override
@@ -2225,9 +2245,8 @@
@override
TypeExpr? visitFunctionDeclaration(FunctionDeclaration node) {
- // TODO(alexmarkov): support function types.
node.variable.annotations.forEach(_visit);
- _declareVariableWithStaticType(node.variable);
+ _declareVariable(node.variable, _closureType(node));
_handleNestedFunctionNode(node.function);
return null;
}
@@ -2830,6 +2849,14 @@
.addAllocatedClass(member.enclosingClass);
}
summaryCollector._entryPointsListener.recordTearOff(member);
+ final Class? concreteClass = summaryCollector.target
+ .concreteClosureClass(summaryCollector._environment.coreTypes);
+ if (concreteClass != null) {
+ return summaryCollector._entryPointsListener
+ .addAllocatedClass(concreteClass)
+ .cls
+ .constantConcreteType(constant);
+ }
return _getStaticType(constant);
}
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 81bc828..38033c8 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -18,6 +18,7 @@
import 'package:kernel/library_index.dart' show LibraryIndex;
import 'package:kernel/target/targets.dart';
import 'package:kernel/type_environment.dart';
+import 'package:vm/metadata/closure_id.dart';
import 'package:vm/metadata/direct_call.dart';
import 'package:vm/metadata/inferred_type.dart';
import 'package:vm/metadata/procedure_attributes.dart';
@@ -310,6 +311,7 @@
final ProcedureAttributesMetadataRepository _procedureAttributesMetadata;
final TableSelectorMetadataRepository _tableSelectorMetadata;
final TableSelectorAssigner _tableSelectorAssigner;
+ final ClosureIdMetadataRepository _closureIdMetadata;
final UnboxingInfoMetadataRepository _unboxingInfoMetadata;
final UnboxingInfoManager _unboxingInfo;
final Class _intClass;
@@ -325,6 +327,7 @@
_unreachableNodeMetadata = UnreachableNodeMetadataRepository(),
_procedureAttributesMetadata = ProcedureAttributesMetadataRepository(),
_tableSelectorMetadata = TableSelectorMetadataRepository(),
+ _closureIdMetadata = ClosureIdMetadataRepository(),
_unboxingInfoMetadata = UnboxingInfoMetadataRepository(),
_intClass = _typeFlowAnalysis.environment.coreTypes.intClass {
component.addMetadataRepository(_inferredTypeMetadata);
@@ -332,6 +335,7 @@
component.addMetadataRepository(_unreachableNodeMetadata);
component.addMetadataRepository(_procedureAttributesMetadata);
component.addMetadataRepository(_tableSelectorMetadata);
+ component.addMetadataRepository(_closureIdMetadata);
component.addMetadataRepository(_unboxingInfoMetadata);
}
@@ -344,6 +348,8 @@
{bool skipCheck = false, bool receiverNotInt = false}) {
Class? concreteClass;
Constant? constantValue;
+ Member? closureMember;
+ int closureId = 0;
bool isInt = false;
final nullable = type is NullableType;
@@ -363,7 +369,20 @@
}
if (type is ConcreteType && !nullable) {
- constantValue = type.constant;
+ constantValue = type.attributes?.constant;
+
+ final closure = type.attributes?.closure;
+ if (closure != null) {
+ closureMember = closure.member;
+ final function = closure.function;
+ if (function != null) {
+ _closureIdMetadata.indexClosures(closureMember);
+ closureId = _closureIdMetadata.getClosureId(function);
+ assert(closureId > 0);
+ } else {
+ closureId = 0;
+ }
+ }
}
}
@@ -381,8 +400,10 @@
isInt ||
constantValue != null ||
skipCheck ||
- receiverNotInt) {
+ receiverNotInt ||
+ closureMember != null) {
return new InferredType(concreteClass, nullable, isInt, constantValue,
+ closureMember, closureId,
exactTypeArguments: typeArgs,
skipCheck: skipCheck,
receiverNotInt: receiverNotInt);
diff --git a/pkg/vm/lib/transformations/type_flow/types.dart b/pkg/vm/lib/transformations/type_flow/types.dart
index 8cdd58d..a0e1c21 100644
--- a/pkg/vm/lib/transformations/type_flow/types.dart
+++ b/pkg/vm/lib/transformations/type_flow/types.dart
@@ -26,7 +26,7 @@
final int id;
final Class classNode;
final RecordShape? recordShape;
- final Map<Constant, ConcreteType> _constantConcreteTypes = {};
+ final Map<TypeAttributes, ConcreteType> _concreteTypesWithAttributes = {};
/// TFClass should not be instantiated directly.
/// Instead, [TypeHierarchy.getTFClass] should be used to obtain [TFClass]
@@ -40,7 +40,21 @@
/// Returns ConcreteType corresponding to this class and
/// [constant] value.
ConcreteType constantConcreteType(Constant constant) =>
- _constantConcreteTypes[constant] ??= ConcreteType._(this, null, constant);
+ _concreteTypeWithAttributes(
+ TypeAttributes._(constant, _closureForConstant(constant)));
+
+ /// Returns ConcreteType corresponding to this class and
+ /// given [function] in [member].
+ ConcreteType closureConcreteType(Member member, LocalFunction? function) {
+ assert(function != null ||
+ (member is Procedure &&
+ !member.isGetter &&
+ !member.isSetter &&
+ !member.isStatic &&
+ !member.isAbstract));
+ return _concreteTypeWithAttributes(
+ TypeAttributes._(null, Closure._(member, function)));
+ }
/// Returns ConeType corresponding to this class.
late final ConeType coneType = ConeType._(this);
@@ -55,6 +69,26 @@
@override
String toString() => nodeToText(classNode);
+
+ ConcreteType _concreteTypeWithAttributes(TypeAttributes attr) =>
+ _concreteTypesWithAttributes[attr] ??= ConcreteType._(this, null, attr);
+
+ Closure? _closureForConstant(Constant c) {
+ if (c is InstantiationConstant) {
+ return _closureForConstant(c.tearOffConstant);
+ } else if (c is TearOffConstant) {
+ final target = c.target;
+ assert(target is Constructor ||
+ (target is Procedure &&
+ target.isStatic &&
+ !target.isGetter &&
+ !target.isSetter));
+ return Closure._(target, null);
+ } else if (c is TypedefTearOffConstant) {
+ throw 'Unexpected TypedefTearOffConstant $c';
+ }
+ return null;
+ }
}
/// Shape of a record (number of positional fields and a set of named fields).
@@ -894,6 +928,94 @@
}
}
+/// Object representing a closure function.
+///
+/// Can be used to represent local function (FunctionExpression,
+// FunctionDeclaration) or tear-off of Procedure or Constructor.
+class Closure {
+ final Member member;
+ final LocalFunction? function;
+
+ Closure._(this.member, this.function);
+
+ @override
+ int get hashCode => ((member.hashCode * 31) & kHashMask) + function.hashCode;
+
+ @override
+ bool operator ==(other) {
+ if (identical(this, other)) return true;
+ if (other is! Closure) return false;
+ return (this.member == other.member) && (this.function == other.function);
+ }
+
+ @override
+ String toString() {
+ final function = this.function;
+ if (function == null) {
+ return 'tear-off ${nodeToText(member)}';
+ }
+ switch (function) {
+ case FunctionDeclaration():
+ return function.variable.name!;
+ case FunctionExpression():
+ final location = function.location;
+ return '<anonymous closure' +
+ (location != null
+ ? ' at ${location.file.pathSegments.last}:${location.line}'
+ : '') +
+ '>';
+ default:
+ throw 'Unexpected local function ${function.runtimeType} $function';
+ }
+ }
+}
+
+/// Disjoint (mutually exclusive) attributes of Dart values.
+///
+/// If two sets of values V1 and V2 are known to have
+/// distinct attributes A1 != A2, then Intersection(V1, V2) is empty.
+///
+/// Currently used for
+/// - constant values;
+/// - closures.
+///
+class TypeAttributes {
+ final Constant? constant;
+ final Closure? closure;
+
+ TypeAttributes._(this.constant, this.closure)
+ : hashCode = constant.hashCode ^ closure.hashCode {
+ assert(constant != null || closure != null);
+ }
+
+ @override
+ final int hashCode;
+
+ @override
+ bool operator ==(other) {
+ if (identical(this, other)) return true;
+ if (other is! TypeAttributes) return false;
+ return (this.constant == other.constant) && (this.closure == other.closure);
+ }
+
+ @override
+ String toString() {
+ final buf = StringBuffer();
+ final constant = this.constant;
+ if (constant != null) {
+ buf.write(nodeToText(constant));
+ }
+ final closure = this.closure;
+ if (closure != null) {
+ if (buf.isNotEmpty) {
+ buf.write(', ');
+ }
+ buf.write(closure.toString());
+ }
+ return buf.toString();
+ }
+}
+
/// Type representing a set of instances of a specific Dart class (no subtypes
/// or `null` object).
class ConcreteType extends Type implements Comparable<ConcreteType> {
@@ -920,10 +1042,11 @@
final int numImmediateTypeArgs;
final List<Type>? typeArgs;
- // May be null if constant value is not inferred.
- final Constant? constant;
+ // Additional type attributes such as constant value and
+ // inferred closure.
+ final TypeAttributes? attributes;
- ConcreteType._(this.cls, List<Type>? typeArgs_, this.constant)
+ ConcreteType._(this.cls, List<Type>? typeArgs_, this.attributes)
: typeArgs = typeArgs_,
numImmediateTypeArgs =
typeArgs_ != null ? cls.classNode.typeParameters.length : 0,
@@ -937,7 +1060,7 @@
ConcreteType(TFClass cls, List<Type> typeArgs) : this._(cls, typeArgs, null);
ConcreteType get raw => cls.concreteType;
- bool get isRaw => typeArgs == null && constant == null;
+ bool get isRaw => typeArgs == null && attributes == null;
@override
Class? getConcreteClass(TypeHierarchy typeHierarchy) =>
@@ -1024,7 +1147,7 @@
for (int i = 0; i < numImmediateTypeArgs; ++i) {
hash = (((hash * 31) & kHashMask) + typeArgs![i].hashCode) & kHashMask;
}
- hash = ((hash * 31) & kHashMask) + constant.hashCode;
+ hash = ((hash * 31) & kHashMask) + attributes.hashCode;
return hash;
}
@@ -1034,7 +1157,7 @@
if (other is ConcreteType) {
if (!identical(this.cls, other.cls) ||
this.numImmediateTypeArgs != other.numImmediateTypeArgs ||
- !identical(this.constant, other.constant)) {
+ !identical(this.attributes, other.attributes)) {
return false;
}
if (this.typeArgs != null) {
@@ -1057,7 +1180,7 @@
@override
String toString() {
- if (typeArgs == null && constant == null) {
+ if (typeArgs == null && attributes == null) {
return "_T (${cls})";
}
final StringBuffer buf = new StringBuffer();
@@ -1065,8 +1188,8 @@
if (typeArgs != null) {
buf.write("<${typeArgs!.take(numImmediateTypeArgs).join(', ')}>");
}
- if (constant != null) {
- buf.write(", ${nodeToText(constant!)}");
+ if (attributes != null) {
+ buf.write(", $attributes");
}
buf.write(")");
return buf.toString();
@@ -1090,9 +1213,9 @@
return SetType(types);
} else {
assert(typeArgs != null ||
- constant != null ||
+ attributes != null ||
other.typeArgs != null ||
- other.constant != null);
+ other.attributes != null);
return raw;
}
} else {
@@ -1112,13 +1235,13 @@
if (!identical(this.cls, other.cls)) {
return emptyType;
}
- if (constant != null) {
- if (other.constant == null) {
+ if (attributes != null) {
+ if (other.attributes == null) {
return this;
}
- assert(constant != other.constant);
+ assert(attributes != other.attributes);
return emptyType;
- } else if (other.constant != null) {
+ } else if (other.attributes != null) {
return other;
}
diff --git a/pkg/vm/testcases/transformations/ffi/finalizable_async_star.dart.aot.expect b/pkg/vm/testcases/transformations/ffi/finalizable_async_star.dart.aot.expect
index 0e782ed..c511f9b 100644
--- a/pkg/vm/testcases/transformations/ffi/finalizable_async_star.dart.aot.expect
+++ b/pkg/vm/testcases/transformations/ffi/finalizable_async_star.dart.aot.expect
@@ -14,7 +14,7 @@
}
[@vm.unboxing-info.metadata=()->i]static method doSomething() → core::int
return 3;
-static method useFinalizableAsyncStar([@vm.inferred-arg-type.metadata=#lib::MyFinalizable] ffi::Finalizable finalizable) → asy::Stream<core::int> async* {
+[@vm.closure-id=1]static method useFinalizableAsyncStar([@vm.inferred-arg-type.metadata=#lib::MyFinalizable] ffi::Finalizable finalizable) → asy::Stream<core::int> async* {
final self::MyFinalizable finalizable2 = new self::MyFinalizable::•();
yield block {
final synthesized core::int :expressionValueWrappedFinalizable = self::doSomething();
@@ -23,7 +23,7 @@
} =>:expressionValueWrappedFinalizable;
final self::MyFinalizable finalizable3 = new self::MyFinalizable::•();
await block {
- final synthesized asy::Future<core::int> :expressionValueWrappedFinalizable = asy::Future::sync<core::int>(() → core::int => 3);
+ final synthesized asy::Future<core::int> :expressionValueWrappedFinalizable = asy::Future::sync<core::int>([@vm.closure-id=1]() → core::int => 3);
_in::reachabilityFence(finalizable);
_in::reachabilityFence(finalizable2);
_in::reachabilityFence(finalizable3);
diff --git a/pkg/vm/testcases/transformations/ffi/finalizable_member.dart.aot.expect b/pkg/vm/testcases/transformations/ffi/finalizable_member.dart.aot.expect
index 90bb19e..e64a891 100644
--- a/pkg/vm/testcases/transformations/ffi/finalizable_member.dart.aot.expect
+++ b/pkg/vm/testcases/transformations/ffi/finalizable_member.dart.aot.expect
@@ -27,10 +27,10 @@
}
[@vm.inferred-type.metadata=dart.ffi::Pointer]static final field ffi::Pointer<ffi::NativeFunction<(ffi::Pointer<ffi::NativeType>) → ffi::Void>> free = [@vm.direct-call.metadata=dart.ffi::DynamicLibrary.lookup] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] [@vm.inferred-type.metadata=dart.ffi::DynamicLibrary] ffi::DynamicLibrary::process().{ffi::DynamicLibrary::lookup}<ffi::NativeFunction<(ffi::Pointer<ffi::NativeType>) → ffi::Void>>("free"){(core::String) → ffi::Pointer<ffi::NativeFunction<(ffi::Pointer<ffi::NativeType>) → ffi::Void>>};
[@vm.inferred-type.metadata=dart.ffi::_NativeFinalizer]static final field ffi::NativeFinalizer _nativeFinalizer = new ffi::_NativeFinalizer::•([@vm.inferred-type.metadata=dart.ffi::Pointer] self::free);
-static method main() → asy::Future<void> async /* futureValueType= void */ {
+[@vm.closure-id=1]static method main() → asy::Future<void> async /* futureValueType= void */ {
final self::B b = new self::B::•(new self::A::•());
[@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] final core::List<core::int> l = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] core::_GrowableList::•<core::int>(0);
- asy::Future::doWhile(() → core::bool {
+ asy::Future::doWhile([@vm.closure-id=1]() → core::bool {
[@vm.call-site-attributes.metadata=receiverType:dart.core::List<dart.core::int>] [@vm.direct-call.metadata=dart.core::_GrowableList.add] [@vm.inferred-type.metadata=!? (skip check)] l.{core::List::add}(1){(core::int) → void};
return true;
});
diff --git a/pkg/vm/testcases/transformations/ffi/finalizable_sync2.dart.aot.expect b/pkg/vm/testcases/transformations/ffi/finalizable_sync2.dart.aot.expect
index 78727a8..5da7e8f 100644
--- a/pkg/vm/testcases/transformations/ffi/finalizable_sync2.dart.aot.expect
+++ b/pkg/vm/testcases/transformations/ffi/finalizable_sync2.dart.aot.expect
@@ -11,7 +11,7 @@
: super core::Object::•()
;
}
-static method main() → void {
+[@vm.closure-id=1]static method main() → void {
final self::MyFinalizable finalizable = new self::MyFinalizable::•();
{
final self::MyFinalizable finalizable2 = new self::MyFinalizable::•();
@@ -210,7 +210,7 @@
_in::reachabilityFence(finalizable16);
}
{
- synthesized core::Iterator<ffi::Finalizable> :sync-for-iterator = [@vm.inferred-type.metadata=!] [@vm.inferred-type.metadata=!] core::Iterable::generate<ffi::Finalizable>((core::int index) → self::MyFinalizable => new self::MyFinalizable::•()).{core::Iterable::iterator}{core::Iterator<ffi::Finalizable>};
+ synthesized core::Iterator<ffi::Finalizable> :sync-for-iterator = [@vm.inferred-type.metadata=!] [@vm.inferred-type.metadata=!] core::Iterable::generate<ffi::Finalizable>([@vm.closure-id=1](core::int index) → self::MyFinalizable => new self::MyFinalizable::•()).{core::Iterable::iterator}{core::Iterator<ffi::Finalizable>};
for (; [@vm.inferred-type.metadata=dart.core::bool] :sync-for-iterator.{core::Iterator::moveNext}(){() → core::bool}; ) {
final ffi::Finalizable finalizable17 = [@vm.inferred-type.metadata=#lib::MyFinalizable] :sync-for-iterator.{core::Iterator::current}{ffi::Finalizable};
{
diff --git a/pkg/vm/testcases/transformations/ffi/native_callable.dart.aot.expect b/pkg/vm/testcases/transformations/ffi/native_callable.dart.aot.expect
index 166b87c..cbc30fc 100644
--- a/pkg/vm/testcases/transformations/ffi/native_callable.dart.aot.expect
+++ b/pkg/vm/testcases/transformations/ffi/native_callable.dart.aot.expect
@@ -28,12 +28,12 @@
core::print([@vm.direct-call.metadata=dart.ffi::_NativeCallableBase.nativeFunction] [@vm.inferred-type.metadata=dart.ffi::Pointer] callback.{ffi::NativeCallable::nativeFunction}{ffi::Pointer<ffi::NativeFunction<(ffi::Int32) → ffi::Void>>});
[@vm.direct-call.metadata=dart.ffi::_NativeCallableListener.close] [@vm.inferred-type.metadata=!? (skip check)] callback.{ffi::NativeCallable::close}(){() → void};
}
-static method testNativeCallableListenerClosure() → void {
+[@vm.closure-id=2]static method testNativeCallableListenerClosure() → void {
[@vm.inferred-type.metadata=dart.core::_Smi (value: 123)] core::int j = 123;
- function closure(core::int i) → void
+[@vm.closure-id=1] function closure(core::int i) → void
return core::print([@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(j){(core::num) → core::int});
final ffi::NativeCallable<(ffi::Int32) → ffi::Void> callback = block {
- final ffi::NativeCallable<(ffi::Int32) → ffi::Void> #t2 = new ffi::_NativeCallableListener::•<(ffi::Int32) → ffi::Void>((final core::List<dynamic> args) → void
+ final ffi::NativeCallable<(ffi::Int32) → ffi::Void> #t2 = new ffi::_NativeCallableListener::•<(ffi::Int32) → ffi::Void>([@vm.closure-id=2](final core::List<dynamic> args) → void
closure(args.{core::List::[]}(0){(core::int) → dynamic}){(ffi::Int32) → ffi::Void};
, "NativeCallable(VariableGetImpl(closure))");
[@vm.call-site-attributes.metadata=receiverType:dart.ffi::NativeCallable<dart.ffi::Void Function(dart.ffi::Int32)>] [@vm.direct-call.metadata=dart.ffi::_NativeCallableBase._pointer] #t2.{ffi::_NativeCallableBase::_pointer} = [@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::_createNativeCallableListener<ffi::NativeFunction<(ffi::Int32) → ffi::Void>>(ffi::_nativeAsyncCallbackFunction<(ffi::Int32) → ffi::Void>(), [@vm.direct-call.metadata=dart.ffi::_NativeCallableListener._port] [@vm.inferred-type.metadata=dart.isolate::_RawReceivePort] #t2.{ffi::_NativeCallableListener::_port}{iso::RawReceivePort});
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/control_flow.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/control_flow.dart.expect
index 528987f..145d2d2 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/control_flow.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/control_flow.dart.expect
@@ -287,7 +287,7 @@
t2 = read x
t3 = _Call direct [#lib::foo] (t2)
t4 = _Call direct [#lib::bar] (t2)
-t5 = _Call direct [#lib::foo] (_T (dart.core::Function)+?)
+t5 = _Call direct [#lib::foo] (_T (dart.core::_Closure, <anonymous closure at control_flow.dart:268>))
t6* = _Call direct [#lib::C2.] (_T (#lib::C2))
write x = t6
RESULT: _T {}?
@@ -298,7 +298,7 @@
t3 = _Call direct [#lib::foo] (t2)
t4* = _Call direct [#lib::C2.] (_T (#lib::C2))
write x = t4
-t6 = _Call direct [#lib::foo] (_T (dart.core::Function)+?)
+t6 = _Call direct [#lib::foo] (_T (dart.core::_Closure, <anonymous closure at control_flow.dart:277>))
RESULT: t2
------------ switch1 ------------
%selector = _Parameter #0 [_T (dart.core::int)+?]
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/closures.dart b/pkg/vm/testcases/transformations/type_flow/transformer/closures.dart
new file mode 100644
index 0000000..eee3b0c
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/closures.dart
@@ -0,0 +1,132 @@
+// Copyright (c) 2023, 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.
+
+class C {
+ C(arg) {
+ print(arg);
+ }
+ void instanceMethod(arg) {
+ print(arg);
+ }
+
+ static void staticMethod(arg) {
+ print(arg);
+ }
+}
+
+dynamic createClosure1() => (arg) => print(arg);
+
+dynamic createClosure2() {
+ void inner(arg) {
+ print(arg);
+ }
+
+ return inner;
+}
+
+dynamic createClosure3(obj) => obj.instanceMethod;
+
+dynamic createClosure4() => C.staticMethod;
+
+dynamic createClosure5() => C.new;
+
+void useClosure11(void Function(dynamic) func) {
+ func(42);
+}
+
+void useClosure12(void Function(dynamic) func) {
+ func(42);
+}
+
+void useClosure13(void Function(dynamic) func) {
+ func(42);
+}
+
+void useClosure14(void Function(dynamic) func) {
+ func(42);
+}
+
+void useClosure15(void Function(dynamic) func) {
+ func(42);
+}
+
+void useClosure21(func) {
+ func(42);
+}
+
+void useClosure22(func) {
+ func(42);
+}
+
+void useClosure23(func) {
+ func(42);
+}
+
+void useClosure24(func) {
+ func(42);
+}
+
+void useClosure25(func) {
+ func(42);
+}
+
+class UseClosure31 {
+ final void Function(dynamic) func;
+ UseClosure31(this.func);
+ void use() {
+ func(42);
+ }
+}
+
+class UseClosure32 {
+ final void Function(dynamic) func;
+ UseClosure32(this.func);
+ void use() {
+ func(42);
+ }
+}
+
+class UseClosure33 {
+ final void Function(dynamic) func;
+ UseClosure33(this.func);
+ void use() {
+ func(42);
+ }
+}
+
+class UseClosure34 {
+ final void Function(dynamic) func;
+ UseClosure34(this.func);
+ void use() {
+ func(42);
+ }
+}
+
+class UseClosure35 {
+ final void Function(dynamic) func;
+ UseClosure35(this.func);
+ void use() {
+ func(42);
+ }
+}
+
+void main() {
+ useClosure11(createClosure1());
+ useClosure12(createClosure2());
+ useClosure13(createClosure3(C(3)));
+ useClosure14(createClosure4());
+ useClosure15(createClosure5());
+
+ useClosure21(createClosure1());
+ useClosure22(createClosure2());
+ useClosure23(createClosure3(C(3)));
+ useClosure24(createClosure4());
+ useClosure25(createClosure5());
+
+ UseClosure31(createClosure1()).use();
+ UseClosure32(createClosure2()).use();
+ UseClosure33(createClosure3(C(3))).use();
+ UseClosure34(createClosure4()).use();
+ UseClosure35(createClosure5()).use();
+}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/closures.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/closures.dart.expect
new file mode 100644
index 0000000..ff0026d
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/closures.dart.expect
@@ -0,0 +1,126 @@
+library #lib;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ constructor •(dynamic arg) → self::C
+ : super core::Object::•() {
+ core::print(arg);
+ }
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,methodOrSetterSelectorId:1,getterSelectorId:2] method instanceMethod(dynamic arg) → void {
+ core::print(arg);
+ }
+ static method staticMethod(dynamic arg) → void {
+ core::print(arg);
+ }
+}
+class UseClosure31 extends core::Object {
+[@vm.inferred-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure1)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:3] final field (dynamic) → void func;
+ constructor •([@vm.inferred-arg-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure1)] (dynamic) → void func) → self::UseClosure31
+ : self::UseClosure31::func = func, super core::Object::•()
+ ;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:4,getterSelectorId:5] method use() → void {
+ let final core::int #t1 = 42 in [@vm.direct-call.metadata=#lib::UseClosure31.func] this.{self::UseClosure31::func}{(dynamic) → void}(#t1){(dynamic) → void};
+ }
+}
+class UseClosure32 extends core::Object {
+[@vm.inferred-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure2)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:6] final field (dynamic) → void func;
+ constructor •([@vm.inferred-arg-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure2)] (dynamic) → void func) → self::UseClosure32
+ : self::UseClosure32::func = func, super core::Object::•()
+ ;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8] method use() → void {
+ let final core::int #t2 = 42 in [@vm.direct-call.metadata=#lib::UseClosure32.func] this.{self::UseClosure32::func}{(dynamic) → void}(#t2){(dynamic) → void};
+ }
+}
+class UseClosure33 extends core::Object {
+[@vm.inferred-type.metadata=dart.core::_Closure (closure 0 in #lib::C.instanceMethod)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:9] final field (dynamic) → void func;
+ constructor •([@vm.inferred-arg-type.metadata=dart.core::_Closure (closure 0 in #lib::C.instanceMethod)] (dynamic) → void func) → self::UseClosure33
+ : self::UseClosure33::func = func, super core::Object::•()
+ ;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:10,getterSelectorId:11] method use() → void {
+ let final core::int #t3 = 42 in [@vm.direct-call.metadata=#lib::UseClosure33.func] this.{self::UseClosure33::func}{(dynamic) → void}(#t3){(dynamic) → void};
+ }
+}
+class UseClosure34 extends core::Object {
+[@vm.inferred-type.metadata=dart.core::_Closure (value: #lib::C.staticMethod) (closure 0 in #lib::C.staticMethod)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:12] final field (dynamic) → void func;
+ constructor •() → self::UseClosure34
+ : self::UseClosure34::func = #C1, super core::Object::•()
+ ;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:13,getterSelectorId:14] method use() → void {
+ let final core::int #t4 = 42 in [@vm.direct-call.metadata=#lib::UseClosure34.func] this.{self::UseClosure34::func}{(dynamic) → void}(#t4){(dynamic) → void};
+ }
+}
+class UseClosure35 extends core::Object {
+[@vm.inferred-type.metadata=dart.core::_Closure (value: #lib::C.) (closure 0 in #lib::C.)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:15] final field (dynamic) → void func;
+ constructor •() → self::UseClosure35
+ : self::UseClosure35::func = #C2, super core::Object::•()
+ ;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:16,getterSelectorId:17] method use() → void {
+ let final core::int #t5 = 42 in [@vm.direct-call.metadata=#lib::UseClosure35.func] this.{self::UseClosure35::func}{(dynamic) → void}(#t5){(dynamic) → void};
+ }
+}
+[@vm.closure-id=1]static method createClosure1() → dynamic
+ return [@vm.closure-id=1](dynamic arg) → void => core::print(arg);
+[@vm.closure-id=1]static method createClosure2() → dynamic {
+[@vm.closure-id=1] function inner(dynamic arg) → void {
+ core::print(arg);
+ }
+ return inner;
+}
+static method createClosure3([@vm.inferred-arg-type.metadata=#lib::C] dynamic obj) → dynamic
+ return [@vm.inferred-type.metadata=dart.core::_Closure (receiver not int) (closure 0 in #lib::C.instanceMethod)] obj{dynamic}.instanceMethod;
+static method createClosure4() → dynamic
+ return #C1;
+static method createClosure5() → dynamic
+ return #C2;
+static method useClosure11([@vm.inferred-arg-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure1)] (dynamic) → void func) → void {
+ func(42){(dynamic) → void};
+}
+static method useClosure12([@vm.inferred-arg-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure2)] (dynamic) → void func) → void {
+ func(42){(dynamic) → void};
+}
+static method useClosure13([@vm.inferred-arg-type.metadata=dart.core::_Closure (closure 0 in #lib::C.instanceMethod)] (dynamic) → void func) → void {
+ func(42){(dynamic) → void};
+}
+static method useClosure14() → void {
+ #C1(42){(dynamic) → void};
+}
+static method useClosure15() → void {
+ #C2(42){(dynamic) → void};
+}
+static method useClosure21([@vm.inferred-arg-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure1)] dynamic func) → void {
+ [@vm.inferred-type.metadata=!? (receiver not int)] func{dynamic}.call(42);
+}
+static method useClosure22([@vm.inferred-arg-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure2)] dynamic func) → void {
+ [@vm.inferred-type.metadata=!? (receiver not int)] func{dynamic}.call(42);
+}
+static method useClosure23([@vm.inferred-arg-type.metadata=dart.core::_Closure (closure 0 in #lib::C.instanceMethod)] dynamic func) → void {
+ [@vm.inferred-type.metadata=!? (receiver not int)] func{dynamic}.call(42);
+}
+static method useClosure24() → void {
+ [@vm.inferred-type.metadata=!? (receiver not int)] #C1{dynamic}.call(42);
+}
+static method useClosure25() → void {
+ [@vm.inferred-type.metadata=!? (receiver not int)] #C2{dynamic}.call(42);
+}
+static method main() → void {
+ self::useClosure11([@vm.inferred-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure1)] self::createClosure1() as{TypeError,ForDynamic} (dynamic) → void);
+ self::useClosure12([@vm.inferred-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure2)] self::createClosure2() as{TypeError,ForDynamic} (dynamic) → void);
+ self::useClosure13([@vm.inferred-type.metadata=dart.core::_Closure (closure 0 in #lib::C.instanceMethod)] self::createClosure3(new self::C::•(3)) as{TypeError,ForDynamic} (dynamic) → void);
+ let final (dynamic) → void #t6 = [@vm.inferred-type.metadata=dart.core::_Closure (value: #lib::C.staticMethod) (closure 0 in #lib::C.staticMethod)] self::createClosure4() as{TypeError,ForDynamic} (dynamic) → void in self::useClosure14();
+ let final (dynamic) → void #t7 = [@vm.inferred-type.metadata=dart.core::_Closure (value: #lib::C.) (closure 0 in #lib::C.)] self::createClosure5() as{TypeError,ForDynamic} (dynamic) → void in self::useClosure15();
+ self::useClosure21([@vm.inferred-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure1)] self::createClosure1());
+ self::useClosure22([@vm.inferred-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure2)] self::createClosure2());
+ self::useClosure23([@vm.inferred-type.metadata=dart.core::_Closure (closure 0 in #lib::C.instanceMethod)] self::createClosure3(new self::C::•(3)));
+ let final dynamic #t8 = [@vm.inferred-type.metadata=dart.core::_Closure (value: #lib::C.staticMethod) (closure 0 in #lib::C.staticMethod)] self::createClosure4() in self::useClosure24();
+ let final dynamic #t9 = [@vm.inferred-type.metadata=dart.core::_Closure (value: #lib::C.) (closure 0 in #lib::C.)] self::createClosure5() in self::useClosure25();
+ [@vm.direct-call.metadata=#lib::UseClosure31.use] [@vm.inferred-type.metadata=!? (skip check)] new self::UseClosure31::•([@vm.inferred-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure1)] self::createClosure1() as{TypeError,ForDynamic} (dynamic) → void).{self::UseClosure31::use}(){() → void};
+ [@vm.direct-call.metadata=#lib::UseClosure32.use] [@vm.inferred-type.metadata=!? (skip check)] new self::UseClosure32::•([@vm.inferred-type.metadata=dart.core::_Closure (closure 1 in #lib::createClosure2)] self::createClosure2() as{TypeError,ForDynamic} (dynamic) → void).{self::UseClosure32::use}(){() → void};
+ [@vm.direct-call.metadata=#lib::UseClosure33.use] [@vm.inferred-type.metadata=!? (skip check)] new self::UseClosure33::•([@vm.inferred-type.metadata=dart.core::_Closure (closure 0 in #lib::C.instanceMethod)] self::createClosure3(new self::C::•(3)) as{TypeError,ForDynamic} (dynamic) → void).{self::UseClosure33::use}(){() → void};
+ [@vm.direct-call.metadata=#lib::UseClosure34.use] [@vm.inferred-type.metadata=!? (skip check)](let final (dynamic) → void #t10 = [@vm.inferred-type.metadata=dart.core::_Closure (value: #lib::C.staticMethod) (closure 0 in #lib::C.staticMethod)] self::createClosure4() as{TypeError,ForDynamic} (dynamic) → void in new self::UseClosure34::•()).{self::UseClosure34::use}(){() → void};
+ [@vm.direct-call.metadata=#lib::UseClosure35.use] [@vm.inferred-type.metadata=!? (skip check)](let final (dynamic) → void #t11 = [@vm.inferred-type.metadata=dart.core::_Closure (value: #lib::C.) (closure 0 in #lib::C.)] self::createClosure5() as{TypeError,ForDynamic} (dynamic) → void in new self::UseClosure35::•()).{self::UseClosure35::use}(){() → void};
+}
+constants {
+ #C1 = static-tearoff self::C::staticMethod
+ #C2 = constructor-tearoff self::C::•
+}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/lists.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/lists.dart.expect
index 0988e52..f7daf42 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/lists.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/lists.dart.expect
@@ -25,8 +25,8 @@
[@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::List<dart.core::int>>] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:19] final field core::List<core::List<core::int>> generateFactory5;
[@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:20] final field core::List<core::int> generateFactory6;
[@vm.inferred-type.metadata=dart.core::_List<dart.core::int>] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:21] final field core::List<core::int> generateFactory7;
- synthetic constructor •() → self::A
- : self::A::literal1 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] core::_GrowableList::•<core::int>(0), self::A::literal2 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] core::_GrowableList::_literal3<core::int>(1, 2, 3), self::A::filledFactory1 = [@vm.inferred-type.metadata=dart.core::_List<dart.core::int>] core::_List::filled<core::int>(2, 0), self::A::filledFactory2 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] core::_GrowableList::filled<core::int>(2, 0), self::A::filledFactory3 = [@vm.inferred-type.metadata=dart.core::_List<dart.core::int>] core::_List::filled<core::int>(2, 0), self::A::filledFactory4 = let final core::bool #t1 = _in::unsafeCast<core::bool>([@vm.inferred-type.metadata=dart.core::bool] self::nonConstant()) in [@vm.inferred-type.metadata=!] core::List::filled<core::int>(2, 0, #t1), self::A::filledFactory5 = [@vm.inferred-type.metadata=dart.core::_List<dart.core::int?>] core::_List::•<core::int?>(2), self::A::filledFactory6 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int?>] core::_GrowableList::•<core::int?>(2), self::A::filledFactory7 = [@vm.inferred-type.metadata=dart.core::_List<dart.core::int?>] core::_List::•<core::int?>(2), self::A::filledFactory8 = let final core::bool #t2 = _in::unsafeCast<core::bool>([@vm.inferred-type.metadata=dart.core::bool] self::nonConstant()) in [@vm.inferred-type.metadata=!] core::List::filled<core::int?>(2, null, #t2), self::A::filledFactory9 = let final core::int #t3 = 2 in let final core::bool #t4 = true in [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int?>] core::_GrowableList::•<core::int?>(#t3), self::A::filledFactory10 = let final core::int #t5 = 2 in let final core::bool #t6 = false in [@vm.inferred-type.metadata=dart.core::_List<dart.core::int?>] core::_List::•<core::int?>(#t5), self::A::generateFactory1 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] core::_GrowableList::generate<core::int>(2, (core::int i) → core::int => i), self::A::generateFactory2 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] core::_GrowableList::generate<core::int>(2, (core::int i) → core::int => i), self::A::generateFactory3 = [@vm.inferred-type.metadata=dart.core::_List<dart.core::int>] core::_List::generate<core::int>((core::int i) → core::int => i), self::A::generateFactory4 = let final (core::int) → core::int #t7 = (core::int i) → core::int => i in let final core::bool #t8 = _in::unsafeCast<core::bool>([@vm.inferred-type.metadata=dart.core::bool] self::nonConstant()) in [@vm.inferred-type.metadata=!] core::List::generate<core::int>(#t7, #t8), self::A::generateFactory5 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::List<dart.core::int>>] core::_GrowableList::generate<core::List<core::int>>(2, (core::int _) → core::List<core::int> => core::_GrowableList::•<core::int>(0)), self::A::generateFactory6 = let final core::int #t9 = 2 in let final core::bool #t10 = true in [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] core::_GrowableList::generate<core::int>(#t9, (core::int i) → core::int => i), self::A::generateFactory7 = let final core::int #t11 = 2 in let final core::bool #t12 = false in [@vm.inferred-type.metadata=dart.core::_List<dart.core::int>] core::_List::generate<core::int>((core::int i) → core::int => i), super core::Object::•()
+[@vm.closure-id=7] synthetic constructor •() → self::A
+ : self::A::literal1 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] core::_GrowableList::•<core::int>(0), self::A::literal2 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] core::_GrowableList::_literal3<core::int>(1, 2, 3), self::A::filledFactory1 = [@vm.inferred-type.metadata=dart.core::_List<dart.core::int>] core::_List::filled<core::int>(2, 0), self::A::filledFactory2 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] core::_GrowableList::filled<core::int>(2, 0), self::A::filledFactory3 = [@vm.inferred-type.metadata=dart.core::_List<dart.core::int>] core::_List::filled<core::int>(2, 0), self::A::filledFactory4 = let final core::bool #t1 = _in::unsafeCast<core::bool>([@vm.inferred-type.metadata=dart.core::bool] self::nonConstant()) in [@vm.inferred-type.metadata=!] core::List::filled<core::int>(2, 0, #t1), self::A::filledFactory5 = [@vm.inferred-type.metadata=dart.core::_List<dart.core::int?>] core::_List::•<core::int?>(2), self::A::filledFactory6 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int?>] core::_GrowableList::•<core::int?>(2), self::A::filledFactory7 = [@vm.inferred-type.metadata=dart.core::_List<dart.core::int?>] core::_List::•<core::int?>(2), self::A::filledFactory8 = let final core::bool #t2 = _in::unsafeCast<core::bool>([@vm.inferred-type.metadata=dart.core::bool] self::nonConstant()) in [@vm.inferred-type.metadata=!] core::List::filled<core::int?>(2, null, #t2), self::A::filledFactory9 = let final core::int #t3 = 2 in let final core::bool #t4 = true in [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int?>] core::_GrowableList::•<core::int?>(#t3), self::A::filledFactory10 = let final core::int #t5 = 2 in let final core::bool #t6 = false in [@vm.inferred-type.metadata=dart.core::_List<dart.core::int?>] core::_List::•<core::int?>(#t5), self::A::generateFactory1 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] core::_GrowableList::generate<core::int>(2, [@vm.closure-id=1](core::int i) → core::int => i), self::A::generateFactory2 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] core::_GrowableList::generate<core::int>(2, [@vm.closure-id=2](core::int i) → core::int => i), self::A::generateFactory3 = [@vm.inferred-type.metadata=dart.core::_List<dart.core::int>] core::_List::generate<core::int>([@vm.closure-id=3](core::int i) → core::int => i), self::A::generateFactory4 = let final (core::int) → core::int #t7 = [@vm.closure-id=4](core::int i) → core::int => i in let final core::bool #t8 = _in::unsafeCast<core::bool>([@vm.inferred-type.metadata=dart.core::bool] self::nonConstant()) in [@vm.inferred-type.metadata=!] core::List::generate<core::int>(#t7, #t8), self::A::generateFactory5 = [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::List<dart.core::int>>] core::_GrowableList::generate<core::List<core::int>>(2, [@vm.closure-id=5](core::int _) → core::List<core::int> => core::_GrowableList::•<core::int>(0)), self::A::generateFactory6 = let final core::int #t9 = 2 in let final core::bool #t10 = true in [@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] core::_GrowableList::generate<core::int>(#t9, [@vm.closure-id=6](core::int i) → core::int => i), self::A::generateFactory7 = let final core::int #t11 = 2 in let final core::bool #t12 = false in [@vm.inferred-type.metadata=dart.core::_List<dart.core::int>] core::_List::generate<core::int>([@vm.closure-id=7](core::int i) → core::int => i), super core::Object::•()
;
}
static method nonConstant() → dynamic
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/null_test_elimination2.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/null_test_elimination2.dart.expect
index 73ea026..fb6ac8e 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/null_test_elimination2.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/null_test_elimination2.dart.expect
@@ -5,13 +5,13 @@
static method _defaultCheck([dynamic _ = #C1]) → core::bool
return true;
-static method testStaticTypeOfConditional<T extends core::Object? = dynamic>([@vm.inferred-arg-type.metadata=dart.core::_Closure] (self::testStaticTypeOfConditional::T%) →? core::bool check) → void {
+static method testStaticTypeOfConditional<T extends core::Object? = dynamic>([@vm.inferred-arg-type.metadata=dart.core::_Closure (closure 1 in #lib::main)] (self::testStaticTypeOfConditional::T%) →? core::bool check) → void {
if(#C2 is self::testStaticTypeOfConditional::T% && (let final (self::testStaticTypeOfConditional::T%) →? core::bool #t1 = check in _in::unsafeCast<core::Function>(#t1{(self::testStaticTypeOfConditional::T%) → core::bool}))(#C2) as{TypeError,ForDynamic} core::bool) {
core::print("ok");
}
}
-static method main() → void {
- self::testStaticTypeOfConditional<core::String>((core::String _) → core::bool => true);
+[@vm.closure-id=1]static method main() → void {
+ self::testStaticTypeOfConditional<core::String>([@vm.closure-id=1](core::String _) → core::bool => true);
}
constants {
#C1 = null
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/param_types_before_strong_mode_checks.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/param_types_before_strong_mode_checks.dart.expect
index bfd7bb7..7bd31a1 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/param_types_before_strong_mode_checks.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/param_types_before_strong_mode_checks.dart.expect
@@ -50,12 +50,12 @@
}
static method getDynamic() → dynamic
return self::unknown();
-static method use(dynamic x) → dynamic
+static method use([@vm.inferred-arg-type.metadata=dart.core::_Closure] dynamic x) → dynamic
return self::unknown(x);
static method main(core::List<core::String> args) → dynamic {
self::func1(self::getDynamic() as{TypeError,ForDynamic} self::T0);
self::use(#C1);
- self::use(new self::A::•().{self::A::method1}{(self::T0) → void});
+ self::use([@vm.inferred-type.metadata=dart.core::_Closure (closure 0 in #lib::A.method1)] new self::A::•().{self::A::method1}{(self::T0) → void});
self::B bb = self::getDynamic() as{TypeError,ForDynamic} self::B;
[@vm.direct-call.metadata=#lib::C.method2] [@vm.inferred-type.metadata=!? (skip check)] bb.{self::B::method2}(self::getDynamic()){(dynamic) → void};
self::getDynamic(){dynamic}.method3(self::getDynamic());
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/create_test.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/create_test.dart.expect
index ee20971..e3843a2 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/create_test.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/create_test.dart.expect
@@ -17,7 +17,7 @@
import "package:matcher/src/type_matcher.dart";
import "package:matcher/src/util.dart";
-static method main() → dynamic {
+[@vm.closure-id=1]static method main() → dynamic {
[@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep] pb::FooKeep foo = let final pb::FooKeep #t1 = [@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep] pb::FooKeep::•() in block {
[@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.barKeep] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pb::FooKeep::barKeep} = let final pb::BarKeep #t2 = [@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep] pb::BarKeep::•() in block {
[@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep.aKeep] [@vm.inferred-type.metadata=!? (skip check)] #t2.{pb::BarKeep::aKeep} = 5;
@@ -27,7 +27,7 @@
} =>#t3){(core::String, pb::BarKeep) → void};
[@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.aKeep] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pb::FooKeep::aKeep} = 43;
} =>#t1;
- sca::test(() → Null {
+ sca::test([@vm.closure-id=1]() → Null {
exp::expect([@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep.aKeep] [@vm.inferred-type.metadata=int] [@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.barKeep] [@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep] foo.{pb::FooKeep::barKeep}{pb::BarKeep}.{pb::BarKeep::aKeep}{core::int}, 5);
exp::expect([@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep.aKeep] [@vm.inferred-type.metadata=int] [@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep?] [@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.mapKeep] [@vm.inferred-type.metadata=!] foo.{pb::FooKeep::mapKeep}{core::Map<core::String, pb::BarKeep>}.{core::Map::[]}("foo"){(core::Object?) → pb::BarKeep?}!.{pb::BarKeep::aKeep}{core::int}, 2);
exp::expect([@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.hasHasKeep] [@vm.inferred-type.metadata=dart.core::bool (skip check)] foo.{pb::FooKeep::hasHasKeep}(){() → core::bool}, false);
@@ -47,7 +47,7 @@
[@vm.inferred-type.metadata=library package:protobuf/protobuf.dart::BuilderInfo] static final field pro::BuilderInfo _i = let final pro::BuilderInfo #t1 = new pro::BuilderInfo::•(#C1 ?{core::String} "" : "FooKeep") in block {
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.aOM] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::aOM}<self::BarKeep>(1, #C1 ?{core::String} "" : "barKeep", #C2){(core::int, core::String, {protoName: core::String?, required subBuilder: () → self::BarKeep}) → void};
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.add] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::add}<Null>(0, null, null, null, null){(core::int, core::String, core::int?, dynamic, () →? pro::GeneratedMessage, (core::int) →? pro::ProtobufEnum?, core::List<pro::ProtobufEnum>?, {protoName: core::String?}) → void};
- let final core::String #t2 = #C1 ?{core::String} "" : "mapKeep" in [@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.m] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::m}<core::String, self::BarKeep>(#C2){(core::int, core::String, {defaultEnumValue: pro::ProtobufEnum?, entryClassName: core::String?, enumValues: core::List<pro::ProtobufEnum>?, required keyFieldType: core::int, packageName: pro::PackageName, protoName: core::String?, valueCreator: () →? pro::GeneratedMessage, valueDefaultOrMaker: dynamic, required valueFieldType: core::int, valueOf: (core::int) →? pro::ProtobufEnum?}) → void};
+ let final core::String #t2 = #C1 ?{core::String} "" : "mapKeep" in [@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.m] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::m}<core::String, self::BarKeep>(){(core::int, core::String, {defaultEnumValue: pro::ProtobufEnum?, entryClassName: core::String?, enumValues: core::List<pro::ProtobufEnum>?, required keyFieldType: core::int, packageName: pro::PackageName, protoName: core::String?, valueCreator: () →? pro::GeneratedMessage, valueDefaultOrMaker: dynamic, required valueFieldType: core::int, valueOf: (core::int) →? pro::ProtobufEnum?}) → void};
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.add] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::add}<Null>(0, null, null, null, null){(core::int, core::String, core::int?, dynamic, () →? pro::GeneratedMessage, (core::int) →? pro::ProtobufEnum?, core::List<pro::ProtobufEnum>?, {protoName: core::String?}) → void};
let final core::String #t3 = #C1 ?{core::String} "" : "aKeep" in [@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.a] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::a}<core::int>(5){(core::int, core::String, core::int, {defaultOrMaker: dynamic, enumValues: core::List<pro::ProtobufEnum>?, protoName: core::String?, subBuilder: () →? pro::GeneratedMessage, valueOf: (core::int) →? pro::ProtobufEnum?}) → void};
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.aOM] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::aOM}<self::HasKeep>(6, #C1 ?{core::String} "" : "hasKeep", #C3){(core::int, core::String, {protoName: core::String?, required subBuilder: () → self::HasKeep}) → void};
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/decode_test.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/decode_test.dart.expect
index ea6bed4..123d7b1 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/decode_test.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/decode_test.dart.expect
@@ -18,9 +18,9 @@
import "package:matcher/src/util.dart";
[@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>]static field core::List<core::int> buffer = <core::int>[10, 4, 8, 5, 16, 4, 26, 9, 10, 3, 102, 111, 111, 18, 2, 8, 42, 34, 9, 10, 3, 122, 111, 112, 18, 2, 8, 3, 40, 43, 50, 0, 58, 0];
-static method main() → dynamic {
+[@vm.closure-id=1]static method main() → dynamic {
[@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep] pb::FooKeep foo = [@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep] pb::FooKeep::fromBuffer([@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::int>] self::buffer);
- sca::test(() → Null {
+ sca::test([@vm.closure-id=1]() → Null {
exp::expect([@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep.aKeep] [@vm.inferred-type.metadata=int] [@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep?] [@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.mapKeep] [@vm.inferred-type.metadata=!] foo.{pb::FooKeep::mapKeep}{core::Map<core::String, pb::BarKeep>}.{core::Map::[]}("foo"){(core::Object?) → pb::BarKeep?}!.{pb::BarKeep::aKeep}{core::int}, 42);
exp::expect([@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep.aKeep] [@vm.inferred-type.metadata=int] [@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.barKeep] [@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep] foo.{pb::FooKeep::barKeep}{pb::BarKeep}.{pb::BarKeep::aKeep}{core::int}, 5);
exp::expect([@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.aKeep] [@vm.inferred-type.metadata=int] foo.{pb::FooKeep::aKeep}{core::int}, 43);
@@ -40,7 +40,7 @@
[@vm.inferred-type.metadata=library package:protobuf/protobuf.dart::BuilderInfo] static final field pro::BuilderInfo _i = let final pro::BuilderInfo #t1 = new pro::BuilderInfo::•(#C1 ?{core::String} "" : "FooKeep", createEmptyInstance: #C2) in block {
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.aOM] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::aOM}<self::BarKeep>(1, #C1 ?{core::String} "" : "barKeep", #C3){(core::int, core::String, {protoName: core::String?, required subBuilder: () → self::BarKeep}) → void};
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.add] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::add}<Null>(0, null, null, null, null){(core::int, core::String, core::int?, dynamic, () →? pro::GeneratedMessage, (core::int) →? pro::ProtobufEnum?, core::List<pro::ProtobufEnum>?, {protoName: core::String?}) → void};
- let final core::String #t2 = #C1 ?{core::String} "" : "mapKeep" in [@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.m] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::m}<core::String, self::BarKeep>(#C3){(core::int, core::String, {defaultEnumValue: pro::ProtobufEnum?, entryClassName: core::String?, enumValues: core::List<pro::ProtobufEnum>?, required keyFieldType: core::int, packageName: pro::PackageName, protoName: core::String?, valueCreator: () →? pro::GeneratedMessage, valueDefaultOrMaker: dynamic, required valueFieldType: core::int, valueOf: (core::int) →? pro::ProtobufEnum?}) → void};
+ let final core::String #t2 = #C1 ?{core::String} "" : "mapKeep" in [@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.m] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::m}<core::String, self::BarKeep>(){(core::int, core::String, {defaultEnumValue: pro::ProtobufEnum?, entryClassName: core::String?, enumValues: core::List<pro::ProtobufEnum>?, required keyFieldType: core::int, packageName: pro::PackageName, protoName: core::String?, valueCreator: () →? pro::GeneratedMessage, valueDefaultOrMaker: dynamic, required valueFieldType: core::int, valueOf: (core::int) →? pro::ProtobufEnum?}) → void};
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.add] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::add}<Null>(0, null, null, null, null){(core::int, core::String, core::int?, dynamic, () →? pro::GeneratedMessage, (core::int) →? pro::ProtobufEnum?, core::List<pro::ProtobufEnum>?, {protoName: core::String?}) → void};
let final core::String #t3 = #C1 ?{core::String} "" : "aKeep" in [@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.a] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::a}<core::int>(5){(core::int, core::String, core::int, {defaultOrMaker: dynamic, enumValues: core::List<pro::ProtobufEnum>?, protoName: core::String?, subBuilder: () →? pro::GeneratedMessage, valueOf: (core::int) →? pro::ProtobufEnum?}) → void};
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.aOM] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::aOM}<self::HasKeep>(6, #C1 ?{core::String} "" : "hasKeep", #C4){(core::int, core::String, {protoName: core::String?, required subBuilder: () → self::HasKeep}) → void};
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/freeze_test.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/freeze_test.dart.expect
index 6929208..cfe746a 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/freeze_test.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/freeze_test.dart.expect
@@ -20,7 +20,7 @@
import "package:matcher/src/type_matcher.dart";
import "package:matcher/src/util.dart";
-static method main() → dynamic {
+[@vm.closure-id=2]static method main() → dynamic {
[@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep] pb::FooKeep foo = let final pb::FooKeep #t1 = [@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep] pb::FooKeep::•() in block {
[@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.barKeep] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pb::FooKeep::barKeep} = let final pb::BarKeep #t2 = [@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep] pb::BarKeep::•() in block {
[@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep.aKeep] [@vm.inferred-type.metadata=!? (skip check)] #t2.{pb::BarKeep::aKeep} = 5;
@@ -30,13 +30,13 @@
} =>#t3){(core::String, pb::BarKeep) → void};
[@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.aKeep] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pb::FooKeep::aKeep} = 43;
} =>#t1;
- sca::test(() → Null {
+ sca::test([@vm.closure-id=1]() → Null {
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::GeneratedMessage.freeze] [@vm.inferred-type.metadata=!? (skip check)] foo.{pro::GeneratedMessage::freeze}(){() → pro::GeneratedMessage};
exp::expect([@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep.aKeep] [@vm.inferred-type.metadata=int] [@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.barKeep] [@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep] foo.{pb::FooKeep::barKeep}{pb::BarKeep}.{pb::BarKeep::aKeep}{core::int}, 5);
exp::expect([@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep.aKeep] [@vm.inferred-type.metadata=int] [@vm.inferred-type.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::BarKeep?] [@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.mapKeep] [@vm.inferred-type.metadata=!] foo.{pb::FooKeep::mapKeep}{core::Map<core::String, pb::BarKeep>}.{core::Map::[]}("foo"){(core::Object?) → pb::BarKeep?}!.{pb::BarKeep::aKeep}{core::int}, 2);
exp::expect([@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.hasHasKeep] [@vm.inferred-type.metadata=dart.core::bool (skip check)] foo.{pb::FooKeep::hasHasKeep}(){() → core::bool}, false);
exp::expect([@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.aKeep] [@vm.inferred-type.metadata=int] foo.{pb::FooKeep::aKeep}{core::int}, 43);
- exp::expect(() → void => [@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.clearClearKeep] [@vm.inferred-type.metadata=!? (skip check)] foo.{pb::FooKeep::clearClearKeep}(){() → void}, [@vm.inferred-type.metadata=library package:matcher/src/expect/throws_matcher.dart::Throws] thr::throwsA());
+ exp::expect([@vm.closure-id=2]() → void => [@vm.direct-call.metadata=library file:pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/generated/foo.pb.dart::FooKeep.clearClearKeep] [@vm.inferred-type.metadata=!? (skip check)] foo.{pb::FooKeep::clearClearKeep}(){() → void}, [@vm.inferred-type.metadata=library package:matcher/src/expect/throws_matcher.dart::Throws] thr::throwsA());
});
}
library foo.pb.dart;
@@ -51,7 +51,7 @@
[@vm.inferred-type.metadata=library package:protobuf/protobuf.dart::BuilderInfo] static final field pro::BuilderInfo _i = let final pro::BuilderInfo #t1 = new pro::BuilderInfo::•(#C1 ?{core::String} "" : "FooKeep") in block {
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.aOM] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::aOM}<self::BarKeep>(1, #C1 ?{core::String} "" : "barKeep", #C2){(core::int, core::String, {protoName: core::String?, required subBuilder: () → self::BarKeep}) → void};
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.add] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::add}<Null>(0, null, null, null, null){(core::int, core::String, core::int?, dynamic, () →? pro::GeneratedMessage, (core::int) →? pro::ProtobufEnum?, core::List<pro::ProtobufEnum>?, {protoName: core::String?}) → void};
- let final core::String #t2 = #C1 ?{core::String} "" : "mapKeep" in [@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.m] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::m}<core::String, self::BarKeep>(#C2){(core::int, core::String, {defaultEnumValue: pro::ProtobufEnum?, entryClassName: core::String?, enumValues: core::List<pro::ProtobufEnum>?, required keyFieldType: core::int, packageName: pro::PackageName, protoName: core::String?, valueCreator: () →? pro::GeneratedMessage, valueDefaultOrMaker: dynamic, required valueFieldType: core::int, valueOf: (core::int) →? pro::ProtobufEnum?}) → void};
+ let final core::String #t2 = #C1 ?{core::String} "" : "mapKeep" in [@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.m] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::m}<core::String, self::BarKeep>(){(core::int, core::String, {defaultEnumValue: pro::ProtobufEnum?, entryClassName: core::String?, enumValues: core::List<pro::ProtobufEnum>?, required keyFieldType: core::int, packageName: pro::PackageName, protoName: core::String?, valueCreator: () →? pro::GeneratedMessage, valueDefaultOrMaker: dynamic, required valueFieldType: core::int, valueOf: (core::int) →? pro::ProtobufEnum?}) → void};
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.add] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::add}<Null>(0, null, null, null, null){(core::int, core::String, core::int?, dynamic, () →? pro::GeneratedMessage, (core::int) →? pro::ProtobufEnum?, core::List<pro::ProtobufEnum>?, {protoName: core::String?}) → void};
let final core::String #t3 = #C1 ?{core::String} "" : "aKeep" in [@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.a] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::a}<core::int>(5){(core::int, core::String, core::int, {defaultOrMaker: dynamic, enumValues: core::List<pro::ProtobufEnum>?, protoName: core::String?, subBuilder: () →? pro::GeneratedMessage, valueOf: (core::int) →? pro::ProtobufEnum?}) → void};
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.aOM] [@vm.inferred-type.metadata=!? (skip check)] #t1.{pro::BuilderInfo::aOM}<self::HasKeep>(6, #C1 ?{core::String} "" : "hasKeep", #C3){(core::int, core::String, {protoName: core::String?, required subBuilder: () → self::HasKeep}) → void};
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/name_mangling_test.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/name_mangling_test.dart.expect
index c28c3cd..2efe6aa 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/name_mangling_test.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/name_mangling_test.dart.expect
@@ -34,7 +34,7 @@
}
class NameManglingKeep extends pro::GeneratedMessage {
[@vm.inferred-type.metadata=library package:protobuf/protobuf.dart::BuilderInfo] static final field pro::BuilderInfo _i = let final pro::BuilderInfo #t2 = new pro::BuilderInfo::•(#C1 ?{core::String} "" : "NameManglingKeep", #C6) in block {
- let final core::String #t3 = #C1 ?{core::String} "" : "clone" in [@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.aOM] [@vm.inferred-type.metadata=!? (skip check)] #t2.{pro::BuilderInfo::aOM}<self::AKeep>(#C2){(core::int, core::String, {protoName: core::String?, required subBuilder: () → self::AKeep}) → void};
+ let final core::String #t3 = #C1 ?{core::String} "" : "clone" in [@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.aOM] [@vm.inferred-type.metadata=!? (skip check)] #t2.{pro::BuilderInfo::aOM}<self::AKeep>(){(core::int, core::String, {protoName: core::String?, required subBuilder: () → self::AKeep}) → void};
[@vm.direct-call.metadata=library package:protobuf/protobuf.dart::BuilderInfo.hasRequiredFields] [@vm.inferred-type.metadata=!? (skip check)] #t2.{pro::BuilderInfo::hasRequiredFields} = false;
} =>#t2;
constructor _() → self::NameManglingKeep
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
index bae6c58..07dffe4 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
@@ -112,9 +112,9 @@
}
[@vm.inferred-type.metadata=dart.core::bool?]static field core::bool? ok;
[@vm.inferred-type.metadata=#lib::B3?]static field dynamic bb3 = new self::B3::•();
-[@vm.inferred-type.metadata=dart.core::_Closure]static field core::Function unknown3 = () → dynamic => self::bb3;
+[@vm.inferred-type.metadata=dart.core::_Closure (closure 1 in #lib::unknown3)] [@vm.closure-id=1]static field core::Function unknown3 = [@vm.closure-id=1]() → dynamic => self::bb3;
[@vm.inferred-type.metadata=#lib::B4?]static field dynamic bb4 = new self::B4::•();
-[@vm.inferred-type.metadata=dart.core::_Closure]static field core::Function unknown4 = () → dynamic => self::bb4;
+[@vm.inferred-type.metadata=dart.core::_Closure (closure 1 in #lib::unknown4)] [@vm.closure-id=1]static field core::Function unknown4 = [@vm.closure-id=1]() → dynamic => self::bb4;
static method test1() → void {
self::B1 bb = new self::B1::•();
let final self::B1 #t1 = bb in let final core::int #t2 = 1 in let final core::int #t3 = 2 in let final core::int #t4 = 3 in let final core::int #t5 = 4 in let final self::T1 #t6 = new self::T1::•() in [@vm.direct-call.metadata=#lib::A1.call] [@vm.inferred-type.metadata=!? (skip check)] [@vm.direct-call.metadata=#lib::B1.aa1] [@vm.inferred-type.metadata=#lib::A1] #t1.{self::B1::aa1}{self::A1}.{self::A1::call}(#t2, #t3, #t4, #t5, #t6){([dynamic, dynamic, dynamic, dynamic, dynamic]) → void};
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter81068.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter81068.dart.expect
index 95580c3..0b8a3d1 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter81068.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter81068.dart.expect
@@ -17,11 +17,11 @@
;
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2] method noSuchMethod(core::Invocation i) → dynamic
return throw "Not implemented";
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4] no-such-method-forwarder method then<R extends core::Object? = dynamic>((self::B::T%) → FutureOr<self::B::then::R%>onValue, {core::Function? onError = #C1}) → asy::Future<self::B::then::R%>
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4] no-such-method-forwarder method then<R extends core::Object? = dynamic>([@vm.inferred-arg-type.metadata=dart.core::_Closure] (self::B::T%) → FutureOr<self::B::then::R%>onValue, {[@vm.inferred-arg-type.metadata=dart.core::_Closure?] core::Function? onError = #C1}) → asy::Future<self::B::then::R%>
return _in::unsafeCast<asy::Future<self::B::then::R%>>([@vm.direct-call.metadata=#lib::B.noSuchMethod] [@vm.inferred-type.metadata=! (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C2, 0, [@vm.inferred-type.metadata=dart.core::_ImmutableList] core::List::unmodifiable<core::Type*>([@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::Type*>] core::_GrowableList::_literal1<core::Type*>(self::B::then::R%)), [@vm.inferred-type.metadata=dart.core::_ImmutableList] core::List::unmodifiable<dynamic>([@vm.inferred-type.metadata=dart.core::_GrowableList<dynamic>] core::_GrowableList::_literal1<dynamic>(onValue)), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol*, dynamic>] core::Map::unmodifiable<core::Symbol*, dynamic>(<core::Symbol*, dynamic>{#C3: onError}))){(core::Invocation) → dynamic});
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6] no-such-method-forwarder method catchError([@vm.inferred-arg-type.metadata=dart.core::_Closure] core::Function onError) → asy::Future<self::B::T%>
return _in::unsafeCast<asy::Future<self::B::T%>>([@vm.direct-call.metadata=#lib::B.noSuchMethod] [@vm.inferred-type.metadata=! (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C4, 0, #C5, [@vm.inferred-type.metadata=dart.core::_ImmutableList] core::List::unmodifiable<dynamic>([@vm.inferred-type.metadata=dart.core::_GrowableList<dynamic>] core::_GrowableList::_literal1<dynamic>(onError)), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol*, dynamic>] core::Map::unmodifiable<core::Symbol*, dynamic>(<core::Symbol*, dynamic>{#C6: #C1}))){(core::Invocation) → dynamic});
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8] no-such-method-forwarder method whenComplete(() → FutureOr<void>action) → asy::Future<self::B::T%>
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8] no-such-method-forwarder method whenComplete([@vm.inferred-arg-type.metadata=dart.core::_Closure] () → FutureOr<void>action) → asy::Future<self::B::T%>
return _in::unsafeCast<asy::Future<self::B::T%>>([@vm.direct-call.metadata=#lib::B.noSuchMethod] [@vm.inferred-type.metadata=! (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 0, #C5, [@vm.inferred-type.metadata=dart.core::_ImmutableList] core::List::unmodifiable<dynamic>([@vm.inferred-type.metadata=dart.core::_GrowableList<dynamic>] core::_GrowableList::_literal1<dynamic>(action)), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol*, dynamic>] core::Map::unmodifiable<core::Symbol*, dynamic>(#C8))){(core::Invocation) → dynamic});
}
static method createB<T extends core::Object? = dynamic>() → self::B<dynamic>
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect
index 2d569fc..d1c2fe2 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect
@@ -15,10 +15,10 @@
return [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=! (skip check)] 1.{core::num::+}([@vm.direct-call.metadata=#lib::B.foo] [@vm.inferred-type.metadata=!? (receiver not int)] [@vm.inferred-type.metadata=#lib::B] self::knownResult(){dynamic}.foo() as{TypeError,ForDynamic} core::num){(core::num) → core::num} as core::int;
}
class TearOffDynamicMethod extends core::Object {
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4] field dynamic bazz;
+[@vm.inferred-type.metadata=dart.core::_Closure (closure 0 in #lib::B.foo)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4] field dynamic bazz;
constructor •(dynamic arg) → self::TearOffDynamicMethod
- : self::TearOffDynamicMethod::bazz = arg{dynamic}.foo, super core::Object::•() {
- [@vm.direct-call.metadata=#lib::TearOffDynamicMethod.bazz] this.{self::TearOffDynamicMethod::bazz}{dynamic}{dynamic}.call();
+ : self::TearOffDynamicMethod::bazz = [@vm.inferred-type.metadata=dart.core::_Closure (closure 0 in #lib::B.foo)] arg{dynamic}.foo, super core::Object::•() {
+ [@vm.inferred-type.metadata=!? (receiver not int)] [@vm.direct-call.metadata=#lib::TearOffDynamicMethod.bazz] [@vm.inferred-type.metadata=dart.core::_Closure (closure 0 in #lib::B.foo)] this.{self::TearOffDynamicMethod::bazz}{dynamic}{dynamic}.call();
}
}
static method knownResult() → dynamic
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
index c35c81d..cd8b2e5 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
@@ -19,13 +19,13 @@
return 3;
}
class TearOffInterfaceMethod extends core::Object {
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6] field dynamic bazz;
+[@vm.inferred-type.metadata=dart.core::_Closure (closure 0 in #lib::B.foo)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6] field dynamic bazz;
constructor •([@vm.inferred-arg-type.metadata=#lib::B] self::A arg) → self::TearOffInterfaceMethod
- : self::TearOffInterfaceMethod::bazz = arg.{self::A::foo}{() → core::int}, super core::Object::•()
+ : self::TearOffInterfaceMethod::bazz = [@vm.inferred-type.metadata=dart.core::_Closure (closure 0 in #lib::B.foo)] arg.{self::A::foo}{() → core::int}, super core::Object::•()
;
}
static method knownResult() → dynamic
return new self::B::•();
static method main(core::List<core::String> args) → dynamic {
- [@vm.direct-call.metadata=#lib::TearOffInterfaceMethod.bazz] new self::TearOffInterfaceMethod::•(new self::B::•()).{self::TearOffInterfaceMethod::bazz}{dynamic}{dynamic}.call();
+ [@vm.inferred-type.metadata=!? (receiver not int)] [@vm.direct-call.metadata=#lib::TearOffInterfaceMethod.bazz] [@vm.inferred-type.metadata=dart.core::_Closure (closure 0 in #lib::B.foo)] new self::TearOffInterfaceMethod::•(new self::B::•()).{self::TearOffInterfaceMethod::bazz}{dynamic}{dynamic}.call();
}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect
index c226a22..b079063 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect
@@ -24,15 +24,15 @@
;
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,methodOrSetterSelectorId:3,getterSelectorId:4] [@vm.unboxing-info.metadata=()->i] method foo() → core::int
return _in::unsafeCast<core::int>([@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] 3.{core::num::+}(_in::unsafeCast<core::num>([@vm.direct-call.metadata=#lib::B.foo] [@vm.inferred-type.metadata=int (receiver not int)] [@vm.inferred-type.metadata=#lib::B] self::knownResult(){dynamic}.foo())){(core::num) → core::num});
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6] method doCall(dynamic x) → core::int?
- return x{dynamic}.call() as{TypeError,ForDynamic} core::int?;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6] method doCall([@vm.inferred-arg-type.metadata=dart.core::_Closure (closure 0 in #lib::Base.foo)] dynamic x) → core::int?
+ return [@vm.inferred-type.metadata=!? (receiver not int)] x{dynamic}.call() as{TypeError,ForDynamic} core::int?;
}
class TearOffSuperMethod extends self::Base {
synthetic constructor •() → self::TearOffSuperMethod
: super self::Base::•()
;
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8] method bar() → core::int?
- return [@vm.direct-call.metadata=#lib::Base.doCall] [@vm.inferred-type.metadata=int? (skip check)] this.{self::Base::doCall}(super.{self::Base::foo}){(dynamic) → core::int?};
+ return [@vm.direct-call.metadata=#lib::Base.doCall] [@vm.inferred-type.metadata=int? (skip check)] this.{self::Base::doCall}([@vm.inferred-type.metadata=dart.core::_Closure (closure 0 in #lib::Base.foo)] super.{self::Base::foo}){(dynamic) → core::int?};
}
[@vm.inferred-type.metadata=#lib::B]static field self::A aa = new self::B::•();
static method knownResult() → dynamic
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/unboxed_instance_method_tearoff.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/unboxed_instance_method_tearoff.dart.expect
index e53c68e..2333532 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/unboxed_instance_method_tearoff.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/unboxed_instance_method_tearoff.dart.expect
@@ -170,14 +170,14 @@
self::use([@vm.inferred-type.metadata=dart.core::_Double?] d.{self::Interface::returnBoxedNullableIntOrDouble}(null){(self::X?) → dynamic});
self::use([@vm.inferred-type.metadata=#lib::X?] d.{self::Interface::returnBoxedNullableX}(null){(self::X?) → dynamic});
self::use([@vm.inferred-type.metadata=#lib::X] d.{self::Interface::returnBoxedX}(null){(self::X?) → dynamic});
- self::use(d.{self::Interface::takePositional}{(core::int?, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic) → void});
- self::use(d.{self::Interface::returnUnboxedSmi}{(self::X?) → dynamic});
- self::use(d.{self::Interface::returnUnboxedInt}{(self::X?) → dynamic});
- self::use(d.{self::Interface::returnUnboxedDouble}{(self::X?) → dynamic});
- self::use(d.{self::Interface::returnBoxedNullableInt}{(self::X?) → dynamic});
- self::use(d.{self::Interface::returnBoxedNullableDouble}{(self::X?) → dynamic});
- self::use(d.{self::Interface::returnBoxedIntOrDouble}{(self::X?) → dynamic});
- self::use(d.{self::Interface::returnBoxedNullableIntOrDouble}{(self::X?) → dynamic});
- self::use(d.{self::Interface::returnBoxedNullableX}{(self::X?) → dynamic});
- self::use(d.{self::Interface::returnBoxedX}{(self::X?) → dynamic});
+ self::use([@vm.inferred-type.metadata=dart.core::_Closure] d.{self::Interface::takePositional}{(core::int?, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic) → void});
+ self::use([@vm.inferred-type.metadata=dart.core::_Closure] d.{self::Interface::returnUnboxedSmi}{(self::X?) → dynamic});
+ self::use([@vm.inferred-type.metadata=dart.core::_Closure] d.{self::Interface::returnUnboxedInt}{(self::X?) → dynamic});
+ self::use([@vm.inferred-type.metadata=dart.core::_Closure] d.{self::Interface::returnUnboxedDouble}{(self::X?) → dynamic});
+ self::use([@vm.inferred-type.metadata=dart.core::_Closure] d.{self::Interface::returnBoxedNullableInt}{(self::X?) → dynamic});
+ self::use([@vm.inferred-type.metadata=dart.core::_Closure] d.{self::Interface::returnBoxedNullableDouble}{(self::X?) → dynamic});
+ self::use([@vm.inferred-type.metadata=dart.core::_Closure] d.{self::Interface::returnBoxedIntOrDouble}{(self::X?) → dynamic});
+ self::use([@vm.inferred-type.metadata=dart.core::_Closure] d.{self::Interface::returnBoxedNullableIntOrDouble}{(self::X?) → dynamic});
+ self::use([@vm.inferred-type.metadata=dart.core::_Closure] d.{self::Interface::returnBoxedNullableX}{(self::X?) → dynamic});
+ self::use([@vm.inferred-type.metadata=dart.core::_Closure] d.{self::Interface::returnBoxedX}{(self::X?) → dynamic});
}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/weak.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/weak.dart.expect
index 9ba6795..624fcc0 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/weak.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/weak.dart.expect
@@ -4,7 +4,7 @@
class A extends core::Object {
[@vm.inferred-type.metadata=dart.core::_Smi (value: 1)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2] [@vm.unboxing-info.metadata=(i)->i] field core::int x;
-[@vm.inferred-type.metadata=dart.core::_Closure] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4] field core::Function y = #C1;
+[@vm.inferred-type.metadata=dart.core::_Closure (value: #lib::used2) (closure 0 in #lib::used2)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4] field core::Function y = #C1;
synthetic constructor •() → self::A
: self::A::x = [@vm.inferred-type.metadata=dart.core::_Smi (value: 1)] self::used1(), super core::Object::•()
;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field2.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field2.dart.expect
index 8c4e04c..b2dc6a9 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field2.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field2.dart.expect
@@ -52,11 +52,11 @@
}
}
static method foo() → dynamic {}
-static method main() → void {
+[@vm.closure-id=1]static method main() → void {
new self::A::•();
new self::B::•();
[@vm.inferred-type.metadata=#lib::D] self::C<core::num> c = new self::D::•();
- exp::Expect::throws<core::Object>(() → void {
+ exp::Expect::throws<core::Object>([@vm.closure-id=1]() → void {
[@vm.call-site-attributes.metadata=receiverType:#lib::C<dart.core::num>] [@vm.direct-call.metadata=#lib::D.bar] c.{self::C::bar} = 3.14;
});
self::E e = new self::F::•();
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index 7e5a605..6674771 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -594,11 +594,9 @@
const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg);
switch (opcode) {
case CodeSourceMapOps::kChangePosition: {
- const TokenPosition& old_token =
- (*token_positions)[token_positions->length() - 1];
- (*token_positions)[token_positions->length() - 1] =
- TokenPosition::Deserialize(
- Utils::AddWithWrapAround(arg, old_token.Serialize()));
+ const TokenPosition& old_token = token_positions->Last();
+ token_positions->Last() = TokenPosition::Deserialize(
+ Utils::AddWithWrapAround(arg, old_token.Serialize()));
break;
}
case CodeSourceMapOps::kAdvancePC: {
@@ -692,12 +690,14 @@
void CodeSourceMapReader::DumpInlineIntervals(uword start) {
GrowableArray<const Function*> function_stack;
+ GrowableArray<TokenPosition> token_positions;
LogBlock lb;
NoSafepointScope no_safepoint;
ReadStream stream(map_.Data(), map_.Length());
int32_t current_pc_offset = 0;
function_stack.Add(&root_);
+ token_positions.Add(InitialPosition());
THR_Print("Inline intervals for function '%s' {\n",
root_.ToFullyQualifiedCString());
@@ -706,13 +706,19 @@
const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg);
switch (opcode) {
case CodeSourceMapOps::kChangePosition: {
+ const TokenPosition& old_token = token_positions.Last();
+ token_positions.Last() = TokenPosition::Deserialize(
+ Utils::AddWithWrapAround(arg, old_token.Serialize()));
break;
}
case CodeSourceMapOps::kAdvancePC: {
THR_Print("%" Px "-%" Px ": ", start + current_pc_offset,
start + current_pc_offset + arg - 1);
for (intptr_t i = 0; i < function_stack.length(); i++) {
- THR_Print("%s ", function_stack[i]->ToCString());
+ THR_Print("%s", function_stack[i]->ToCString());
+ if (token_positions[i].IsReal()) {
+ THR_Print(" @%" Pd, token_positions[i].Pos());
+ }
}
THR_Print("\n");
current_pc_offset += arg;
@@ -721,12 +727,15 @@
case CodeSourceMapOps::kPushFunction: {
function_stack.Add(
&Function::Handle(Function::RawCast(functions_.At(arg))));
+ token_positions.Add(InitialPosition());
break;
}
case CodeSourceMapOps::kPopFunction: {
// We never pop the root function.
ASSERT(function_stack.length() > 1);
+ ASSERT(token_positions.length() > 1);
function_stack.RemoveLast();
+ token_positions.RemoveLast();
break;
}
case CodeSourceMapOps::kNullCheck: {
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 8b8f7f4..35655e6 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -3912,7 +3912,7 @@
Array& argument_names =
Array::ZoneHandle(Z, GetOptionalParameterNames(function));
- closure += StaticCall(TokenPosition::kNoSource, target, argument_count,
+ closure += StaticCall(function.token_pos(), target, argument_count,
argument_names, ICData::kNoRebind,
/* result_type = */ nullptr, type_args_len);