[dart2js] Add tracing of types through records in global inference.
Change-Id: I4abdb76caecc91c89792396ff7d3fe4060cc7bc5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/289904 Commit-Queue: Nate Biggs <natebiggs@google.com> Reviewed-by: Stephen Adams <sra@google.com>
This commit is contained in:
@@ -34,6 +34,7 @@ import 'debug.dart' as debug;
|
||||
import 'locals_handler.dart';
|
||||
import 'list_tracer.dart';
|
||||
import 'map_tracer.dart';
|
||||
import 'record_tracer.dart';
|
||||
import 'set_tracer.dart';
|
||||
import 'type_graph_dump.dart';
|
||||
import 'type_graph_nodes.dart';
|
||||
@@ -311,6 +312,18 @@ class InferrerEngine {
|
||||
_workQueue.add(info);
|
||||
}
|
||||
|
||||
void analyzeRecordAndEnqueue(RecordTypeInformation info) {
|
||||
if (info.analyzed) return;
|
||||
info.analyzed = true;
|
||||
RecordTracerVisitor tracer = RecordTracerVisitor(info, this);
|
||||
|
||||
bool succeeded = tracer.run();
|
||||
if (!succeeded) return;
|
||||
|
||||
info.bailedOut = false;
|
||||
_workQueue.add(info);
|
||||
}
|
||||
|
||||
void runOverAllElements() {
|
||||
metrics.time.measure(_runOverAllElements);
|
||||
}
|
||||
|
||||
@@ -104,30 +104,35 @@ abstract class TracerVisitor implements TypeInformationVisitor {
|
||||
int.fromEnvironment('dart2js.tracing.limit', defaultValue: 32);
|
||||
// TODO(natebiggs): We allow null here to maintain current functionality
|
||||
// but we should verify we actually need to allow it.
|
||||
final Setlet<MemberEntity?> analyzedElements = Setlet<MemberEntity?>();
|
||||
final Setlet<MemberEntity?> analyzedElements = Setlet();
|
||||
|
||||
TracerVisitor(this.tracedType, this.inferrer);
|
||||
|
||||
/// Work list that gets populated with [TypeInformation] that could
|
||||
/// contain the container.
|
||||
final List<TypeInformation> workList = <TypeInformation>[];
|
||||
final List<TypeInformation> workList = [];
|
||||
|
||||
/// Work list of lists to analyze after analyzing the users of a
|
||||
/// [TypeInformation]. We know the [tracedType] has been stored in these
|
||||
/// lists and we must check how it escapes from these lists.
|
||||
final List<ListTypeInformation> listsToAnalyze = <ListTypeInformation>[];
|
||||
final List<ListTypeInformation> listsToAnalyze = [];
|
||||
|
||||
/// Work list of sets to analyze after analyzing the users of a
|
||||
/// [TypeInformation]. We know the [tracedType] has been stored in these sets
|
||||
/// and we must check how it escapes from these sets.
|
||||
final List<SetTypeInformation> setsToAnalyze = <SetTypeInformation>[];
|
||||
final List<SetTypeInformation> setsToAnalyze = [];
|
||||
|
||||
/// Work list of maps to analyze after analyzing the users of a
|
||||
/// [TypeInformation]. We know the [tracedType] has been stored in these
|
||||
/// maps and we must check how it escapes from these maps.
|
||||
final List<MapTypeInformation> mapsToAnalyze = <MapTypeInformation>[];
|
||||
final List<MapTypeInformation> mapsToAnalyze = [];
|
||||
|
||||
final Setlet<TypeInformation> flowsInto = Setlet<TypeInformation>();
|
||||
/// Work list of records to analyze after analyzing the users of a
|
||||
/// [TypeInformation]. We know the [tracedType] has been stored in these
|
||||
/// records and we must check how it escapes from these records.
|
||||
final List<RecordTypeInformation> recordsToAnalyze = [];
|
||||
|
||||
final Setlet<TypeInformation> flowsInto = Setlet();
|
||||
|
||||
// The current [TypeInformation] in the analysis.
|
||||
TypeInformation? currentUser;
|
||||
@@ -175,6 +180,9 @@ abstract class TracerVisitor implements TypeInformationVisitor {
|
||||
while (!mapsToAnalyze.isEmpty) {
|
||||
analyzeStoredIntoMap(mapsToAnalyze.removeLast());
|
||||
}
|
||||
while (!recordsToAnalyze.isEmpty) {
|
||||
analyzeStoredIntoRecord(recordsToAnalyze.removeLast());
|
||||
}
|
||||
if (!continueAnalyzing) break;
|
||||
}
|
||||
}
|
||||
@@ -229,9 +237,7 @@ abstract class TracerVisitor implements TypeInformationVisitor {
|
||||
|
||||
@override
|
||||
void visitRecordFieldAccessTypeInformation(
|
||||
RecordFieldAccessTypeInformation info) {
|
||||
addNewEscapeInformation(info);
|
||||
}
|
||||
RecordFieldAccessTypeInformation info) {}
|
||||
|
||||
@override
|
||||
void visitValueInMapTypeInformation(ValueInMapTypeInformation info) {
|
||||
@@ -255,8 +261,7 @@ abstract class TracerVisitor implements TypeInformationVisitor {
|
||||
|
||||
@override
|
||||
void visitRecordTypeInformation(RecordTypeInformation info) {
|
||||
// TODO(50701): Implement better inference for records.
|
||||
bailout('Used as field of Record');
|
||||
recordsToAnalyze.add(info);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -346,6 +351,22 @@ abstract class TracerVisitor implements TypeInformationVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
void analyzeStoredIntoRecord(RecordTypeInformation record) {
|
||||
inferrer.analyzeRecordAndEnqueue(record);
|
||||
|
||||
record.flowsInto.forEach((TypeInformation flow) {
|
||||
flow.users.forEach((TypeInformation user) {
|
||||
if (user is RecordFieldAccessTypeInformation) {
|
||||
final getterIndex =
|
||||
record.recordShape.indexOfGetterName(user.getterName);
|
||||
if (user.receiver != flow ||
|
||||
record.fieldTypes.indexOf(currentUser!) != getterIndex) return;
|
||||
addNewEscapeInformation(user);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// Checks whether this is a call to a list adding method. The definition of
|
||||
/// what list adding means has to stay in sync with
|
||||
/// [isParameterOfListAddingMethod].
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// 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 'node_tracer.dart';
|
||||
import 'type_graph_nodes.dart';
|
||||
|
||||
class RecordTracerVisitor extends TracerVisitor {
|
||||
RecordTracerVisitor(super.tracedType, super.inferrer);
|
||||
|
||||
bool run() {
|
||||
analyze();
|
||||
final record = tracedType as RecordTypeInformation;
|
||||
if (continueAnalyzing) {
|
||||
record.addFlowsIntoTargets(flowsInto);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2052,7 +2052,7 @@ class ValueInMapTypeInformation extends InferredTypeInformation {
|
||||
|
||||
/// A [RecordTypeInformation] is the constructor for a record, used for Record
|
||||
/// constants and literals.
|
||||
class RecordTypeInformation extends TypeInformation {
|
||||
class RecordTypeInformation extends TypeInformation with TracedTypeInformation {
|
||||
final RecordShape recordShape;
|
||||
final AbstractValue originalType;
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import 'debug.dart' as debug;
|
||||
import 'locals_handler.dart';
|
||||
import 'list_tracer.dart';
|
||||
import 'map_tracer.dart';
|
||||
import 'record_tracer.dart';
|
||||
import 'set_tracer.dart';
|
||||
import 'type_graph_dump.dart';
|
||||
import 'type_graph_nodes.dart';
|
||||
@@ -319,6 +320,18 @@ class InferrerEngine {
|
||||
_workQueue.add(info);
|
||||
}
|
||||
|
||||
void analyzeRecordAndEnqueue(RecordTypeInformation info) {
|
||||
if (info.analyzed) return;
|
||||
info.analyzed = true;
|
||||
RecordTracerVisitor tracer = RecordTracerVisitor(info, this);
|
||||
|
||||
bool succeeded = tracer.run();
|
||||
if (!succeeded) return;
|
||||
|
||||
info.bailedOut = false;
|
||||
_workQueue.add(info);
|
||||
}
|
||||
|
||||
void runOverAllElements() {
|
||||
metrics.time.measure(_runOverAllElements);
|
||||
}
|
||||
|
||||
@@ -104,30 +104,35 @@ abstract class TracerVisitor implements TypeInformationVisitor {
|
||||
int.fromEnvironment('dart2js.tracing.limit', defaultValue: 32);
|
||||
// TODO(natebiggs): We allow null here to maintain current functionality
|
||||
// but we should verify we actually need to allow it.
|
||||
final Setlet<MemberEntity?> analyzedElements = Setlet<MemberEntity?>();
|
||||
final Setlet<MemberEntity?> analyzedElements = Setlet();
|
||||
|
||||
TracerVisitor(this.tracedType, this.inferrer);
|
||||
|
||||
/// Work list that gets populated with [TypeInformation] that could
|
||||
/// contain the container.
|
||||
final List<TypeInformation> workList = <TypeInformation>[];
|
||||
final List<TypeInformation> workList = [];
|
||||
|
||||
/// Work list of lists to analyze after analyzing the users of a
|
||||
/// [TypeInformation]. We know the [tracedType] has been stored in these
|
||||
/// lists and we must check how it escapes from these lists.
|
||||
final List<ListTypeInformation> listsToAnalyze = <ListTypeInformation>[];
|
||||
final List<ListTypeInformation> listsToAnalyze = [];
|
||||
|
||||
/// Work list of sets to analyze after analyzing the users of a
|
||||
/// [TypeInformation]. We know the [tracedType] has been stored in these sets
|
||||
/// and we must check how it escapes from these sets.
|
||||
final List<SetTypeInformation> setsToAnalyze = <SetTypeInformation>[];
|
||||
final List<SetTypeInformation> setsToAnalyze = [];
|
||||
|
||||
/// Work list of maps to analyze after analyzing the users of a
|
||||
/// [TypeInformation]. We know the [tracedType] has been stored in these
|
||||
/// maps and we must check how it escapes from these maps.
|
||||
final List<MapTypeInformation> mapsToAnalyze = <MapTypeInformation>[];
|
||||
final List<MapTypeInformation> mapsToAnalyze = [];
|
||||
|
||||
final Setlet<TypeInformation> flowsInto = Setlet<TypeInformation>();
|
||||
/// Work list of records to analyze after analyzing the users of a
|
||||
/// [TypeInformation]. We know the [tracedType] has been stored in these
|
||||
/// records and we must check how it escapes from these records.
|
||||
final List<RecordTypeInformation> recordsToAnalyze = [];
|
||||
|
||||
final Setlet<TypeInformation> flowsInto = Setlet();
|
||||
|
||||
// The current [TypeInformation] in the analysis.
|
||||
TypeInformation? currentUser;
|
||||
@@ -175,6 +180,9 @@ abstract class TracerVisitor implements TypeInformationVisitor {
|
||||
while (!mapsToAnalyze.isEmpty) {
|
||||
analyzeStoredIntoMap(mapsToAnalyze.removeLast());
|
||||
}
|
||||
while (!recordsToAnalyze.isEmpty) {
|
||||
analyzeStoredIntoRecord(recordsToAnalyze.removeLast());
|
||||
}
|
||||
if (!continueAnalyzing) break;
|
||||
}
|
||||
}
|
||||
@@ -229,9 +237,7 @@ abstract class TracerVisitor implements TypeInformationVisitor {
|
||||
|
||||
@override
|
||||
void visitRecordFieldAccessTypeInformation(
|
||||
RecordFieldAccessTypeInformation info) {
|
||||
addNewEscapeInformation(info);
|
||||
}
|
||||
RecordFieldAccessTypeInformation info) {}
|
||||
|
||||
@override
|
||||
void visitValueInMapTypeInformation(ValueInMapTypeInformation info) {
|
||||
@@ -255,8 +261,7 @@ abstract class TracerVisitor implements TypeInformationVisitor {
|
||||
|
||||
@override
|
||||
void visitRecordTypeInformation(RecordTypeInformation info) {
|
||||
// TODO(50701): Implement better inference for records.
|
||||
bailout('Used as field of Record');
|
||||
recordsToAnalyze.add(info);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -346,6 +351,22 @@ abstract class TracerVisitor implements TypeInformationVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
void analyzeStoredIntoRecord(RecordTypeInformation record) {
|
||||
inferrer.analyzeRecordAndEnqueue(record);
|
||||
|
||||
record.flowsInto.forEach((TypeInformation flow) {
|
||||
flow.users.forEach((TypeInformation user) {
|
||||
if (user is RecordFieldAccessTypeInformation) {
|
||||
final getterIndex =
|
||||
record.recordShape.indexOfGetterName(user.getterName);
|
||||
if (user.receiver != flow ||
|
||||
record.fieldTypes.indexOf(currentUser!) != getterIndex) return;
|
||||
addNewEscapeInformation(user);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// Checks whether this is a call to a list adding method. The definition of
|
||||
/// what list adding means has to stay in sync with
|
||||
/// [isParameterOfListAddingMethod].
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// 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 'node_tracer.dart';
|
||||
import 'type_graph_nodes.dart';
|
||||
|
||||
class RecordTracerVisitor extends TracerVisitor {
|
||||
RecordTracerVisitor(super.tracedType, super.inferrer);
|
||||
|
||||
bool run() {
|
||||
analyze();
|
||||
final record = tracedType as RecordTypeInformation;
|
||||
if (continueAnalyzing) {
|
||||
record.addFlowsIntoTargets(flowsInto);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2058,7 +2058,7 @@ class ValueInMapTypeInformation extends InferredTypeInformation {
|
||||
|
||||
/// A [RecordTypeInformation] is the constructor for a record, used for Record
|
||||
/// constants and literals.
|
||||
class RecordTypeInformation extends TypeInformation {
|
||||
class RecordTypeInformation extends TypeInformation with TracedTypeInformation {
|
||||
final RecordShape recordShape;
|
||||
final AbstractValue originalType;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ analyzer:
|
||||
|
||||
exclude:
|
||||
- '**/data/*'
|
||||
- '**/inference_data/*'
|
||||
- 'rti/emission/*'
|
||||
- '**/model_data/*'
|
||||
- 'deferred_loading/libs/*'
|
||||
|
||||
@@ -57,11 +57,11 @@ testStoredInMapOfList() {
|
||||
dynamic b = <dynamic, dynamic>{'foo': 1};
|
||||
|
||||
b
|
||||
/*update: Dictionary([exact=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSExtendableArray], [exact=JSUInt31]), map: {foo: [exact=JSUInt31], bar: Container([null|exact=JSExtendableArray], element: [subclass=Closure], length: 1)})*/
|
||||
/*update: Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSExtendableArray], [exact=JSUInt31]), map: {foo: [exact=JSUInt31], bar: Container([null|exact=JSExtendableArray], element: [subclass=Closure], length: 1)})*/
|
||||
['bar'] = a;
|
||||
|
||||
b
|
||||
/*Dictionary([exact=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSExtendableArray], [exact=JSUInt31]), map: {foo: [exact=JSUInt31], bar: Container([null|exact=JSExtendableArray], element: [subclass=Closure], length: 1)})*/
|
||||
/*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSExtendableArray], [exact=JSUInt31]), map: {foo: [exact=JSUInt31], bar: Container([null|exact=JSExtendableArray], element: [subclass=Closure], length: 1)})*/
|
||||
['bar']
|
||||
|
||||
/*Container([null|exact=JSExtendableArray], element: [subclass=Closure], length: 1)*/
|
||||
@@ -127,10 +127,10 @@ testStoredInListOfListUsingAdd() {
|
||||
return res;
|
||||
}
|
||||
|
||||
/*member: testStoredInRecord:[null|subclass=Object]*/
|
||||
/*member: testStoredInRecord:[null|exact=JSUInt31]*/
|
||||
testStoredInRecord() {
|
||||
var res;
|
||||
/*[null|subclass=Object]*/ closure(/*[null|subclass=Object]*/ a) => res = a;
|
||||
/*[exact=JSUInt31]*/ closure(/*[exact=JSUInt31]*/ a) => res = a;
|
||||
final a = (3, closure);
|
||||
|
||||
a. /*[Record(RecordShape(2), [[exact=JSUInt31], [subclass=Closure]])]*/ $2(
|
||||
@@ -203,6 +203,41 @@ testStaticClosure4() {
|
||||
return topLevel4;
|
||||
}
|
||||
|
||||
/*member: bar1:[subclass=Closure]*/
|
||||
int Function(int, [int]) bar1(
|
||||
int /*[exact=JSUInt31]*/ a) => /*[subclass=JSInt]*/
|
||||
(int /*spec.[null|subclass=Object]*/ /*prod.[null|subclass=JSInt]*/ b,
|
||||
[int /*spec.[null|subclass=Object]*/ /*prod.[null|subclass=JSInt]*/
|
||||
c = 17]) =>
|
||||
a /*invoke: [exact=JSUInt31]*/ + b /*invoke: [subclass=JSInt]*/ + c;
|
||||
/*member: bar2:[subclass=Closure]*/
|
||||
int Function(int, [int]) bar2(
|
||||
int /*[exact=JSUInt31]*/ a) => /*[subclass=JSInt]*/
|
||||
(int /*spec.[null|subclass=Object]*/ /*prod.[null|subclass=JSInt]*/ b,
|
||||
[int /*spec.[null|subclass=Object]*/ /*prod.[null|subclass=JSInt]*/
|
||||
c = 17]) =>
|
||||
a /*invoke: [exact=JSUInt31]*/ + b /*invoke: [subclass=JSInt]*/ + c;
|
||||
/*member: bar3:[subclass=Closure]*/
|
||||
int Function(int, [int]) bar3(
|
||||
int /*[exact=JSUInt31]*/ a) => /*[subclass=JSPositiveInt]*/
|
||||
(int /*[exact=JSUInt31]*/ b, [int /*[exact=JSUInt31]*/ c = 17]) =>
|
||||
a /*invoke: [exact=JSUInt31]*/ + b /*invoke: [subclass=JSUInt32]*/ + c;
|
||||
|
||||
/*member: testFunctionApply:[null|subclass=Object]*/
|
||||
testFunctionApply() {
|
||||
return Function.apply(bar1(10), [20]);
|
||||
}
|
||||
|
||||
/*member: testRecordFunctionApply:[null|subclass=Object]*/
|
||||
testRecordFunctionApply() {
|
||||
final rec = (bar2(10), bar3(10));
|
||||
(rec. /*[Record(RecordShape(2), [[subclass=Closure], [subclass=Closure]])]*/ $2)(
|
||||
2, 3);
|
||||
return Function.apply(
|
||||
rec. /*[Record(RecordShape(2), [[subclass=Closure], [subclass=Closure]])]*/ $1,
|
||||
[20]);
|
||||
}
|
||||
|
||||
/*member: main:[null]*/
|
||||
main() {
|
||||
testFunctionStatement();
|
||||
@@ -219,4 +254,6 @@ main() {
|
||||
testStaticClosure2();
|
||||
testStaticClosure3();
|
||||
testStaticClosure4();
|
||||
testFunctionApply();
|
||||
testRecordFunctionApply();
|
||||
}
|
||||
|
||||
@@ -4,25 +4,25 @@ void main() {
|
||||
testClosure1();
|
||||
}
|
||||
|
||||
/*member: testList:Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/
|
||||
/*member: testList:Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: null)*/
|
||||
testList() {
|
||||
dynamic list = [];
|
||||
final rec = (list, 3);
|
||||
final myList = rec
|
||||
. /*[Record(RecordShape(2), [Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null), [exact=JSUInt31]])]*/ $1;
|
||||
. /*[Record(RecordShape(2), [Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: null), [exact=JSUInt31]])]*/ $1;
|
||||
myList
|
||||
. /*invoke: Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/ add(
|
||||
. /*invoke: Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: null)*/ add(
|
||||
1);
|
||||
return list;
|
||||
}
|
||||
|
||||
/*member: testClosure1:Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/
|
||||
/*member: testClosure1:Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 2)*/
|
||||
testClosure1() {
|
||||
return getRecord()
|
||||
. /*[Record(RecordShape(2), [Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null), [exact=JSUInt31]])]*/ $1;
|
||||
. /*[Record(RecordShape(2), [Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 2), [exact=JSUInt31]])]*/ $1;
|
||||
}
|
||||
|
||||
/*member: getRecord:[Record(RecordShape(2), [Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null), [exact=JSUInt31]])]*/
|
||||
/*member: getRecord:[Record(RecordShape(2), [Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 2), [exact=JSUInt31]])]*/
|
||||
getRecord() {
|
||||
return ([1, 2], 3);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// 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.
|
||||
|
||||
main() {
|
||||
directUnusedTest();
|
||||
recordUnusedTest();
|
||||
directCalledTest();
|
||||
directAppliedTest();
|
||||
recordCalledTest();
|
||||
recordAppliedTest();
|
||||
}
|
||||
|
||||
int Function(int, [int]) _recordUnused(int a) =>
|
||||
(int b, [int c = 17]) => a + b + c;
|
||||
int Function(int, [int]) _recordCalled(int a) =>
|
||||
(int b, [int c = 17]) => a + b + c;
|
||||
int Function(int, [int]) _recordApplied(int a) =>
|
||||
/*apply*/ (int b, [int c = 17]) => a + b + c;
|
||||
int Function(int, [int]) _directUnused(int a) =>
|
||||
(int b, [int c = 17]) => a + b + c;
|
||||
int Function(int, [int]) _directCalled(int a) =>
|
||||
(int b, [int c = 17]) => a + b + c;
|
||||
int Function(int, [int]) _directApplied(int a) =>
|
||||
/*apply*/ (int b, [int c = 17]) => a + b + c;
|
||||
|
||||
directUnusedTest() {
|
||||
return _directUnused(10);
|
||||
}
|
||||
|
||||
recordUnusedTest() {
|
||||
final rec = (_recordUnused(10), 4);
|
||||
return rec.$1;
|
||||
}
|
||||
|
||||
directCalledTest() {
|
||||
return _directCalled(10)(20);
|
||||
}
|
||||
|
||||
directAppliedTest() {
|
||||
return Function.apply(_directApplied(10), [20]);
|
||||
}
|
||||
|
||||
recordCalledTest() {
|
||||
final rec = (4, _recordCalled(10));
|
||||
return (rec.$2)(20);
|
||||
}
|
||||
|
||||
recordAppliedTest() {
|
||||
final rec = (_recordApplied(10), 4);
|
||||
return Function.apply(rec.$1, [20]);
|
||||
}
|
||||
@@ -265,10 +265,10 @@ doTest(String allocation, {required bool nullify}) async {
|
||||
checkType('listPassedAsNamedParameter', commonMasks.numType);
|
||||
checkType('listStoredInList', commonMasks.uint31Type);
|
||||
checkType('listStoredInListButEscapes', commonMasks.dynamicType);
|
||||
checkType('listStoredInRecordWithIndexAccess', commonMasks.dynamicType);
|
||||
checkType('listStoredInRecordWithNameAccess', commonMasks.dynamicType);
|
||||
checkType('listStoredInRecordWithDynamicAccess', commonMasks.dynamicType);
|
||||
checkType('listStoredInRecordWithoutAccess', commonMasks.dynamicType);
|
||||
checkType('listStoredInRecordWithIndexAccess', commonMasks.numType);
|
||||
checkType('listStoredInRecordWithNameAccess', commonMasks.numType);
|
||||
checkType('listStoredInRecordWithDynamicAccess', commonMasks.numType);
|
||||
checkType('listStoredInRecordWithoutAccess', commonMasks.uint31Type);
|
||||
|
||||
if (!allocation.contains('filled')) {
|
||||
checkType('listUnset', TypeMask.nonNullEmpty());
|
||||
|
||||
@@ -313,14 +313,14 @@ doTest(String allocation,
|
||||
checkType('mapStoredInMap', K(aKeyType), V(commonMasks.uint31Type));
|
||||
checkType('mapStoredInMapButEscapes', K(commonMasks.dynamicType),
|
||||
V(commonMasks.dynamicType));
|
||||
checkType('mapStoredInRecordWithIndexAccess', K(commonMasks.dynamicType),
|
||||
V(commonMasks.dynamicType));
|
||||
checkType('mapStoredInRecordWithNameAccess', K(commonMasks.dynamicType),
|
||||
V(commonMasks.dynamicType));
|
||||
checkType('mapStoredInRecordWithDynamicAccess', K(commonMasks.dynamicType),
|
||||
V(commonMasks.dynamicType));
|
||||
checkType('mapStoredInRecordWithoutAccess', K(commonMasks.dynamicType),
|
||||
V(commonMasks.dynamicType));
|
||||
checkType(
|
||||
'mapStoredInRecordWithIndexAccess', K(aKeyType), V(commonMasks.numType));
|
||||
checkType(
|
||||
'mapStoredInRecordWithNameAccess', K(aKeyType), V(commonMasks.numType));
|
||||
checkType('mapStoredInRecordWithDynamicAccess', K(aKeyType),
|
||||
V(commonMasks.numType));
|
||||
checkType('mapStoredInRecordWithoutAccess', K(aKeyType),
|
||||
V(commonMasks.positiveIntType));
|
||||
|
||||
checkType('mapUnset', K(emptyType), V(emptyType));
|
||||
checkType('mapOnlySetWithConstraint', K(aKeyType), V(emptyType));
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"."
|
||||
],
|
||||
"exclude": [
|
||||
"^pkg/compiler/test/.*/inference_data/.*",
|
||||
"^pkg/compiler/test/.*/data/.*",
|
||||
"^pkg/compiler/test/.*/data_2/.*",
|
||||
"^pkg/compiler/test/.*/emission/.*",
|
||||
|
||||
Reference in New Issue
Block a user