[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>
diff --git a/pkg/compiler/lib/src/inferrer/engine.dart b/pkg/compiler/lib/src/inferrer/engine.dart
index 6c3d50c..29209c5 100644
--- a/pkg/compiler/lib/src/inferrer/engine.dart
+++ b/pkg/compiler/lib/src/inferrer/engine.dart
@@ -34,6 +34,7 @@
 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 @@
     _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 534e958..5eab958 100644
--- a/pkg/compiler/lib/src/inferrer/node_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/node_tracer.dart
@@ -104,30 +104,35 @@
       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 @@
       while (!mapsToAnalyze.isEmpty) {
         analyzeStoredIntoMap(mapsToAnalyze.removeLast());
       }
+      while (!recordsToAnalyze.isEmpty) {
+        analyzeStoredIntoRecord(recordsToAnalyze.removeLast());
+      }
       if (!continueAnalyzing) break;
     }
   }
@@ -229,9 +237,7 @@
 
   @override
   void visitRecordFieldAccessTypeInformation(
-      RecordFieldAccessTypeInformation info) {
-    addNewEscapeInformation(info);
-  }
+      RecordFieldAccessTypeInformation info) {}
 
   @override
   void visitValueInMapTypeInformation(ValueInMapTypeInformation info) {
@@ -255,8 +261,7 @@
 
   @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 @@
     }
   }
 
+  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 0000000..67ac017
--- /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 50c13a4..188af13 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 @@
 
 /// 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 50a6aef..e9e3a2f 100644
--- a/pkg/compiler/lib/src/inferrer_experimental/engine.dart
+++ b/pkg/compiler/lib/src/inferrer_experimental/engine.dart
@@ -35,6 +35,7 @@
 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 @@
     _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 c5f7340..ed1bce0 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 @@
       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 @@
       while (!mapsToAnalyze.isEmpty) {
         analyzeStoredIntoMap(mapsToAnalyze.removeLast());
       }
+      while (!recordsToAnalyze.isEmpty) {
+        analyzeStoredIntoRecord(recordsToAnalyze.removeLast());
+      }
       if (!continueAnalyzing) break;
     }
   }
@@ -229,9 +237,7 @@
 
   @override
   void visitRecordFieldAccessTypeInformation(
-      RecordFieldAccessTypeInformation info) {
-    addNewEscapeInformation(info);
-  }
+      RecordFieldAccessTypeInformation info) {}
 
   @override
   void visitValueInMapTypeInformation(ValueInMapTypeInformation info) {
@@ -255,8 +261,7 @@
 
   @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 @@
     }
   }
 
+  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 0000000..67ac017
--- /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 7f9b41a..7633f2f 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 @@
 
 /// 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 7d40a1a..03a6cbc 100644
--- a/pkg/compiler/test/analysis_options.yaml
+++ b/pkg/compiler/test/analysis_options.yaml
@@ -10,6 +10,7 @@
 
   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 2c85938..136ab44 100644
--- a/pkg/compiler/test/inference/data/closure_tracer.dart
+++ b/pkg/compiler/test/inference/data/closure_tracer.dart
@@ -57,11 +57,11 @@
   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 @@
   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 @@
   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 @@
   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 d61e074..a6a3fa9 100644
--- a/pkg/compiler/test/inference/data/record_4.dart
+++ b/pkg/compiler/test/inference/data/record_4.dart
@@ -4,25 +4,25 @@
   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 0000000..58c79d9
--- /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 ee901cf..39c62eb 100644
--- a/pkg/compiler/test/inference/list_tracer_test.dart
+++ b/pkg/compiler/test/inference/list_tracer_test.dart
@@ -265,10 +265,10 @@
   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 348a7fb..83b8b2e 100644
--- a/pkg/compiler/test/inference/map_tracer_test.dart
+++ b/pkg/compiler/test/inference/map_tracer_test.dart
@@ -313,14 +313,14 @@
   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 dde9e2a..9d1100b 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/.*",