Avoid late creation of entities.

This changes has been reviewed as part of https://dart-review.googlesource.com/c/sdk/+/55898

Change-Id: I28d41110919a592499ee7b5b7605728638bd5ea2
Reviewed-on: https://dart-review.googlesource.com/56481
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index a62b1a9..b598761 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -418,13 +418,13 @@
     phase = PHASE_DONE_RESOLVING;
 
     ClosedWorld closedWorld = resolutionWorldBuilder.closeWorld();
+    OutputUnitData result = deferredLoadTask.run(mainFunction, closedWorld);
     ClosedWorldRefiner closedWorldRefiner =
         backendStrategy.createClosedWorldRefiner(closedWorld);
     // Compute whole-program-knowledge that the backend needs. (This might
     // require the information computed in [world.closeWorld].)
     backend.onResolutionClosedWorld(closedWorld, closedWorldRefiner);
 
-    OutputUnitData result = deferredLoadTask.run(mainFunction, closedWorld);
     backend.onDeferredLoadComplete(result);
 
     // TODO(johnniwinther): Move this after rti computation but before
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index fe02b86..b017937 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -841,6 +841,9 @@
 
 /// Mixin that implements the abstract methods in [KernelToElementMapBase].
 abstract class ElementCreatorMixin implements KernelToElementMapBase {
+  /// Set to `true` before creating the J-World from the K-World to assert that
+  /// no entities are created late.
+  bool _envIsClosed = false;
   ProgramEnv get _env;
   EntityDataEnvMap<IndexedLibrary, LibraryData, LibraryEnv> get _libraries;
   EntityDataEnvMap<IndexedClass, ClassData, ClassEnv> get _classes;
@@ -885,6 +888,10 @@
 
   LibraryEntity _getLibrary(ir.Library node, [LibraryEnv libraryEnv]) {
     return _libraryMap.putIfAbsent(node, () {
+      assert(
+          !_envIsClosed,
+          "Environment of $this is closed. Trying to create "
+          "library for $node.");
       Uri canonicalUri = node.importUri;
       String name = node.name;
       if (name == null) {
@@ -900,6 +907,10 @@
 
   ClassEntity _getClass(ir.Class node, [ClassEnv classEnv]) {
     return _classMap.putIfAbsent(node, () {
+      assert(
+          !_envIsClosed,
+          "Environment of $this is closed. Trying to create "
+          "class for $node.");
       KLibrary library = _getLibrary(node.enclosingLibrary);
       if (classEnv == null) {
         classEnv = _libraries.getEnv(library).lookupClass(node.name);
@@ -913,6 +924,10 @@
 
   TypedefEntity _getTypedef(ir.Typedef node) {
     return _typedefMap.putIfAbsent(node, () {
+      assert(
+          !_envIsClosed,
+          "Environment of $this is closed. Trying to create "
+          "typedef for $node.");
       IndexedLibrary library = _getLibrary(node.enclosingLibrary);
       IndexedTypedef typedef = createTypedef(library, node.name);
       TypedefType typedefType = new TypedefType(
@@ -926,6 +941,10 @@
 
   TypeVariableEntity _getTypeVariable(ir.TypeParameter node) {
     return _typeVariableMap.putIfAbsent(node, () {
+      assert(
+          !_envIsClosed,
+          "Environment of $this is closed. Trying to create "
+          "type variable for $node.");
       if (node.parent is ir.Class) {
         ir.Class cls = node.parent;
         int index = cls.typeParameters.indexOf(node);
@@ -962,6 +981,10 @@
 
   ConstructorEntity _getConstructor(ir.Member node) {
     return _constructorMap.putIfAbsent(node, () {
+      assert(
+          !_envIsClosed,
+          "Environment of $this is closed. Trying to create "
+          "constructor for $node.");
       MemberDefinition definition;
       ir.FunctionNode functionNode;
       ClassEntity enclosingClass = _getClass(node.enclosingClass);
@@ -999,6 +1022,10 @@
 
   FunctionEntity _getMethod(ir.Procedure node) {
     return _methodMap.putIfAbsent(node, () {
+      assert(
+          !_envIsClosed,
+          "Environment of $this is closed. Trying to create "
+          "function for $node.");
       LibraryEntity library;
       ClassEntity enclosingClass;
       if (node.enclosingClass != null) {
@@ -1048,6 +1075,10 @@
 
   FieldEntity _getField(ir.Field node) {
     return _fieldMap.putIfAbsent(node, () {
+      assert(
+          !_envIsClosed,
+          "Environment of $this is closed. Trying to create "
+          "field for $node.");
       LibraryEntity library;
       ClassEntity enclosingClass;
       if (node.enclosingClass != null) {
@@ -2370,6 +2401,11 @@
       assert(newTypeVariable.typeVariableIndex ==
           oldTypeVariable.typeVariableIndex);
     }
+    // TODO(johnniwinther): We should close the environment in the beginning of
+    // this constructor but currently we need the [MemberEntity] to query if the
+    // member is live, thus potentially creating the [MemberEntity] in the
+    // process. Avoid this.
+    _elementMap._envIsClosed = true;
   }
 
   @override
diff --git a/tests/compiler/dart2js/model/strong_mode_closed_world_test.dart b/tests/compiler/dart2js/model/strong_mode_closed_world_test.dart
index fa652b4..16a33bd 100644
--- a/tests/compiler/dart2js/model/strong_mode_closed_world_test.dart
+++ b/tests/compiler/dart2js/model/strong_mode_closed_world_test.dart
@@ -179,16 +179,18 @@
       (ClassEntity cls) {
     List<String> expectedLiveMembers =
         expectedLiveMembersMap[cls.name] ?? const <String>[];
-    elementEnvironment.forEachLocalClassMember(cls, (MemberEntity member) {
+    List<String> actualLiveMembers = <String>[];
+    closedWorld.processedMembers.forEach((MemberEntity member) {
       if (member.enclosingClass != cls) return;
-      bool expected = expectedLiveMembers.contains(member.name);
-      bool live = closedWorld.processedMembers.contains(member);
-      Expect.equals(
-          expected,
-          live,
-          "Member $member ${expected ? '' : 'not '}expected to be live "
-          "in ${strongMode ? 'Dart 2' : 'Dart 1'}. "
-          "Expected members for ${cls.name}: $expectedLiveMembers");
+      if (member.isConstructor) return;
+      actualLiveMembers.add(member.name);
     });
+    Expect.setEquals(
+        expectedLiveMembers,
+        actualLiveMembers,
+        "Unexpected live members for $cls "
+        "in ${strongMode ? 'Dart 2' : 'Dart 1'}. \n"
+        "Expected members for ${cls.name}: $expectedLiveMembers\n"
+        "Actual members for ${cls.name}  : $actualLiveMembers");
   });
 }