From 7ceea1ec112d84c5fdb9cdd5681a09ceeba7ee0f Mon Sep 17 00:00:00 2001 From: Nate Biggs Date: Tue, 4 Apr 2023 02:11:01 +0000 Subject: [PATCH] [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 Reviewed-by: Stephen Adams --- pkg/compiler/lib/src/inferrer/engine.dart | 13 +++++ .../lib/src/inferrer/node_tracer.dart | 43 +++++++++++---- .../lib/src/inferrer/record_tracer.dart | 19 +++++++ .../lib/src/inferrer/type_graph_nodes.dart | 2 +- .../lib/src/inferrer_experimental/engine.dart | 13 +++++ .../inferrer_experimental/node_tracer.dart | 43 +++++++++++---- .../inferrer_experimental/record_tracer.dart | 19 +++++++ .../type_graph_nodes.dart | 2 +- pkg/compiler/test/analysis_options.yaml | 1 + .../test/inference/data/closure_tracer.dart | 45 ++++++++++++++-- .../test/inference/data/record_4.dart | 12 ++--- .../inference_data/function_apply_record.dart | 52 +++++++++++++++++++ .../test/inference/list_tracer_test.dart | 8 +-- .../test/inference/map_tracer_test.dart | 16 +++--- pkg/compiler/test/testing.json | 1 + 15 files changed, 243 insertions(+), 46 deletions(-) create mode 100644 pkg/compiler/lib/src/inferrer/record_tracer.dart create mode 100644 pkg/compiler/lib/src/inferrer_experimental/record_tracer.dart create mode 100644 pkg/compiler/test/inference/inference_data/function_apply_record.dart diff --git a/pkg/compiler/lib/src/inferrer/engine.dart b/pkg/compiler/lib/src/inferrer/engine.dart index 6c3d50c5941..29209c56a58 100644 --- a/pkg/compiler/lib/src/inferrer/engine.dart +++ b/pkg/compiler/lib/src/inferrer/engine.dart @@ -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); } diff --git a/pkg/compiler/lib/src/inferrer/node_tracer.dart b/pkg/compiler/lib/src/inferrer/node_tracer.dart index 534e95864e6..5eab958e905 100644 --- a/pkg/compiler/lib/src/inferrer/node_tracer.dart +++ b/pkg/compiler/lib/src/inferrer/node_tracer.dart @@ -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 analyzedElements = Setlet(); + final Setlet analyzedElements = Setlet(); TracerVisitor(this.tracedType, this.inferrer); /// Work list that gets populated with [TypeInformation] that could /// contain the container. - final List workList = []; + final List 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 listsToAnalyze = []; + final List 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 setsToAnalyze = []; + final List 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 mapsToAnalyze = []; + final List mapsToAnalyze = []; - final Setlet flowsInto = Setlet(); + /// 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 recordsToAnalyze = []; + + final Setlet 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]. diff --git a/pkg/compiler/lib/src/inferrer/record_tracer.dart b/pkg/compiler/lib/src/inferrer/record_tracer.dart new file mode 100644 index 00000000000..67ac0172108 --- /dev/null +++ b/pkg/compiler/lib/src/inferrer/record_tracer.dart @@ -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; + } +} diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart index 50c13a413b2..188af13dd60 100644 --- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart +++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart @@ -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; diff --git a/pkg/compiler/lib/src/inferrer_experimental/engine.dart b/pkg/compiler/lib/src/inferrer_experimental/engine.dart index 50a6aefe26b..e9e3a2f5d1a 100644 --- a/pkg/compiler/lib/src/inferrer_experimental/engine.dart +++ b/pkg/compiler/lib/src/inferrer_experimental/engine.dart @@ -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); } diff --git a/pkg/compiler/lib/src/inferrer_experimental/node_tracer.dart b/pkg/compiler/lib/src/inferrer_experimental/node_tracer.dart index c5f7340e710..ed1bce03b39 100644 --- a/pkg/compiler/lib/src/inferrer_experimental/node_tracer.dart +++ b/pkg/compiler/lib/src/inferrer_experimental/node_tracer.dart @@ -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 analyzedElements = Setlet(); + final Setlet analyzedElements = Setlet(); TracerVisitor(this.tracedType, this.inferrer); /// Work list that gets populated with [TypeInformation] that could /// contain the container. - final List workList = []; + final List 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 listsToAnalyze = []; + final List 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 setsToAnalyze = []; + final List 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 mapsToAnalyze = []; + final List mapsToAnalyze = []; - final Setlet flowsInto = Setlet(); + /// 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 recordsToAnalyze = []; + + final Setlet 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]. diff --git a/pkg/compiler/lib/src/inferrer_experimental/record_tracer.dart b/pkg/compiler/lib/src/inferrer_experimental/record_tracer.dart new file mode 100644 index 00000000000..67ac0172108 --- /dev/null +++ b/pkg/compiler/lib/src/inferrer_experimental/record_tracer.dart @@ -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; + } +} diff --git a/pkg/compiler/lib/src/inferrer_experimental/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer_experimental/type_graph_nodes.dart index 7f9b41a828b..7633f2fec06 100644 --- a/pkg/compiler/lib/src/inferrer_experimental/type_graph_nodes.dart +++ b/pkg/compiler/lib/src/inferrer_experimental/type_graph_nodes.dart @@ -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; diff --git a/pkg/compiler/test/analysis_options.yaml b/pkg/compiler/test/analysis_options.yaml index 7d40a1a38cd..03a6cbc19e6 100644 --- a/pkg/compiler/test/analysis_options.yaml +++ b/pkg/compiler/test/analysis_options.yaml @@ -10,6 +10,7 @@ analyzer: exclude: - '**/data/*' + - '**/inference_data/*' - 'rti/emission/*' - '**/model_data/*' - 'deferred_loading/libs/*' diff --git a/pkg/compiler/test/inference/data/closure_tracer.dart b/pkg/compiler/test/inference/data/closure_tracer.dart index 2c85938acd7..136ab442aa5 100644 --- a/pkg/compiler/test/inference/data/closure_tracer.dart +++ b/pkg/compiler/test/inference/data/closure_tracer.dart @@ -57,11 +57,11 @@ testStoredInMapOfList() { dynamic b = {'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(); } diff --git a/pkg/compiler/test/inference/data/record_4.dart b/pkg/compiler/test/inference/data/record_4.dart index d61e074d7b2..a6a3fa9c9d2 100644 --- a/pkg/compiler/test/inference/data/record_4.dart +++ b/pkg/compiler/test/inference/data/record_4.dart @@ -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); } diff --git a/pkg/compiler/test/inference/inference_data/function_apply_record.dart b/pkg/compiler/test/inference/inference_data/function_apply_record.dart new file mode 100644 index 00000000000..58c79d93c74 --- /dev/null +++ b/pkg/compiler/test/inference/inference_data/function_apply_record.dart @@ -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]); +} diff --git a/pkg/compiler/test/inference/list_tracer_test.dart b/pkg/compiler/test/inference/list_tracer_test.dart index ee901cf77a1..39c62eb8846 100644 --- a/pkg/compiler/test/inference/list_tracer_test.dart +++ b/pkg/compiler/test/inference/list_tracer_test.dart @@ -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()); diff --git a/pkg/compiler/test/inference/map_tracer_test.dart b/pkg/compiler/test/inference/map_tracer_test.dart index 348a7fbab46..83b8b2efd4e 100644 --- a/pkg/compiler/test/inference/map_tracer_test.dart +++ b/pkg/compiler/test/inference/map_tracer_test.dart @@ -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)); diff --git a/pkg/compiler/test/testing.json b/pkg/compiler/test/testing.json index dde9e2a6df1..9d1100b1449 100644 --- a/pkg/compiler/test/testing.json +++ b/pkg/compiler/test/testing.json @@ -9,6 +9,7 @@ "." ], "exclude": [ + "^pkg/compiler/test/.*/inference_data/.*", "^pkg/compiler/test/.*/data/.*", "^pkg/compiler/test/.*/data_2/.*", "^pkg/compiler/test/.*/emission/.*",